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.