3

I am trying to return a pdf file from my REST API and have added a ReportController to my collection of controllers as follows.

public class ReportController : ApiController
{
    public HttpResponseMessage Get(int id)
    {
        var result = new HttpResponseMessage(HttpStatusCode.OK);
        string fileName = id.ToString();

        MemoryStream memoryStream = GetStreamFromBlob(fileName);
        result.Content = new ByteArrayContent(memoryStream.ToArray());
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

        return result;
    }
}

The other controllers all work fine, however this is the first that has been set to return a HttpResponseMessage rather than a serializable object or collection of objects.

However I am having difficulty consuming this from the client end. Have tried a number of versions of code to do this however the controller code never gets hit, and there seem to be few complete examples of a successful way to call this. The following is my current version:-

public async Task<string> GetPdfFile(int id)
{
    string fileName = string.Format("C:\\Code\\PDF_Client\\{0}.pdf", id);

    using (HttpClient proxy = new HttpClient())
    {
        string url = string.Format("http://localhost:10056/api/report/{0}", id);
        HttpResponseMessage reportResponse = await proxy.GetAsync(url);  //****
        byte[] b = await reportResponse.Content.ReadAsByteArrayAsync();
        System.IO.File.WriteAllBytes(fileName, b);
    }
    return fileName;
}

However the line **** fails with the message No connection could be made because the target machine actively refused it 127.0.0.1:10056.

As I say, other controllers at http://localhost:10056/api/ work fine.

Is this the correct way to GET a file from a WEBAPI server method?

Do you have any advice as to other areas of the code that could be better such as use of await/async, or better ways for the controller to return a file?

4

1 回答 1

5

我遇到了同样的问题,想将 PDF 写入 ApiController 操作的输出。

这个链接帮助了我:http ://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

我编写了自己的 MediaTypeFormatter 用于从字节数组写入 PDF。

public class PdfFormatter : MediaTypeFormatter
{
    #region Constants and Fields

    private const int ChunkSizeMax = 1024 * 10;

    #endregion

    #region Constructors and Destructors

    public PdfFormatter()
    {
        SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/pdf"));
    }

    #endregion

    #region Public Methods

    public override bool CanReadType(Type type)
    {
        return false; // can't read any types
    }

    public override bool CanWriteType(Type type)
    {
        return type == typeof(byte[]);
    }

    public override Task WriteToStreamAsync(
        Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
    {
        Task t = new Task(() => WritePdfBytes(value, writeStream));
        t.Start();
        return t;
    }

    #endregion

    #region Methods

    private static void WritePdfBytes(object value, Stream writeStream)
    {
        byte[] buffer = value as byte[];
        int offset = 0;

        while (offset < buffer.Length)
        {
            int chunkSize = Math.Min(buffer.Length - offset, ChunkSizeMax);
            writeStream.Write(buffer, offset, chunkSize);
            offset += chunkSize;
        }
    }

    #endregion
}

然后,我在 Global.asax 中注册了这个格式化程序,如下所示:

private void SetupFormatters()
{
    GlobalConfiguration.Configuration.Formatters.Add(new PdfFormatter());
}

我的 ApiController Get 方法的相关部分如下所示:

public HttpResponseMessage Get(string url, string title)
{
    byte[] pdfBytes;

    /* generate the pdf into pdfBytes */

    string cleanTitle = new Regex(@"[^\w\d_-]+").Replace(title, "_");
    string contentDisposition = string.Concat("attachment; filename=", cleanTitle, ".pdf");
    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, pdfBytes, MediaTypeHeaderValue.Parse("application/pdf"));
    response.Content.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse(contentDisposition);

    return response;
}
于 2014-03-21T18:29:43.577 回答