with validate net isvalid fromuri frombody from diet body asp c# file-upload tdd asp.net-web-api

c# - validate - ¿Existe una forma comprobable de la unidad para cargar archivos a ASP.NET WebAPI?



web api get with parameters c# (4)

La respuesta es no". ASP.NET es un marco basado en la herencia. Si está intentando escribir aplicaciones basadas en la composición, en algún momento encontrará fricciones y bloqueos de carreteras. Es hora de cambiar a algo como Nancy .

Estoy trabajando en un proyecto que utiliza el nuevo ASP.NET WebAPI. Mi tarea actual es aceptar un archivo cargado. Hasta ahora, he usado TDD para eliminar el código WebAPI, pero me he topado con una carga. Actualmente estoy siguiendo los consejos que se encuentran en http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2 , pero parece que no hay forma en absoluto para conducir esto fuera de una prueba de unidad. Para acceder al archivo y los datos del formulario, tengo que usar MultipartFormDataStreamProvider , que es imposible de burlar y / o anular. Aparte de abandonar mi enfoque TDD, ¿qué puedo hacer?

Aquí está el código del ejemplo:

public Task<HttpResponseMessage> PostFormData() { // Check if the request contains multipart/form-data. if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } string root = HttpContext.Current.Server.MapPath("~/App_Data"); var provider = new MultipartFormDataStreamProvider(root); // Read the form data and return an async task. var task = Request.Content.ReadAsMultipartAsync(provider). ContinueWith<HttpResponseMessage>(t => { if (t.IsFaulted || t.IsCanceled) { Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception); } // This illustrates how to get the file names. foreach (MultipartFileData file in provider.FileData) { Trace.WriteLine(file.Headers.ContentDisposition.FileName); Trace.WriteLine("Server file path: " + file.LocalFileName); } return Request.CreateResponse(HttpStatusCode.OK); }); return task; }

El primer problema es esta línea:

var provider = new MultipartFormDataStreamProvider(root);

Para empezar, para hacer una prueba de unidad de este código, necesito poder inyectar un proveedor de este tipo. HACE MUCHO demasiado en esa simple llamada de constructor para estar "renovándolo" en línea. Tiene que haber otra manera. (Si no es así, WebAPI falla)


Me abstraí de un envoltorio del proveedor para poder burlarme de esas partes móviles, algo así como

public interface IMultiPartFormDataStreamProviderWrapper : IDependency { string LocalFileName { get; } MultipartFormDataStreamProvider Provider { get; } } public class MultiPartFormDataStreamProviderWrapper : IMultiPartFormDataStreamProviderWrapper { public const string UploadPath = "~/Media/Default/Vocabulary/"; private MultipartFormDataStreamProvider provider; public MultiPartFormDataStreamProviderWrapper(IHttpContextAccessor httpContextAccessor) { provider = new CustomMultipartFormDataStreamProvider(httpContextAccessor.Current().Server.MapPath(UploadPath)); } public string LocalFileName { get { return provider.FileData[0].LocalFileName; } } public MultipartFormDataStreamProvider Provider { get { return provider; } } }

Entonces podría hacer algo como

if (Request.Content.IsMimeMultipartContent()) { return Request.Content.ReadAsMultipartAsync(provider.Provider).ContinueWith(t => { if (t.IsCanceled || t.IsFaulted) return (object)new { success = false };

No es ideal, pero le da cierta tranquilidad. ¿Qué piensas?


Si aún no ha tirado la toalla en la API web, puede probar System.Net.Http.TestableMultipartStreamProviders , que son una reescritura de los proveedores de flujo de Microsoft. Su beneficio es que dependen de SystemWrapper para las operaciones de archivos, lo que significa que las operaciones de archivos se pueden burlar en las pruebas unitarias. La wiki da algunas ideas sobre cómo aprovechar DI para hacer que los controladores de prueba sean menos molestos.


Si usa la capacidad de self-hosting , puede escribir una prueba de unidad que:

  • Inicia los controladores (y varios otros formateadores / filtros / etc.)
  • Utiliza un HttpClient (o personalmente, yo usaría RestSharp ) para enviar un archivo a ese controlador (con RestSharp, puede usar la función AddFile para hacer esto)
  • Valida el flujo de entrada como desee (por ejemplo, anulando al proveedor o simplemente inspeccionando el valor que se pasa a un controlador de prueba o algo así)