c# asp.net asp.net-web-api

add swagger to web api c#



TransmisiĆ³n de archivos grandes(> 2GB sobre IIS) usando WebAPI (3)

Estoy tratando de cargar archivos muy grandes (> 2GB) a mi aplicación WebAPI (ejecutándose en .NET 4.5.2, Windows 2012R2).

La configuración de la propiedad httpRuntime maxRequestLength no sirve de nada porque solo funciona con archivos de menos de 2 GB.

Actualmente estoy usando un MultipartFormDataStreamProvider personalizado para leer la secuencia completa en el Servidor y ya he desactivado el almacenamiento en búfer usando un WebHostBufferPolicySelector personalizado.

Lo que descubrí es que ASP.NET (o WebAPI para esa materia) utiliza un HttpBufferlessInputStream bajo el capó que tiene un campo llamado _disableMaxRequestLength. Si configuro este valor en verdadero (a través de la reflexión), puedo transmitir archivos de cualquier tamaño.

Sin embargo, jugar con estas internas es claramente una mala manera.

La clase HttpRequest utilizada para la solicitud tiene un método llamado GetBufferlessInputStream que tiene una sobrecarga que permite deshabilitar maxRequestLength.

Mi pregunta es: ¿Cómo puedo hacer que la WebAPI use esta sobrecarga en lugar de la estándar?

¿Hay alguna manera de reemplazar la clase predeterminada HttpRequest o HttpContext? ¿O realmente necesito usar la reflexión para todo el material?

Este es el código que estoy usando actualmente para deshabilitar maxRequestLength:

private void DisableRequestLengthOnStream(HttpContent parent) { var streamContentProperty = parent.GetType().GetProperty("StreamContent", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); if (streamContentProperty == null) return; var streamContent = streamContentProperty.GetValue(parent, null); if (streamContent == null) return; var contentProperty = typeof(StreamContent).GetField("content", BindingFlags.Instance | BindingFlags.NonPublic); if (contentProperty == null) return; var content = contentProperty.GetValue(streamContent); if (content == null) return; var requestLengthField = content.GetType().GetField("_disableMaxRequestLength", BindingFlags.Instance | BindingFlags.NonPublic); if (requestLengthField == null) return; requestLengthField.SetValue(content, true); }


En mi humilde opinión no hay una manera fácil de hacer eso.

La llamada a GetBufferlessInputStream está GetBufferlessInputStream el interior de HttpControllerHandler , que es la capa más baja posible de la API web de ASP.NET (es un controlador HTTP sobre el que se construye la pila completa de la API web).

Puedes ver el código aquí .

Como ves, está lleno de estadísticas, métodos largos con condiciones lógicas anidadas, internas y privadas, por lo que no es realmente personalizable en absoluto.
Si bien todo el HttpControllerHandler en la API web puede ser reemplazado teóricamente por una implementación personalizada (esto se hace dentro de HttpControllerRouteHandler , al reemplazar el método GetHttpHandler ), es de hecho imposible (puede intentar internalizar este código en su aplicación, pero terminará arrastrando un montón de clases internas adicionales también).

Lo mejor (y me da miedo decirlo) que me viene a la mente es modificar la clase HttpControllerHandler origen para usar la sobrecarga de GetBufferlessInputStream que deshabilita el límite de longitud de la solicitud y volver a compilar el ensamblado System.Web.Http.WebHost , e implementarlo Versión modificada con su aplicación.


Ok, he encontrado una solución bastante simple. La respuesta de @JustinR. Funcionaría, por supuesto. Pero quería seguir usando un MultipartFormDataStreamProvider porque eso maneja todo el material MIME.

La solución es simplemente crear una nueva instancia de StreamContent con la secuencia de entrada correcta sin búfer y rellenarla con los encabezados del contenido original:

var provider = new MultipartFormDataStreamProvider(path); var content = new StreamContent(HttpContext.Current.Request.GetBufferlessInputStream(true)); foreach (var header in Request.Content.Headers) { content.Headers.TryAddWithoutValidation(header.Key, header.Value); } await content.ReadAsMultipartAsync(provider);


Según MSDN , la manera de leer una longitud de transmisión ilimitada es HttpRequest.GetBufferlessInputStream . Podrías hacer algo como:

public void ReadStream(HttpContext context, string filePath) { using (var reader = new StreamReader(context.Request.GetBufferlessInputStream(true))) using (var filestream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read, 4096, true)) using (var writer = new StreamWriter(filestream)) { var readBuffer = reader.ReadToEnd(); writer.WriteAsync(readBuffer); } }