ASP.NET WebAPI에서 파일 (FileContentResult)을 반환하는 방법
일반 MVC 컨트롤러에서는을 사용하여 pdf를 출력 할 수 있습니다 FileContentResult
.
public FileContentResult Test(TestViewModel vm)
{
var stream = new MemoryStream();
//... add content to the stream.
return File(stream.GetBuffer(), "application/pdf", "test.pdf");
}
그러나 어떻게 그것을로 바꿀 수 ApiController
있습니까?
[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
//...
return Ok(pdfOutput);
}
여기에 내가 시도한 것이 있지만 작동하지 않는 것 같습니다.
[HttpGet]
public IHttpActionResult Test()
{
var stream = new MemoryStream();
//...
var content = new StreamContent(stream);
content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Headers.ContentLength = stream.GetBuffer().Length;
return Ok(content);
}
브라우저에 표시되는 결과는 다음과 같습니다.
{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}
그리고 비슷한 게시물이 있습니다 : ASP.NET Web API의 컨트롤러에서 바이너리 파일 반환 . 기존 파일 출력에 대해 설명합니다. 그러나 스트림으로 작동시키지 못했습니다.
어떤 제안?
대신에 반환하는 StreamContent
으로 Content
, 나는 그것이 작동 할 수 있습니다 ByteArrayContent
.
[HttpGet]
public HttpResponseMessage Generate()
{
var stream = new MemoryStream();
// processing the stream.
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(stream.ToArray())
};
result.Content.Headers.ContentDisposition =
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "CertificationCard.pdf"
};
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return result;
}
돌아가려면 IHttpActionResult
다음과 같이하십시오.
[HttpGet]
public IHttpActionResult Test()
{
var stream = new MemoryStream();
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(stream.GetBuffer())
};
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "test.pdf"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
var response = ResponseMessage(result);
return response;
}
따라서 이것을 시도하십시오 :
컨트롤러 코드 :
[HttpGet]
public HttpResponseMessage Test()
{
var path = System.Web.HttpContext.Current.Server.MapPath("~/Content/test.docx");;
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(path, FileMode.Open);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(path);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = stream.Length;
return result;
}
클릭 이벤트 및 간단한 URL과 함께 HTML 마크 업보기 :
<script type="text/javascript">
$(document).ready(function () {
$("#btn").click(function () {
// httproute = "" - using this to construct proper web api links.
window.location.href = "@Url.Action("GetFile", "Data", new { httproute = "" })";
});
});
</script>
<button id="btn">
Button text
</button>
<a href=" @Url.Action("GetFile", "Data", new { httproute = "" }) ">Data</a>
I am not exactly sure which part to blame, but here's why MemoryStream
doesn't work for you:
As you write to MemoryStream
, it increments it's Position
property. The constructor of StreamContent
takes into account the stream's current Position
. So if you write to the stream, then pass it to StreamContent
, the response will start from the nothingness at the end of the stream.
There's two ways to properly fix this:
1) construct content, write to stream
[HttpGet]
public HttpResponseMessage Test()
{
var stream = new MemoryStream();
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
// ...
// stream.Write(...);
// ...
return response;
}
2) write to stream, reset position, construct content
[HttpGet]
public HttpResponseMessage Test()
{
var stream = new MemoryStream();
// ...
// stream.Write(...);
// ...
stream.Position = 0;
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
return response;
}
2) looks a little better if you have a fresh Stream, 1) is simpler if your stream does not start at 0
Here is an implementation that streams the file's content out without buffering it (buffering in byte[] / MemoryStream, etc. can be a server problem if it's a big file).
public class FileResult : IHttpActionResult
{
public FileResult(string filePath)
{
if (filePath == null)
throw new ArgumentNullException(nameof(filePath));
FilePath = filePath;
}
public string FilePath { get; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(File.OpenRead(FilePath));
var contentType = MimeMapping.GetMimeMapping(Path.GetExtension(FilePath));
response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return Task.FromResult(response);
}
}
It can be simply used like this:
public class MyController : ApiController
{
public IHttpActionResult Get()
{
string filePath = GetSomeValidFilePath();
return new FileResult(filePath);
}
}
For me it was the difference between
var response = Request.CreateResponse(HttpStatusCode.OK, new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");
and
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");
The first one was returning the JSON representation of StringContent: {"Headers":[{"Key":"Content-Type","Value":["application/octet-stream; charset=utf-8"]}]}
While the second one was returning the file proper.
It seems that Request.CreateResponse has an overload that takes a string as the second parameter and this seems to have been what was causing the StringContent object itself to be rendered as a string, instead of the actual content.
'Programing' 카테고리의 다른 글
파이썬 : 룩업 테이블에 대한 목록 대 Dict (0) | 2020.06.07 |
---|---|
#ifdef에 'or'조건을 추가하는 방법 (0) | 2020.06.07 |
배열에서 쿼리 문자열을 작성하는 PHP 함수 (0) | 2020.06.07 |
Windows에서 여러 Python 버전을 실행하는 방법 (0) | 2020.06.07 |
Swift에서 "포장 해제 된 값"은 무엇입니까? (0) | 2020.06.07 |