Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I want to upload a file and send along with the file some additional information, let's say a string foo and an int bar.

How would I write a ASP.NET WebAPI controller method that receives a file upload, a string, and an int?

My JavaScript:

var fileInput = document.querySelector("#filePicker");
var formData = new FormData();
formData.append("file", fileInput.files[0]);
formData.append("foo", "hello world!");
formData.append("bar", 42);

var options = {
   url: "/api/foo/upload",
   data: formData,
   processData: false // Prevents JQuery from transforming the data into a query string
};
$.ajax(options);

My WebAPI controller can access the file like this:

public async Task<HttpResponseMessage> Upload()
{
    var streamProvider = new MultipartMemoryStreamProvider();
    await Request.Content.ReadAsMultipartAsync(streamProvider);
    var fileStream = await streamProvider.Contents[0].ReadAsStreamAsync();
}

But it's not clear to me how I can get at my string and my int. I figure I can probably say streamProvider.Content[1], or whatever, but that feels super nasty.

What's the Right Way? to write a WebAPI action that accepts a file upload, a string, and an int?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
352 views
Welcome To Ask or Share your Answers For Others

1 Answer

You can create your own MultipartFileStreamProvider to access the additional arguments.

In ExecutePostProcessingAsync we loop through each file in multi-part form and load the custom data (if you only have one file you'll just have one object in the CustomData list).

class MyCustomData
{
    public int Foo { get; set; }
    public string Bar { get; set; }
}

class CustomMultipartFileStreamProvider : MultipartMemoryStreamProvider
{
    public List<MyCustomData> CustomData { get; set; }

    public CustomMultipartFileStreamProvider()
    {
        CustomData = new List<MyCustomData>();
    }

    public override Task ExecutePostProcessingAsync()
    {
        foreach (var file in Contents)
        {
            var parameters = file.Headers.ContentDisposition.Parameters;
            var data = new MyCustomData
            {
                Foo = int.Parse(GetNameHeaderValue(parameters, "Foo")),
                Bar = GetNameHeaderValue(parameters, "Bar"),
            };

            CustomData.Add(data);
        }

        return base.ExecutePostProcessingAsync();
    }

    private static string GetNameHeaderValue(ICollection<NameValueHeaderValue> headerValues, string name)
    {
        var nameValueHeader = headerValues.FirstOrDefault(
            x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase));

        return nameValueHeader != null ? nameValueHeader.Value : null;
    }
}

Then in your controller:

class UploadController : ApiController
{
    public async Task<HttpResponseMessage> Upload()
    {
        var streamProvider = new CustomMultipartFileStreamProvider();
        await Request.Content.ReadAsMultipartAsync(streamProvider);

        var fileStream = await streamProvider.Contents[0].ReadAsStreamAsync();
        var customData = streamProvider.CustomData;

        return Request.CreateResponse(HttpStatusCode.Created);
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...