Вопрос по c#, asp.net-web-api – Как вернуть файл с помощью веб-API?

76

я используюASP.NET Web API.
 Я хочу скачать PDF с C # из API (который генерирует API).

Могу ли я просто вернуть APIbyte[]? и для приложения C # я могу просто сделать:

byte[] pdf = client.DownloadData("urlToAPI");? 

а также

File.WriteAllBytes()?
Любой, кто приземлится и хочет вернуть поток через web api и IHTTPActionResult, увидит здесь:nodogmablog.bryanhogan.net/2017/02/… IbrarMumtaz
@ Роберт: Спасибо - этот тег делает его более понятным, хотя и ссылается на «ASP.NET Web API». было бы еще яснее. Частично ошибка MS в чепуховом родовом имени :) Jon Skeet
@JonSkeet: веб-API - это новая функция в последней версии ASP.NET. Увидетьasp.net/whitepapers/mvc4-release-notes#_Toc317096197 Robert Harvey♦
& quot; веб-API & quot ;? Что именно ты имеешь ввиду? Пожалуйста, прочитайтеtinyurl.com/so-hints и отредактируйте свой вопрос. Jon Skeet

Ваш Ответ

3   ответа
137

Лучше вернуть HttpResponseMessage с StreamContent внутри него.

Вот пример:

public HttpResponseMessage GetFile(string id)
{
    if (String.IsNullOrEmpty(id))
        return Request.CreateResponse(HttpStatusCode.BadRequest);

    string fileName;
    string localFilePath;
    int fileSize;

    localFilePath = getFileFromID(id, out fileName, out fileSize);

    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
    response.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
    response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
    response.Content.Headers.ContentDisposition.FileName = fileName;
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

    return response;
}

UPD из комментарияPatridge: Should anyone else get here looking to send out a response from a byte array instead of an actual file, you're going to want to use new ByteArrayContent(someData) instead of StreamContent (see Вот).

@patridge: естьByteArrayContent лучше чемresponse.BinaryWrite?
Во-первых, этот код вызовет исключение, поскольку вы обновляете два объекта FileStream, указывающих на один и тот же файл. Во-вторых, вы не хотите использовать & quot; Использование & quot; оператора, потому что, как только переменная выйдет из области видимости, .NET удалит ее, и вы получите сообщения об ошибках при закрытии основного соединения.
Вы также можете переопределить базовую функцию dispose (), чтобы вы могли правильно обрабатывать свои ресурсы при вызове платформы.
Если кто-то еще захочет отправить ответ из байтового массива вместо реального файла, вы захотите использоватьnew ByteArrayContent(someData) вместоStreamContent (увидетьhere).
@BrandonMontgomery Хорошо, вы имеете право. Спасибо!
4

Пример сIHttpActionResult вApiController.

[HttpGet]
[Route("file/{id}/")]
public IHttpActionResult GetFileForCustomer(int id)
{
    if (id == 0)
      return BadRequest();

    var file = GetFile(id);

    IHttpActionResult response;
    HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.OK);
    responseMsg.Content = new ByteArrayContent(file.SomeData);
    responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
    responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
    responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
    response = ResponseMessage(responseMsg);
    return response;
}

Если вы не хотите загружать PDF и использовать браузер, встроенный в программу просмотра PDF, удалите следующие две строки:

responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
@ElbertJohnFelipe Да, вы получаете файл сvar file = GetFile(id);. file.SomeData является байтовым массивом (byte[]) а такжеfile.FileNameявляетсяstring.
Каков следующий шаг? Будет ли это работать только с этим?
Спасибо за ваше сообщение. & APOS; HttpResponseMessage & APOS; у меня не получалось работать внутри ApiController, поэтому вы меня спасли.
31

Я сделал следующее действие:

[HttpGet]
[Route("api/DownloadPdfFile/{id}")]
public HttpResponseMessage DownloadPdfFile(long id)
{
    HttpResponseMessage result = null;
    try
    {
        SQL.File file = db.Files.Where(b => b.ID == id).SingleOrDefault();

        if (file == null)
        {
            result = Request.CreateResponse(HttpStatusCode.Gone);
        }
        else
        {
            // sendo file to client
            byte[] bytes = Convert.FromBase64String(file.pdfBase64);


            result = Request.CreateResponse(HttpStatusCode.OK);
            result.Content = new ByteArrayContent(bytes);
            result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = file.name + ".pdf";
        }

        return result;
    }
    catch (Exception ex)
    {
        return Request.CreateResponse(HttpStatusCode.Gone);
    }
}
Это на самом деле отвечает на вопрос
Это не было бы хорошей идеей для больших файлов, так как загружает все изображение в память. Опция потока лучше.

Похожие вопросы