339 votes

Retour du fichier binaire du contrôleur dans l'API Web ASP.NET

Je travaille sur un service web utilisant le nouveau WebAPI d'ASP.NET MVC qui servira des fichiers binaires, principalement des fichiers .cab et .exe .

La méthode de contrôleur suivante semble fonctionner, ce qui signifie qu'elle renvoie un fichier, mais elle définit le type de contenu sur 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"));
}
 

Y a-t-il une meilleure manière de faire cela?

539voto

carlosfigueira Points 40778

Essayez d'utiliser un simple HttpResponseMessage , avec un StreamContent inside, ce qui devrait fonctionner correctement.

 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);
    result.Content = new StreamContent(stream);
    result.Content.Headers.ContentType = 
        new MediaTypeHeaderValue("application/octet-stream");
    return result;
}
 

145voto

Ronnie Overby Points 11402

Pour l'API Web 2, vous pouvez implémenter IHttpActionResult. Voici la mienne:

 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)
    {
        return Task.Run(() =>
        {
            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 response;

        }, cancellationToken);
    }
}
 

Alors quelque chose comme ça dans votre contrôleur:

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

Et voici une façon de dire à IIS d'ignorer les requêtes avec une extension afin que la requête parvienne au contrôleur:

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

10voto

Eric Boumendil Points 436

Alors que la solution proposée fonctionne très bien, il est une autre façon de retourner un tableau d'octets à partir du contrôleur, avec des flux de réponse correctement mis en forme :

  • Dans la demande, définir l'en-tête "Accept: application/octet-stream".
  • Côté serveur, ajouter un type de média formateur à l'appui de ce type mime.

Malheureusement, WebApi ne comprend pas tout formateur pour "application/octet-stream". Il y a une mise en œuvre ici sur GitHub: BinaryMediaTypeFormatter (il y a des adaptations mineures à faire, il travaille pour webapi 2, signatures de méthode modifiée).

Vous pouvez ajouter ce formateur dans votre config :

HttpConfiguration config;
// ...
config.Formatters.Add(new BinaryMediaTypeFormatter(false));

WebApi doit maintenant utiliser BinaryMediaTypeFormatter si la demande spécifie le bon en-tête Accept.

Je préfère cette solution car un contrôleur d'action de retour byte[] est plus à l'aise pour tester. Cependant, l'autre solution vous permet plus de contrôle, si vous souhaitez renvoyer un autre type de contenu que de "application/octet-stream" (par exemple "image/gif").

8voto

David Peden Points 3532

La surcharge que vous utilisez définit l'énumération des formateurs de sérialisation. Vous devez spécifier le type de contenu explicitement comme:

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

5voto

MickySmig Points 94

Tu pourrais essayer

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X