Cómo aceptar un archivo POST

Estoy usando asp.net mvc 4 webapi beta para construir un servicio de descanso. Necesito poder aceptar imágenes / archivos POSTed desde las aplicaciones del cliente. ¿Es esto posible usar el webapi? A continuación se muestra cómo acción estoy usando actualmente. ¿Alguien sabe de un ejemplo de cómo debería funcionar esto?

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

ver http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2 , aunque creo que el artículo lo hace parecer un poco más complicado que realmente es.

Básicamente,

 public Task 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(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; } 

Me sorprende que muchos de ustedes parezcan querer guardar archivos en el servidor. La solución para mantener todo en la memoria es la siguiente:

 [HttpPost, Route("api/upload")] public async Task 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 binary data. } return Ok(); } 

Vea el código a continuación, adaptado de este artículo , que demuestra el código de ejemplo más simple que pude encontrar. Incluye cargas de archivos y de memoria (más rápidas).

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

Aquí hay una solución rápida y sucia que toma los contenidos cargados del cuerpo HTTP y los escribe en un archivo. Incluí un fragmento HTML / JS “básico” para la carga del archivo.

Método de API web:

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

Carga de archivos HTML:

 

Utilicé la respuesta de Mike Wasson antes de actualizar todos los NuGets en mi proyecto webapi mvc4. Una vez que lo hice, tuve que volver a escribir la acción de carga del archivo:

  public Task 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(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; } 

Aparentemente, BodyPartFileNames ya no está disponible dentro de MultipartFormDataStreamProvider.

En esta misma dirección, publico un cliente y snipets de servidor que envían archivos de Excel usando 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 } } 

Y el controlador webapi del servidor:

 public Task> 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!")); } } 

Y el Custom MyMultipartFormDataStreamProvider, necesario para personalizar el nombre de archivo:

PD: Tomé este código de otra publicación 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); } } 

La forma de ASP.NET Core ya está aquí :

 [HttpPost("UploadFiles")] public async Task Post(List 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}); } 
 [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); } } 

Aquí hay dos formas de aceptar un archivo. Uno que utiliza en el proveedor de memoria MultipartMemoryStreamProvider y otro que usa MultipartFormDataStreamProvider que lo guarda en un disco. Tenga en cuenta que esto es solo para la carga de un archivo a la vez. Puede ampliar esto con certeza para guardar múltiples archivos. El segundo enfoque puede admitir archivos de gran tamaño. He probado archivos de más de 200 MB y funciona bien. El uso de la aproximación de memoria no requiere que guarde en el disco, pero saltará la excepción de memoria si supera un límite determinado.

  private async Task 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 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; } 

Tuve un problema similar para la API web de vista previa. Aún no ha transferido esa parte a la nueva API web de MVC 4, pero quizás esto ayude:

¿Subir archivo REST con HttpRequestMessage o Stream?

Por favor, avíseme, puede sentarse mañana e intentar implementarlo de nuevo.

Esta pregunta tiene muchas buenas respuestas incluso para .Net Core. Estaba usando ambos Frameworks, los ejemplos de códigos proporcionados funcionan bien. Entonces no lo repetiré. En mi caso, lo importante era cómo usar las acciones de carga de archivo con Swagger de esta manera:

Botón de carga de archivo en Swagger

Aquí está mi resumen:

ASP .Net WebAPI 2

  • Para subir el uso del archivo: MultipartFormDataStreamProvider ver respuestas aquí
  • Cómo usarlo con Swagger

.NET Core

  • Para subir el archivo use: IFormFile vea las respuestas aquí o la documentación de MS
  • Cómo usarlo con Swagger