该示例中实际上应用了 jquery ajax(web client) + async web api 双异步。
jquery ajax post
1 $.ajax({ 2 type: "POST", 3 url: "/api/FileUpload", 4 contentType: false, 5 processData: false, 6 data: data, 7 success: function (results) { 8 ShowUploadControls(); 9 $("#uploadResults").empty(); 10 for (i = 0; i < results.length; i++) { 11 $("#uploadResults").append($("<li/>").text(results[i])); 12 } 13 }, 14 error: function (xhr, ajaxOptions, thrownError) { 15 ShowUploadControls(); 16 alert(xhr.responseText); 17 } 18 });
client端以post的方式发送数据。其中上传成功后的回调脚本定义在success处。
async Web API
Controller处Action返回值为Task<TResult>,本例中如下定义:
1 public Task<IEnumerable<string>> Post() 2 { 3 ... ... 4 }
而具体异步效果体现在“文件内容读取”和“后续处理”上。
1 string fullPath = HttpContext.Current.Server.MapPath("~/Uploads"); 2 CustomMultipartFormDataStreamProvider streamProvider = new CustomMultipartFormDataStreamProvider(fullPath); 3 var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t => 4 { 5 if (t.IsFaulted || t.IsCanceled) 6 throw new HttpResponseException(HttpStatusCode.InternalServerError); 7 8 var fileInfo = streamProvider.FileData.Select(i => 9 { 10 var info = new FileInfo(i.LocalFileName); 11 return "File saved as " + info.FullName + " (" + info.Length + ")"; 12 }); 13 return fileInfo; 14 15 });
ReadAsMultipartAsync
(From MSDN) 读取 MIME 多部分消息中的所有正文部分,并通过使用 streamProvider 实例确定每个正文部分内容的写入位置,来生成一组 HttpContent 实例作为结果。
Task.ContinueWith<TResult>
创建一个在目标 Task 完成时异步执行的延续任务。具体到该示例中,当 ReadAsMultipartAsync(读取)任务完成后,ContinueWith 中定义的行为才会作为延续而异步执行。
MultipartFormDataStreamProvider 对象
一个 IMultipartStreamProvider,适合与 HTML 文件上载一起使用,以将文件内容写入 FileStream。流提供程序将查看 <b>Content-Disposition</b> 标头字段,并根据 <b>filename</b> 参数是否存在来确定输出 Stream。如果 <b>Content-Disposition</b> 标头字段中存在 <b>filename</b> 参数,则正文部分将写入 FileStream 中;否则,正文部分将写入 MemoryStream 中。这将更加便于处理作为窗体数据和文件内容的组合的 MIME 多部分 HTML 窗体数据。
小技巧:lambda 表达式反转,从FileData到IEnumerable<string>
1 var fileInfo = streamProvider.FileData.Select(i => 2 { 3 var info = new FileInfo(i.LocalFileName); 4 return "File saved as " + info.FullName + " (" + info.Length + ")"; 5 });