C# 如何使用 Web API 返回文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11125535/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 16:36:46  来源:igfitidea点击:

How to return a file using Web API?

c#asp.net-web-api

提问by Kyle

I am using ASP.NET Web API.
I want to download a PDF with C# from the API (that the API generates).

我正在使用ASP.NET Web API
我想从 API(API 生成)下载带有 C# 的 PDF。

Can I just have the API return a byte[]? and for the C# application can I just do:

我可以让 API 返回一个byte[]吗?对于 C# 应用程序,我可以这样做:

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

and

File.WriteAllBytes()?

采纳答案by Regfor

Better to return HttpResponseMessage with StreamContent inside of it.

最好返回包含 StreamContent 的 HttpResponseMessage 。

Here is example:

这是示例:

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

UPDfrom comment by 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 here).

UPD来自patridge 的评论:如果其他人来到这里希望从字节数组而不是实际文件发送响应,您将要使用 new ByteArrayContent(someData) 而不是 StreamContent(请参阅此处)。

回答by André de Mattos Ferraz

I made the follow action:

我做了以下操作:

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

回答by Ogglas

Example with IHttpActionResultin ApiController.

IHttpActionResultin为例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;
}

If you don't want to download the PDF and use a browsers built in PDF viewer instead remove the following two lines:

如果您不想下载 PDF 并使用内置 PDF 查看器的浏览器,请删除以下两行:

responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;

回答by Amir Shirazi

Just a note for .Net Core: We can use the FileContentResultand set the contentType to application/octet-streamif we want to send the raw bytes. Example:

请注意.Net Core:如果我们想发送原始字节,我们可以使用FileContentResult并将 contentType 设置为application/octet-stream。例子:

[HttpGet("{id}")]
public IActionResult GetDocumentBytes(int id)
{
    byte[] byteArray = GetDocumentByteArray(id);
    return new FileContentResult(byteArray, "application/octet-stream");
}

回答by Jake

I've been wondering if there was a simple way to download a file in a more ... "generic" way. I came up with this.

我一直想知道是否有一种简单的方法可以以更......“通用”的方式下载文件。我想出了这个。

It's a simple ActionResultthat will allow you to download a file from a controller call that returns an IHttpActionResult. The file is stored in the byte[] Content. You can turn it into a stream if needs be.

这是一个简单的方法ActionResult,它允许您从返回IHttpActionResult. 该文件存储在byte[] Content. 如果需要,您可以将其转换为流。

I used this to return files stored in a database's varbinary column.

我用它来返回存储在数据库的 varbinary 列中的文件。

    public class FileHttpActionResult : IHttpActionResult
    {
        public HttpRequestMessage Request { get; set; }

        public string FileName { get; set; }
        public string MediaType { get; set; }
        public HttpStatusCode StatusCode { get; set; }

        public byte[] Content { get; set; }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            HttpResponseMessage response = new HttpResponseMessage(StatusCode);

            response.StatusCode = StatusCode;
            response.Content = new StreamContent(new MemoryStream(Content));
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            response.Content.Headers.ContentDisposition.FileName = FileName;
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(MediaType);

            return Task.FromResult(response);
        }
    }