Zwracanie pliku binarnego z kontrolera w ASP.NET Web API
Pracuję nad serwisem internetowym wykorzystującym ASP.NET nowy WebAPI MVC, który będzie obsługiwał pliki binarne, głównie Pliki .cab
i .exe
.
Następująca metoda kontrolera wydaje się działać, co oznacza, że zwraca plik, ale ustawia typ zawartości na 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"));
}
Czy jest na to lepszy sposób? 8 answers
Spróbuj użyć prostego HttpResponseMessage
z właściwością Content
ustawioną na 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;
}
Kilka rzeczy na temat stream
używane:
Nie wolno wywoływać
stream.Dispose()
, ponieważ Web API nadal musi mieć dostęp do niego, gdy przetwarza metodę kontroleraresult
, Aby wysłać dane z powrotem do klienta. Dlatego nie należy używać blokuusing (var stream = …)
. Web API będzie dysponować strumień dla Ciebie.Upewnij się, że strumień ma ustawioną bieżącą pozycję do 0 (tj. początek danych strumienia). W powyższym przykładzie jest to podane, ponieważ dopiero co otworzyłeś plik. Jednak w innych scenariuszach (np. gdy po raz pierwszy zapisujesz dane binarne do
MemoryStream
), upewnij się, żestream.Seek(0, SeekOrigin.Begin);
lub ustawiszstream.Position = 0;
Ze strumieniami plików, jawnie określając
FileAccess.Read
uprawnienia mogą pomóc w zapobieganiu problemom z prawami dostępu na serwerach WWW; konta puli aplikacji IIS są często podawane tylko do odczytu / listy / wykonania praw dostępu do wwwroot.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-15 10:40:08
Dla Web API 2 można zaimplementować IHttpActionResult
. Oto moje:
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);
}
}
Wtedy coś takiego w Twoim kontrolerze:
[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);
}
I oto jeden ze sposobów, w jaki można powiedzieć IIS, aby ignorował żądania z rozszerzeniem, aby żądanie trafiło do kontrolera:
<!-- web.config -->
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-22 14:37:16
Dla użytkowników. NET Core:
Możesz użyć interfejsu IActionResult w metodzie kontrolera API, w ten sposób...
[HttpGet("GetReportData/{year}")]
public async Task<IActionResult> GetReportData(int year)
{
// Render Excel document in memory and return as Byte[]
Byte[] file = await this._reportDao.RenderReportAsExcel(year);
return File(file, "application/vnd.openxmlformats", "fileName.xlsx");
}
Ten przykład jest uproszczony, ale powinien być zrozumiały. W. Net Core proces ten jest więc znacznie prostszy niż w poprzednich wersjach. NET - tzn. brak ustawiania typu odpowiedzi, zawartości, nagłówków itp.
Również, oczywiście typ MIME dla pliku i rozszerzenia będzie zależał od indywidualnych potrzeb.
Reference: SO Post Answer by @NKosi
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55
Chociaż sugerowane rozwiązanie działa poprawnie, istnieje inny sposób na zwrócenie tablicy bajtów z kontrolera, ze strumieniem odpowiedzi odpowiednio sformatowanym :
- w żądaniu Ustaw nagłówek "Accept: application / octet-stream".
- Po stronie serwera, Dodaj program do formatowania typów multimediów, aby obsługiwać ten typ mime.
Niestety, WebApi nie zawiera żadnego formatera dla "application / octet-stream". Istnieje implementacja na Githubie: BinaryMediaTypeFormatter (istnieją drobne adaptacje, aby działało to dla webapi 2, podpisy metod zostały zmienione).
Możesz dodać ten formatter do globalnej konfiguracji:
HttpConfiguration config;
// ...
config.Formatters.Add(new BinaryMediaTypeFormatter(false));
WebApi powinien teraz używać BinaryMediaTypeFormatter
, jeśli żądanie określa poprawny nagłówek Accept.
Wolę to rozwiązanie, ponieważ kontroler akcji zwracający bajt [] jest wygodniejszy w testowaniu. Jednak inne rozwiązanie pozwala na większą kontrolę, jeśli chcesz zwrócić inny typ zawartości niż "application / octet-stream" (na przykład "image / gif").
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-07 14:06:15
Dla każdego, kto ma problem z wywołaniem API więcej niż jeden raz podczas pobierania dość dużego pliku przy użyciu metody w zaakceptowanej odpowiedzi, Ustaw buforowanie odpowiedzi na true System.Www.HttpContext.Aktualne.Odpowiedź.Bufor = true;
Zapewnia to, że cała zawartość binarna jest buforowana po stronie serwera, zanim zostanie wysłana do klienta. W przeciwnym razie do kontrolera zostanie wysłanych wiele żądań, a jeśli nie obsłużysz ich poprawnie, plik zostanie stać się skorumpowanym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-13 11:54:33
Przeciążenie, którego używasz, ustawia wyliczenie formaterów serializacji. Musisz określić typ zawartości jawnie jak:
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-02 22:58:02
Możesz spróbować]}
httpResponseMessage.Content.Headers.Add("Content-Type", "application/octet-stream");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-01 15:23:01
Możesz wypróbować następujący fragment kodu
httpResponseMessage.Content.Headers.Add("Content-Type", "application/octet-stream");
Mam nadzieję, że ci się uda.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-29 16:30:11