Open Closed

Blazor Web App Static Proxy Endpoint Generates Incorrectly #10097


User avatar
0
ddelamare created

I have a Blazor Web App which exposes this app service method defined in the base class.

public virtual async Task<TAttachmentDto> CreateAsync(Guid attachmentTypeId, TEntityKey entityId,
            CreateFileInputWithStream inputWithStream, bool replaceByAttachmentType = false, bool autoSave = false)
        {
            await CheckPolicyAsync(CreatePolicyName);

            var attachmentType = await AttachmentTypeRepository.GetAsync(attachmentTypeId);

            if (attachmentType == null)
            {
                throw new UserFriendlyException(L["InvalidAttachmentType"]);
            }

            await CheckSize(inputWithStream.File.ContentLength ?? 0, attachmentType);
            await CheckFileExtension(inputWithStream.Name, entityId, attachmentType);

            var fileDescriptor = await AttachmentManager.CreateAsync(inputWithStream.Name,
                inputWithStream.File.ContentType, inputWithStream.File, attachmentTypeId, entityId,
                inputWithStream.ExtraProperties, overrideExisting: true, replaceByAttachmentType, autoSave);
            return ObjectMapper.Map<TAttachment, TAttachmentDto>(fileDescriptor);
        }

This is the app service declaration. The base class where the method exists is AttachmentAppService

OrganizationAttachmentAppService :
        AttachmentAppService<OrganizationAttachmentType, OrganizationAttachment, OrganizationAttachmentBlobContainer,
            AttachmentDto>, IOrganizationAttachmentAppService

The issue is when I call the method via the static proxy classes in the Blazor WASM project, it returns 415 Unsupported Media Type. From my research this appears to be an issue with how the endpoints are generated in the Blazor Server site. The generated endpoints seen via swagger are missing the multipart content type that exist in the api copy of the endpoint.

The blazor server swagger

The api swagger

How can I fix this invalid endpoint registration?


4 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    1. Solution
    • Root cause

      • Your method receives a file using ABP’s stream-friendly DTO (CreateFileInputWithStream with an IRemoteStreamContent/File field). Such endpoints must be exposed as multipart/form-data. In a Blazor Web App (WASM + Server host) solution, when you enable Static C# Proxies on the Blazor Server host, the Auto API/Swagger for the Server app can incorrectly describe that action as application/json and omit multipart/form-data. Calls made through the static proxy then send JSON, resulting in 415 Unsupported Media Type.
    • Fix: force the correct content type on the action and let Swagger describe it properly

      • Add FromForm to the file/stream input model argument so model binding selects multipart/form-data.
      • Add explicit Consumes attribute to the action to declare multipart/form-data.
      • Ensure your file input type in the DTO is IRemoteStreamContent (or IFormFile) so ABP’s formatter kicks in.

      Example:

    using Microsoft.AspNetCore.Mvc;
      using Volo.Abp.Content;
    
      public class CreateFileInputWithStream
      {
          public string Name { get; set; }
          public IRemoteStreamContent File { get; set; }
          public ExtraPropertyDictionary ExtraProperties { get; set; }
      }
    
      [ApiController]
      [Route("api/app/organization-attachment")]
      public class OrganizationAttachmentController : ControllerBase
      {
          [HttpPost]
          [Consumes("multipart/form-data")]
          public async Task<AttachmentDto> CreateAsync(
              [FromQuery] Guid attachmentTypeId,
              [FromQuery] Guid entityId,
              [FromForm] CreateFileInputWithStream inputWithStream,
              [FromQuery] bool replaceByAttachmentType = false,
              [FromQuery] bool autoSave = false)
          {
              // call your service method here
              // return await _appService.CreateAsync(...);
              throw new NotImplementedException();
          }
      }
    

    Notes:

    • If you’re using ABP Auto API Controllers (recommended), you don’t have to manually define the controller; you can annotate your application service method similarly:
    [Consumes("multipart/form-data")]
        public virtual Task<TAttachmentDto> CreateAsync(
            Guid attachmentTypeId,
            TEntityKey entityId,
            [FromForm] CreateFileInputWithStream inputWithStream,
            bool replaceByAttachmentType = false,
            bool autoSave = false)
        { ... }
    
    • After adding Consumes + FromForm, re-run and check the Blazor Server Swagger. It should now show a multipart/form-data body with a binary File field, matching your HttpApi.Host/API swagger.

    • Ensure the WASM static proxy posts FormData

      • The generated WASM proxy for a parameter typed as IRemoteStreamContent or a DTO containing it posts multipart/form-data automatically. If you have a custom call, use FormData:
    // In Blazor WASM
        var form = new MultipartFormDataContent();
        form.Add(new StringContent(attachmentTypeId.ToString()), "attachmentTypeId");
        form.Add(new StringContent(entityId.ToString()), "entityId");
        form.Add(new StringContent(input.Name), "inputWithStream.Name");
        form.Add(new StreamContent(fileStream) { Headers = { ContentType = new MediaTypeHeaderValue(fileContentType) }}, "inputWithStream.File", fileName);
        // plus ExtraProperties if needed
    
    • Prefer using the generated C# static proxy method for the service interface; once Swagger describes multipart/form-data correctly, the proxy will send the right content type and 415 will disappear.

    • If the Blazor Server host still shows the wrong content type

      • Clear and re-generate static proxies and swagger:
        • Stop the solution, delete bin/obj, rebuild.
        • Ensure you don’t have an outdated generated proxy/contract assembly altering ApiExplorer.
      • If you host client proxies on the Server app, make sure your HttpApi project references the Application.Contracts and your Blazor Server project references the HttpApi.Client (not Contracts) for consuming remote APIs.
      • Avoid custom ApiExplorer/Swagger filters that override request body content types.
    1. Sources
    • Auto API Controllers and content negotiation for streams:
      • https://docs.abp.io/en/abp/latest/API/Auto-API-Controllers
    • ABP repository reference for IRemoteStreamContent usage and tests:
      • https://github.com/abpframework/abp

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you share a new template project with your code?

    liming.ma@volosoft.com

    Thanks.

  • User Avatar
    0
    ddelamare created

    I built out a new template with the affected service classes and I was able to reproduce the issue of the controller methods not generating with a multipart/form data input option. However, I was able to fix it by adding this to the module startup config.

    Configure<AbpAspNetCoreMvcOptions>(options => { options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(CreateFileInputWithStream)); });

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Great 👍

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on December 03, 2025, 13:19
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.