2

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...:

  • I add the json data as part of the form data and cannot have it extracted from body as "such" in the Web API Controller action, and I have to keep the key used in the Angular app for json data and then loop over the remaining keys (which are supposedly all files).
  • I have to send a different "POST" for each file

1 Answer 1

4

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);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

is it possible to stream out the different files independently without writing the request to disk?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.