Natalie Perret
Natalie Perret

Reputation: 9047

How to send json data and formdata (files) from Angular to an ASP.NET WebAPI Controller action in one shot?

Let's say I have an ASP.NET WebAPI Controller that looks like that:

public class StuffController
{
    [HttpGet]
    [Route("api/v1/stuff/{id:int}")]
    [ResponseType(typeof(Model))]
    public async Task<IHttpActionResult> GetAsync(int id)
    {
        // ...
    }

    [HttpPut]
    [Route("api/v1/stuff/{id:int}")]
    [ResponseType(typeof(IHttpActionResult))]
    public async Task<IHttpActionResult> UpdateAsync(int id, Model model)
    {
        // ...
    }

    [HttpPost]
    [Route("api/v1/stuff")]
    [ResponseType(typeof(IHttpActionResult))]
    public async Task<IHttpActionResult> CreateAsync([FromBody] Model model)
    {
        // ...
    }
}

Is there anyway I can send / upload / post from an Angular app (obviously in a service with HttpClient properly injected) a model (which is the json data that would be extracted from the body) and the form data containing files...)?

The problem is... I don't really see how:

const formData = new FormData();

const uploadReq = new HttpRequest('POST', url, formData, {
     reportProgress: true,
     headers: headers
});

It's like whether...:

Upvotes: 2

Views: 2000

Answers (1)

Dai
Dai

Reputation: 155608

Send a MIME multipart request (multipart/form-data), each blob is its own FormData entry: https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects - on the server-side you can extract different parts from the request in ASP.NET by using the Request.Content.ReadAsMultipartAsync API: https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2

You will need to change your Controller Actions to not use method parameters but to read from Request directly:

public async Task<HttpResponseMessage> PostFormData()
{
    // Check if the request contains multipart/form-data.
    if( !this.Request.Content.IsMimeMultipartContent() )
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    // Temporarily write the request to disk (if you use `MultipartMemoryStreamProvider` your risk crashing your server if a malicious user uploads a 2GB+ sized request)
    String root = this.Server.MapPath("~/App_Data");
    MultipartStreamProvider provider = new MultipartFormDataStreamProvider(root);

    try
    {
        // Read the form data and serialize it to disk for reading immediately afterwards:
        await this.Request.Content.ReadAsMultipartAsync( provider );

        // This illustrates how to get the names each part, but remember these are not necessarily files: they could be form fields, JSON blobs, etc
        foreach( MultipartFileData file in provider.FileData )
        {
            Trace.WriteLine( file.Headers.ContentDisposition.FileName );
            Trace.WriteLine( "Server file path: " + file.LocalFileName );
        }

        return this.Request.CreateResponse( HttpStatusCode.OK );
    }
    catch( System.Exception e )
    {
        return this.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
    }
}

Upvotes: 4

Related Questions