asp.net-mvc c# - Devolviendo un archivo binario desde el controlador en ASP.NET Web API





to send (6)


Para cualquier persona que tenga el problema de que se llame más de una vez a la API mientras descarga un archivo bastante grande con el método de la respuesta aceptada, configure el búfer de respuesta en verdadero System.Web.HttpContext.Current.Response.Buffer = true;

Esto asegura que todo el contenido binario se almacena en el búfer antes de enviarlo al cliente. De lo contrario, verá una solicitud múltiple que se envía al controlador y, si no la maneja correctamente, el archivo se dañará.

Estoy trabajando en un servicio web utilizando el nuevo WebAPI de ASP.NET MVC que servirá archivos binarios, principalmente archivos .cab y .exe .

El siguiente método de controlador parece funcionar, lo que significa que devuelve un archivo, pero está configurando el tipo de contenido en application/json :

public HttpResponseMessage<Stream> Post(string version, string environment, string filetype)
{
    var path = @"C:\Temp\test.exe";
    var stream = new FileStream(path, FileMode.Open);
    return new HttpResponseMessage<Stream>(stream, new MediaTypeHeaderValue("application/octet-stream"));
}

¿Hay una mejor manera de hacer esto?




Tu podrías intentar

httpResponseMessage.Content.Headers.Add("Content-Type", "application/octet-stream");



Para la API web 2 , puede implementar IHttpActionResult . Aquí está el mío:

using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

class FileResult : IHttpActionResult
{
    private readonly string _filePath;
    private readonly string _contentType;

    public FileResult(string filePath, string contentType = null)
    {
        if (filePath == null) throw new ArgumentNullException("filePath");

        _filePath = filePath;
        _contentType = contentType;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StreamContent(File.OpenRead(_filePath))
        };

        var contentType = _contentType ?? MimeMapping.GetMimeMapping(Path.GetExtension(_filePath));
        response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);

        return Task.FromResult(response);
    }
}

Entonces algo como esto en tu controlador:

[Route("Images/{*imagePath}")]
public IHttpActionResult GetImage(string imagePath)
{
    var serverPath = Path.Combine(_rootPath, imagePath);
    var fileInfo = new FileInfo(serverPath);

    return !fileInfo.Exists
        ? (IHttpActionResult) NotFound()
        : new FileResult(fileInfo.FullName);
}

Y aquí hay una forma en que puede decirle a IIS que ignore las solicitudes con una extensión para que la solicitud llegue al controlador:

<!-- web.config -->
<system.webServer>
  <modules runAllManagedModulesForAllRequests="true"/>



La sobrecarga que está utilizando establece la enumeración de formateadores de serialización. Necesita especificar el tipo de contenido explícitamente como:

httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");



Intente usar un HttpResponseMessage simple con su propiedad de Content establecida en un StreamContent :

// using System.IO;
// using System.Net.Http;
// using System.Net.Http.Headers;

public HttpResponseMessage Post(string version, string environment,
    string filetype)
{
    var path = @"C:\Temp\test.exe";
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
    result.Content = new StreamContent(stream);
    result.Content.Headers.ContentType = 
        new MediaTypeHeaderValue("application/octet-stream");
    return result;
}

Algunas cosas a tener en cuenta sobre la stream utilizada:

  • No debe llamar a stream.Dispose() , ya que la API web aún debe poder acceder a ella cuando procesa el result del método del controlador para enviar datos al cliente. Por lo tanto, no utilice un bloque using (var stream = …) . La API web dispondrá de la transmisión por usted.

  • Asegúrese de que el flujo tenga su posición actual establecida en 0 (es decir, el comienzo de los datos del flujo). En el ejemplo anterior, esto es un hecho dado que acaba de abrir el archivo. Sin embargo, en otros escenarios (como cuando escribe por primera vez algunos datos binarios en un MemoryStream ), asegúrese de stream.Seek(0, SeekOrigin.Begin); o establecer stream.Position = 0;

  • Con las secuencias de archivos, la especificación explícita del permiso FileAccess.Read puede ayudar a prevenir problemas de derechos de acceso en los servidores web; Las cuentas del grupo de aplicaciones de IIS a menudo solo reciben derechos de acceso de lectura / lista / ejecución a wwwroot.




Yo sugeriría comenzar con las soluciones más directas primero, tal vez una autenticación HTTP básica + HTTPS es suficiente en su escenario.

Si no es así (por ejemplo, no puede usar https o necesita una administración de claves más compleja), puede echar un vistazo a las soluciones basadas en HMAC como lo sugieren otros. Un buen ejemplo de dicha API sería Amazon S3 ( http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html )

Escribí una publicación de blog sobre autenticación basada en HMAC en la API web de ASP.NET. Analiza tanto el servicio de API web como el cliente de API web y el código está disponible en bitbucket. http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/

Aquí hay una publicación sobre autenticación básica en la API web: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/

Recuerde que si va a proporcionar una API a terceros, probablemente también será responsable de entregar las bibliotecas de los clientes. La autenticación básica tiene una ventaja significativa aquí, ya que es compatible con la mayoría de las plataformas de programación listas para usar. HMAC, por otro lado, no está tan estandarizado y requerirá una implementación personalizada. Estos deben ser relativamente sencillos pero aún requieren trabajo.

PD. También hay una opción para utilizar certificados HTTPS +. http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/





asp.net asp.net-mvc asp.net-web-api