采用文件上载和附加参数的WebAPI方法

时间:2014-05-19 03:51:47

标签: asp.net asp.net-mvc file-upload asp.net-web-api

我想上传一个文件并随文件一起发送一些额外的信息,比方说一个字符串foo和一个int吧。

我如何编写接收文件上传,字符串和int的ASP.NET WebAPI控制器方法?

我的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);

我的WebAPI控制器可以像这样访问文件:

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

但是我不清楚如何获得我的字符串和我的int。我想我可以说是streamProvider.Content [1],或者其他什么,但这感觉非常讨厌。

编写接受文件上传,字符串和int的WebAPI操作的正确方法是什么?

5 个答案:

答案 0 :(得分:18)

您可以创建自己的MultipartFileStreamProvider来访问其他参数。

ExecutePostProcessingAsync中,我们以多部分形式循环遍历每个文件并加载自定义数据(如果您只有一个文件,则CustomData列表中只有一个对象)。

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;
    }
}

然后在你的控制器中:

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);
    }
}

答案 1 :(得分:4)

我认为这里的答案非常好。所以其他人可以看到一个简单的例子,说明如何以摘要形式传递数据,包括一个Javascript函数,它调用FileUpload控制器,以及来自FileUpload Controller的片段(在VB.net中)它读取从Javascript传递的其他数据。

使用Javascript:

            function uploadImage(files) {
            var data = new FormData();
            if (files.length > 0) {
                data.append("UploadedImage", files[0]);
                data.append("Source", "1")
                var ajaxRequest = $.ajax({
                    type: "POST",
                    url: "/api/fileupload/uploadfile",
                    contentType: false,
                    processData: false,
                    data: data
                });

文件上传控制器:

        <HttpPost> _
    Public Function UploadFile() As KeyValuePair(Of Boolean, String)
        Try
            If HttpContext.Current.Request.Files.AllKeys.Any() Then
                Dim httpPostedFile = HttpContext.Current.Request.Files("UploadedImage")
                Dim source = HttpContext.Current.Request.Form("Source").ToString()

因此,您可以在Javascript中看到,传递的其他数据是“Source”键,值为“1”。正如Chandrika上面回答的那样,Controller通过“System.Web.HttpContext.Current.Request.Form(”Source“)读取这个传递的数据.ToString()”。

注意Form(“Source”)使用()(vs. []),因为控制器代码在VB.net中。

希望这有帮助。

答案 2 :(得分:3)

您可以通过以下方式提取多个文件和多个属性:

public async Task<HttpResponseMessage> Post()
{
    Dictionary<string,string> attributes = new Dictionary<string, string>();
    Dictionary<string, byte[]> files = new Dictionary<string, byte[]>();

    var provider = new MultipartMemoryStreamProvider();
    await Request.Content.ReadAsMultipartAsync(provider);
    foreach (var file in provider.Contents)
    {
        if (file.Headers.ContentDisposition.FileName != null)
        {
            var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
            var buffer = await file.ReadAsByteArrayAsync();
            files.Add(filename, buffer);
        } else
        {
            foreach(NameValueHeaderValue p in file.Headers.ContentDisposition.Parameters)
            {
                string name = p.Value;
                if (name.StartsWith("\"") && name.EndsWith("\"")) name = name.Substring(1, name.Length - 2);
                string value = await file.ReadAsStringAsync();
                attributes.Add(name, value);
            }
        }
    }
    //Your code here  
    return new HttpResponseMessage(HttpStatusCode.OK);
}

答案 3 :(得分:1)

您可以通过以下方式执行此操作: JQuery方法:

    var data = new FormData();

    data.append("file", filesToUpload[0].rawFile);
    var doc = {};            
    doc.DocumentId = 0; 
    $.support.cors = true;
    $.ajax({
        url: '/api/document/uploaddocument',
        type: 'POST',
        contentType: 'multipart/form-data',
        data: data,
        cache: false,
        contentType: false,
        processData: false,
        success: function (response) {
            docId = response.split('|')[0];
            doc.DocumentId = docId;
            $.post('/api/document/metadata', doc)
                .done(function (response) {
                });
          alert('Document save successfully!');
        },
        error: function (e) {
            alert(e);
        }
    });

拨打“UploadDocuement”网址api

[Route("api/document/uploaddocument"), HttpPost]
        [UnhandledExceptionFilter]
        [ActionName("UploadDocument")]
        public Task<HttpResponseMessage> UploadDocument()
        {
            // Check if the request contains multipart/form-data.
            if (!Request.Content.IsMimeMultipartContent())
            {
                Task<HttpResponseMessage> mytask = new Task<HttpResponseMessage>(delegate()
                {
                    return new HttpResponseMessage()
                    {
                        StatusCode = HttpStatusCode.BadRequest,
                        Content = "In valid file & request content type!".ToStringContent()
                    };
                });
                return mytask;
            }


            string root = HttpContext.Current.Server.MapPath("~/Documents");
            if (System.IO.Directory.Exists(root))
            {
                System.IO.Directory.CreateDirectory(root);
            }
            var provider = new MultipartFormDataStreamProvider(root);

            var task = Request.Content.ReadAsMultipartAsync(provider).
            ContinueWith<HttpResponseMessage>(o =>
            {
                if (o.IsFaulted || o.IsCanceled)
                    throw new HttpResponseException(HttpStatusCode.InternalServerError);

                FileInfo finfo = new FileInfo(provider.FileData.First().LocalFileName);

                string guid = Guid.NewGuid().ToString();

                File.Move(finfo.FullName, Path.Combine(root, guid + "_" + provider.FileData.First().Headers.ContentDisposition.FileName.Replace("\"", "")));

                string sFileName = provider.FileData.First().Headers.ContentDisposition.FileName.Replace("\"", "");

                FileInfo FInfos = new FileInfo(Path.Combine(root, guid + "_" + provider.FileData.First().Headers.ContentDisposition.FileName.Replace("\"", "")));

                Document dbDoc = new Document()
                {
                    DocumentID = 0                

                };

                context.DocumentRepository.Insert(dbDoc);
                context.Save();

                return new HttpResponseMessage()
                {
                    Content = new StringContent(string.Format("{0}|File uploaded.", dbDoc.DocumentID))
                };
            }
           );
            return task;

        }

按照以下方式调用您的元数据网络API:

[Route("api/document/metadata"), HttpPost]
        [ActionName("Metadata")]
        public Task<HttpResponseMessage> Metadata(Document doc)
        {
            int DocId = Convert.ToInt32(System.Web.HttpContext.Current.Request.Form["DocumentId"].ToString());

            Task<HttpResponseMessage> mytask = new Task<HttpResponseMessage>(delegate()
            {
                return new HttpResponseMessage()
                {
                    Content = new StringContent("metadata updated")
                };
            });
            return mytask;
        }

答案 4 :(得分:0)

var receipents = HttpContext.Current.Request.Params [“ Receipents”]; var参与者= HttpContext.Current.Request.Params [“参与者”];

        var file = HttpContext.Current.Request.Files.Count > 0 ?  HttpContext.Current.Request.Files[0] : null;

        if (file != null && file.ContentLength > 0)
        {
            var fileName = Path.GetFileName(file.FileName);

            var path = Path.Combine(
                HttpContext.Current.Server.MapPath("~/uploads"),
                fileName
            );

            file.SaveAs(path);
        }