Возrotation двоичного файла из controllerа в ASP.NET Web API

Я работаю над веб-сервисом, используя новый WebAPI ASP.NET MVC, который будет обслуживать двоичные файлы, в основном файлы .cab и .exe .

Кажется, что работает следующий метод controllerа, что означает, что он возвращает файл, но он устанавливает тип содержимого для application/json :

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

Есть лучший способ сделать это?

Попробуйте использовать простой HttpResponseMessage со свойством Content установленным в 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; } 

Несколько примечаний относительно используемого stream :

  • Вы не должны вызывать stream.Dispose() , поскольку веб-API по-прежнему должен иметь доступ к нему, когда он обрабатывает результат метода controllerа, чтобы отправить данные обратно клиенту. Поэтому не используйте блок using (var stream = …) . Web API предоставит вам stream.

  • Убедитесь, что stream имеет текущую позицию, установленную в 0 (т.е. начало данных streamа). В приведенном выше примере это заданное, поскольку вы только что открыли файл. Однако в других сценариях (например, когда вы сначала записываете некоторые двоичные данные в MemoryStream ), убедитесь, что stream.Seek(0, SeekOrigin.Begin); или установить stream.Position = 0;

  • С файловыми streamами явное указание разрешения FileAccess.Read может помочь предотвратить проблемы с правами доступа на веб-серверах; Учетным пулам приложений IIS часто присваиваются только права доступа на чтение / список / выполнение для wwwroot.

Для Web API 2 вы можете реализовать IHttpActionResult . Вот мой:

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

Тогда что-то вроде этого в вашем controllerе:

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

И вот один из способов сообщить IIS игнорировать запросы с расширением, чтобы запрос передал его controllerу:

    

Хотя предлагаемое решение работает нормально, есть еще один способ вернуть массив байтов из controllerа, при этом корректно отформатированный stream ответов:

  • В запросе установите заголовок «Accept: application / octet-stream».
  • На стороне сервера добавьте форматировщик типа мультимедиа для поддержки этого типа mime.

К сожалению, WebApi не содержит форматера для «application / octet-stream». Существует реализация здесь на GitHub: BinaryMediaTypeFormatter (есть небольшие адаптации, чтобы заставить его работать для webapi 2, изменения в методах изменены).

Вы можете добавить этот форматтер в свою глобальную конфигурацию:

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

WebApi теперь должен использовать BinaryMediaTypeFormatter если запрос указывает правильный заголовок Accept.

Я предпочитаю это решение, потому что controller возврата возвращаемого байта [] более удобен для тестирования. Хотя другое решение позволяет вам больше контролировать, если вы хотите вернуть другой тип контента, чем «application / octet-stream» (например, «image / gif»).

Перегрузка, которую вы используете, задает перечисление форматов сериализации. Вам нужно указать тип содержимого явно:

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

Для тех, у кого проблема API, вызываемая более одного раза при загрузке довольно большого файла с использованием метода в принятом ответе, настройте буферизацию ответа на истинный System.Web.HttpContext.Current.Response.Buffer = true;

Это гарантирует, что весь бинарный контент буферизуется на стороне сервера, прежде чем он будет отправлен клиенту. В противном случае вы увидите, что на controller будет отправлено несколько запросов, и если вы не обработаете его должным образом, файл станет поврежденным.

Вы можете попробовать

 httpResponseMessage.Content.Headers.Add("Content-Type", "application/octet-stream"); 
  • Один controller с несколькими методами GET в ASP.NET Web API
  • Указание пользовательского формата DateTime при сериализации с помощью Json.Net
  • Поддержка CORS для PUT и DELETE с помощью веб-API ASP.NET
  • ApiController возвращает 404, когда идентификатор содержит период
  • Почему «Ожидание Task.Yield ()» требуется для корректного streamа Thread.CurrentPrincipal?
  • WebAPI StreamContent vs PushStreamContent
  • WCF vs ASP.NET Web API
  • Хостинг WebAPI с использованием OWIN в службе Windows
  • Предоставляет ли IMDB API?
  • Чтение FromUri и FromBody одновременно
  • Убедитесь, что controller имеет ошибку без параметров
  • Давайте будем гением компьютера.