如何接受文件POST
我正在使用asp.net mvc 4 webapitesting版来构build一个rest服务。 我需要能够从客户端应用程序接受张贴的图像/文件。 这可能使用webapi吗? 以下是我目前正在使用的操作。 有没有人知道这个应该如何工作的例子?
[HttpPost] public string ProfileImagePost(HttpPostedFile profileImage) { string[] extensions = { ".jpg", ".jpeg", ".gif", ".bmp", ".png" }; if (!extensions.Any(x => x.Equals(Path.GetExtension(profileImage.FileName.ToLower()), StringComparison.OrdinalIgnoreCase))) { throw new HttpResponseException("Invalid file type.", HttpStatusCode.BadRequest); } // Other code goes here return "/path/to/image.png"; }
看到http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2 ,虽然我认为这篇文章看起来似乎比它复杂一点真的是。
基本上,
public Task<HttpResponseMessage> PostFile() { HttpRequestMessage request = this.Request; if (!request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads"); var provider = new MultipartFormDataStreamProvider(root); var task = request.Content.ReadAsMultipartAsync(provider). ContinueWith<HttpResponseMessage>(o => { string file1 = provider.BodyPartFileNames.First().Value; // this is the file name on the server where the file was saved return new HttpResponseMessage() { Content = new StringContent("File uploaded.") }; } ); return task; }
我很惊讶你很多人似乎想在服务器上保存文件。 将所有内容保存在内存中的解决scheme如下:
[HttpPost, Route("api/upload")] public async Task<IHttpActionResult> Upload() { if (!Request.Content.IsMimeMultipartContent()) throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); var provider = new MultipartMemoryStreamProvider(); await Request.Content.ReadAsMultipartAsync(provider); foreach (var file in provider.Contents) { var filename = file.Headers.ContentDisposition.FileName.Trim('\"'); var buffer = await file.ReadAsByteArrayAsync(); //Do whatever you want with filename and its binaray data. } return Ok(); }
请参阅下面的代码,从这篇文章改编,它演示了我能find的最简单的示例代码。 它包括文件和内存 (更快)的上传。
public HttpResponseMessage Post() { var httpRequest = HttpContext.Current.Request; if (httpRequest.Files.Count < 1) { return Request.CreateResponse(HttpStatusCode.BadRequest); } foreach(string file in httpRequest.Files) { var postedFile = httpRequest.Files[file]; var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName); postedFile.SaveAs(filePath); // NOTE: To store in memory use postedFile.InputStream } return Request.CreateResponse(HttpStatusCode.Created); }
这是一个快速和肮脏的解决scheme,它从HTTP正文上载文件内容并将其写入文件。 我为file upload包含了一个“裸机”HTML / JS代码片段。
Web API方法:
[Route("api/myfileupload")] [HttpPost] public string MyFileUpload() { var request = HttpContext.Current.Request; var filePath = "C:\\temp\\" + request.Headers["filename"]; using (var fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create)) { request.InputStream.CopyTo(fs); } return "uploaded"; }
HTMLfile upload:
<form> <input type="file" id="myfile"/> <input type="button" onclick="uploadFile();" value="Upload" /> </form> <script type="text/javascript"> function uploadFile() { var xhr = new XMLHttpRequest(); var file = document.getElementById('myfile').files[0]; xhr.open("POST", "api/myfileupload"); xhr.setRequestHeader("filename", file.name); xhr.send(file); } </script>
在我更新我的webapi mvc4项目中的所有NuGets之前,我使用了Mike Wasson的答案。 一旦我做了,我不得不重写file upload操作:
public Task<HttpResponseMessage> Upload(int id) { HttpRequestMessage request = this.Request; if (!request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType)); } string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads"); var provider = new MultipartFormDataStreamProvider(root); var task = request.Content.ReadAsMultipartAsync(provider). ContinueWith<HttpResponseMessage>(o => { 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("\"", ""))); return new HttpResponseMessage() { Content = new StringContent("File uploaded.") }; } ); return task; }
显然,BodyPartFileNames在MultipartFormDataStreamProvider中不再可用。
向同样的方向,我发布了一个客户端和服务器snipets发送Excel文件使用WebApi,C#4:
public static void SetFile(String serviceUrl, byte[] fileArray, String fileName) { try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); using (var content = new MultipartFormDataContent()) { var fileContent = new ByteArrayContent(fileArray);//(System.IO.File.ReadAllBytes(fileName)); fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = fileName }; content.Add(fileContent); var result = client.PostAsync(serviceUrl, content).Result; } } } catch (Exception e) { //Log the exception } }
和服务器webapi控制器:
public Task<IEnumerable<string>> Post() { if (Request.Content.IsMimeMultipartContent()) { string fullPath = HttpContext.Current.Server.MapPath("~/uploads"); MyMultipartFormDataStreamProvider streamProvider = new MyMultipartFormDataStreamProvider(fullPath); var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t => { if (t.IsFaulted || t.IsCanceled) throw new HttpResponseException(HttpStatusCode.InternalServerError); var fileInfo = streamProvider.FileData.Select(i => { var info = new FileInfo(i.LocalFileName); return "File uploaded as " + info.FullName + " (" + info.Length + ")"; }); return fileInfo; }); return task; } else { throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "Invalid Request!")); } }
自定义MyMultipartFormDataStreamProvider需要自定义文件名:
PS:我从另一个post采取这个代码http://www.codeguru.com/csharp/.net/uploading-files-asynchronously-using-asp.net-web-api.htm
public class MyMultipartFormDataStreamProvider : MultipartFormDataStreamProvider { public MyMultipartFormDataStreamProvider(string path) : base(path) { } public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers) { string fileName; if (!string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName)) { fileName = headers.ContentDisposition.FileName; } else { fileName = Guid.NewGuid().ToString() + ".data"; } return fileName.Replace("\"", string.Empty); } }
[HttpPost] public JsonResult PostImage(HttpPostedFileBase file) { try { if (file != null && file.ContentLength > 0 && file.ContentLength<=10485760) { var fileName = Path.GetFileName(file.FileName); var path = Path.Combine(Server.MapPath("~/") + "HisloImages" + "\\", fileName); file.SaveAs(path); #region MyRegion ////save imag in Db //using (MemoryStream ms = new MemoryStream()) //{ // file.InputStream.CopyTo(ms); // byte[] array = ms.GetBuffer(); //} #endregion return Json(JsonResponseFactory.SuccessResponse("Status:0 ,Message: OK"), JsonRequestBehavior.AllowGet); } else { return Json(JsonResponseFactory.ErrorResponse("Status:1 , Message: Upload Again and File Size Should be Less Than 10MB"), JsonRequestBehavior.AllowGet); } } catch (Exception ex) { return Json(JsonResponseFactory.ErrorResponse(ex.Message), JsonRequestBehavior.AllowGet); } }
ASP.NET Core的方式现在在这里 :
[HttpPost("UploadFiles")] public async Task<IActionResult> Post(List<IFormFile> files) { long size = files.Sum(f => f.Length); // full path to file in temp location var filePath = Path.GetTempFileName(); foreach (var formFile in files) { if (formFile.Length > 0) { using (var stream = new FileStream(filePath, FileMode.Create)) { await formFile.CopyToAsync(stream); } } } // process uploaded files // Don't rely on or trust the FileName property without validation. return Ok(new { count = files.Count, size, filePath}); }
这里有两种接受文件的方法。 一个使用内存提供程序MultipartMemoryStreamProvider和一个使用MultipartFormDataStreamProvider保存到磁盘。 请注意,这只适用于一次上传一个文件。 你可以肯定,扩大这个保存多个文件。 第二种方法可以支持大文件。 我已经testing了超过200MB的文件,它工作正常。 在内存中使用不需要保存到磁盘,但是如果超过了某个限制,将会抛出内存exception。
private async Task<Stream> ReadStream() { Stream stream = null; var provider = new MultipartMemoryStreamProvider(); await Request.Content.ReadAsMultipartAsync(provider); foreach (var file in provider.Contents) { var buffer = await file.ReadAsByteArrayAsync(); stream = new MemoryStream(buffer); } return stream; } private async Task<Stream> ReadLargeStream() { Stream stream = null; string root = Path.GetTempPath(); var provider = new MultipartFormDataStreamProvider(root); await Request.Content.ReadAsMultipartAsync(provider); foreach (var file in provider.FileData) { var path = file.LocalFileName; byte[] content = File.ReadAllBytes(path); File.Delete(path); stream = new MemoryStream(content); } return stream; }
我对预览Web API有类似的问题。 没有把这个部分移植到新的MVC 4 Web API上,但是这可能有助于:
RESTfile upload与HttpRequestMessage或stream?
请让我知道,明天可以坐下来再试一次。
- ASP.NET WebApiunit testing与Request.CreateResponse
- 任何人都可以解释给我的CreatedAtRoute()?
- ASP .NET MVC 4 WebApi:手动处理OData查询
- 如何让HttpClient与请求一起传递证书?
- WCF Web API和ASP.NET Web API有什么区别?
- WebAPI和WebAPI 2有什么区别?
- .NET WebAPI序列化k_BackingField Nastiness
- ASP.NET WebApi:如何使用WebApi HttpClient执行file upload的多部分文章
- ApiController的输出caching(MVC4 Web API)