Web API를 사용하여 파일을 반환하는 방법은 무엇입니까?


100

내가 사용하고 ASP.NET 웹 API를 .
API (API가 생성하는)에서 C #으로 PDF를 다운로드하고 싶습니다.

API가 반환하도록 할 수 있습니까 byte[]? C # 응용 프로그램의 경우 다음을 수행 할 수 있습니다.

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

File.WriteAllBytes()?

"웹 API"? 정확히 무슨 뜻입니까? tinyurl.com/so-hints를 읽고 질문을 수정하세요.
Jon Skeet

1
@JonSkeet : 웹 API는 최신 버전의 ASP.NET의 새로운 기능입니다. 참조 asp.net/whitepapers/mvc4-release-notes#_Toc317096197
로버트 하비

1
@Robert : 감사합니다. "ASP.NET Web API"를 언급하는 것이 여전히 더 명확했을 것입니다. 부분적으로 rubbishly 일반적인 이름에 대한 MS의 잘못도 :)
존 소총


웹 API 및 IHTTPActionResult를 통해 스트림을 반환하려는 사람은 여기를 참조하십시오. nodogmablog.bryanhogan.net/2017/02/…
IbrarMumtaz

답변:


172

StreamContent가 포함 된 HttpResponseMessage를 내부에 반환하는 것이 좋습니다.

예를 들면 다음과 같습니다.

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

patridge의 주석에서 UPD : 다른 사람이 실제 파일 대신 바이트 배열에서 응답을 보내려고 여기에 오면 StreamContent 대신 new ByteArrayContent (someData)를 사용하고 싶을 것입니다 ( 여기 참조 ).


1
우선,이 코드는 동일한 파일을 가리키는 두 개의 FileStream 객체를 새로 만들기 때문에 예외를 발생시킵니다. 두 번째는 "Using"문을 사용하지 않는 것입니다. 변수가 범위를 벗어나는 즉시 .NET에서 변수를 삭제하고 기본 연결이 닫혔다는 오류 메시지가 표시되기 때문입니다.
Brandon Montgomery

48
다른 사람이 실제 파일 대신 바이트 배열에서 응답을 보내려고 여기에 오면 대신 사용하고 싶을 new ByteArrayContent(someData)것입니다 StreamContent( 여기 참조 ).
patridge 2013 년

프레임 워크에서 리소스를 호출 할 때 리소스를 올바르게 처리 할 수 ​​있도록 기본 dispose ()를 재정의 할 수도 있습니다.
Phil Cooper

2
올바른 MediaTypeHeaderValue가 중요하다는 점을 지적하고 이와 같이 할 수있는 다른 파일 형식이있는 경우이를 동적으로 가져 오려면. (여기서 fileName은 문자열이고 .jpg, .pdf, docx 등으로 끝나는 파일 유형을가집니다.) var contentType = MimeMapping.GetMimeMapping (fileName); response.Content.Headers.ContentType = new MediaTypeHeaderValue (contentType);
JimiSweden

1
FileStream이 자동으로 삭제됩니까?
Brian Tacker 19 년

37

다음 조치를 취했습니다.

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

이것은 실제로 질문에 답

1
이것은 전체 이미지를 메모리에로드하기 때문에 대용량 파일의 경우 좋은 생각이 아닙니다. 스트림 옵션이 더 좋습니다.
Paul Reedy

@PaulReedy Perfect ...하지만 많은 경우 큰 파일을 다룰 필요가 없습니다. 그러나 나는 당신의 요점에 전적으로 동의합니다!
André de Mattos Ferraz

15

와 예 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.
Ogglas

게시물 주셔서 감사합니다. 'HttpResponseMessage'가 ApiController 내부에서 작동하지 않았으므로 나를 구했습니다.
Max

14

참고 사항 .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");
}

1
이것은 훌륭하게 작동합니다. 또한 파일 이름을 제어하려면 파일 이름 을 지정하기 위해 FileContentResult호출 되는 속성이 있습니다FileDownloadName
weeksdev

@weeksdev 아는 그것을 몰랐습니다. 댓글 주셔서 감사합니다.
Amir Shirazi

그게 다야, 고마워. 또한 weeksdev의 의견은 매우 유용합니다.
fragg

1

좀 더 ... "일반적인"방법으로 파일을 다운로드하는 간단한 방법이 있는지 궁금합니다. 나는 이것을 생각 해냈다.

ActionResult을 반환하는 컨트롤러 호출에서 파일을 다운로드 할 수 있는 간단한 방법 입니다 IHttpActionResult. 파일은 byte[] Content. 필요한 경우 스트림으로 전환 할 수 있습니다.

나는 이것을 사용하여 데이터베이스의 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);
        }
    }

코드가 OP의 문제를 어떻게 수정하는지에 대한 간략한 설명은 답변의 품질을 향상시킬 것입니다.
Adrian Mole
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.