Как вернуть файл (FileContentResult) в ASP.NET WebAPI



в обычном контроллере 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"]}]}


и есть аналогичный пост на SO:возвращаясь двоичный файл из контроллера в Интернете ASP.NET API-интерфейс
. Он говорит о выводе существующего файла. но я не удалось заставить его работать с потоком.



какие предложения?

712   5  

5 ответов:

вместо возврата 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;          
}

просмотр HTML-разметки (с помощью события click и простой URL-адрес):

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

Я не совсем уверен, какая часть виновата, но вот почему MemoryStream не работает:

как вы пишете в MemoryStream увеличивает это Position собственность. Конструктор StreamContent учитывает текущий поток Position. Так что если вы пишете в поток, то передайте его в StreamContent, ответ будет начинаться с небытия в конце потока.

есть два способа правильно исправить это:

1) построить контент, написать поток

[HttpGet]
public HttpResponseMessage Test()
{
    var stream = new MemoryStream();
    var response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StreamContent(stream);
    // ...
    // stream.Write(...);
    // ...
    return response;
}

2) запись в поток, сброс позиции, построить контент

[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) выглядит немного лучше, если у вас есть свежий поток, 1) проще, если ваш поток не начинается с 0

для меня это была разница между

var response = Request.CreateResponse(HttpStatusCode.OK, new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");

и

var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");

первый возвращал представление JSON StringContent: {"Headers": [{"Key": "Content-Type", "Value": ["application / octet-stream; charset=utf-8"]}]}

в то время как второй возвращал файл правильно.

Кажется, что запрос.CreateResponse имеет перегрузку, которая принимает строку в качестве второго параметра, и это, похоже, было причиной Сам объект StringContent будет отображаться как строка, а не фактическое содержимое.

Comments

    Ничего не найдено.