Custom form data with multiple files to Web API controller

我怕爱的太早我们不能终老 提交于 2019-12-19 03:59:21

问题


I have problems of getting all the form data I've specified in my API Controller.

javascript upload function:

$scope.upload[index] = $upload.upload({
        url: '/api/upload/',
        method: 'POST',
        data: {
            Photographer: $scope.models[index].photographer,
            Description: $scope.models[index].desc
        },
        file: $scope.models[index].file
    })

Form data: Works as I want it to, for each request that is sent it includes my values as i want it to.

------WebKitFormBoundaryzlLjAnm449nw1EvC
Content-Disposition: form-data; name="Photographer"

Scott Johnson
------WebKitFormBoundaryzlLjAnm449nw1EvC
Content-Disposition: form-data; name="Description"

Image taken with a Nikon camerea
------WebKitFormBoundaryzlLjAnm449nw1EvC
Content-Disposition: form-data; name="file"; filename="moxnes.jpg"
Content-Type: image/jpeg

My Web API Controller:

Template from this guide

public class UploadController : ApiController
{
    public async Task < HttpResponseMessage > PostFormData() 
    {
        var root = HttpContext.Current.Server.MapPath("~/App_Data");
        var provider = new MultipartFormDataStreamProvider(root);

        try 
        {
            // Read the form data.
            await Request.Content.ReadAsMultipartAsync(provider);

            // Show all the key-value pairs.
            foreach(var key in provider.FormData.AllKeys) 
            {
                foreach(var val in provider.FormData.GetValues(key)) 
                {
                    var keyValue = string.Format("{0}: {1}", key, val);
                }
            }

            foreach(MultipartFileData fileData in provider.FileData) 
            {
                var fileName = fileData.Headers.ContentDisposition.FileName;
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        } 
        catch (Exception e) 
        {
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
        }
    }
}

Here's the problem: The controller can receive multiple request asynchronously and read all the files through this loop: foreach(MultipartFileData fileData in provider.FileData) which works fine, but my other form data values (Phtographer and Description) does only include values from one of the requests (the last request received).

foreach(var key in provider.FormData.AllKeys)

I need to take out each requests form data values. How can I do it, or is there any better way of solving this? Maybe by adding a model as parameter?


回答1:


I used this along with angular and it worked fine for me:

public partial class UploadController : ApiController
{
    [HttpPost]
    public Task<HttpResponseMessage> PostFormData()
    {
        // Check if the request contains multipart/form-data.
        if (!Request.Content.IsMimeMultipartContent()) {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }

        string root = HttpContext.Current.Server.MapPath("~/App_Data");
        var provider = new MultipartFormDataStreamProvider(root);

        // Read the form data and return an async task.
        var task = Request.Content.ReadAsMultipartAsync(provider).
            ContinueWith<HttpResponseMessage>(t =>
            {
                if (t.IsFaulted || t.IsCanceled) {
                    Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
                }


                foreach (MultipartFileData file in provider.FileData) {
                    using (StreamReader fileStream = new StreamReader(file.LocalFileName)){
                        if (provider.FormData.AllKeys.AsParallel().Contains("demo")){
                            //read demo key value from form data successfully
                        }
                        else{
                           //failed to read demo key value from form.
                        }
                    }
                }
                return Request.CreateResponse(HttpStatusCode.OK, "OK");
            });

        return task;
    }
...



回答2:


I've created a MediaTypeFormatter that decodes the multipart/form-data and provides a HttpPostedFileBase via model binding. It makes file uploads as easy as any other API parameters. It currently loads the full file upload into the memory but the formatter can be easily adjusted to also write the uploaded data into a temporary upload directory.

https://gist.github.com/Danielku15/bfc568a19b9e58fd9e80

Simply register the formatter in your API configuration and you're all set to use it in your data transfer models:

Configuration.Formatters.Add(new FormMultipartEncodedMediaTypeFormatter());


来源:https://stackoverflow.com/questions/21627437/custom-form-data-with-multiple-files-to-web-api-controller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!