Question

I'm trying to set up a web api service that searches for a .pdf file in a directory and returns the file if it's found.

The controller

public class ProductsController : ApiController
{

    [HttpPost]
    public HttpResponseMessage Post([FromBody]string certificateId)
    {
        string fileName = certificateId + ".pdf";
        var path = @"C:\Certificates\20487A" + fileName;

        //check the directory for pdf matching the certid
        if (File.Exists(path))
        {
            //if there is a match then return the file
            HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
            var stream = new FileStream(path, FileMode.Open);
            stream.Position = 0;
            result.Content = new StreamContent(stream);
            result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = fileName };
            result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
            result.Content.Headers.ContentDisposition.FileName = fileName;
            return result;
        }
        else
        {
            HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.Gone);
            return result;
        }
    }
}

I'm calling the service with the following code

private void GetCertQueryResponse(string url, string serial)
{
    string encodedParameters = "certificateId=" + serial.Replace(" ", "");

    HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);

    httpRequest.Method = "POST";
    httpRequest.ContentType = "application/x-www-form-urlencoded";
    httpRequest.AllowAutoRedirect = false;

    byte[] bytedata = Encoding.UTF8.GetBytes(encodedParameters);
    httpRequest.ContentLength = bytedata.Length;

    Stream requestStream = httpRequest.GetRequestStream();
    requestStream.Write(bytedata, 0, bytedata.Length);
    requestStream.Close();

    HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();

    if (response.StatusCode == HttpStatusCode.OK)
    {

        byte[] bytes = null;
        using (Stream stream = response.GetResponseStream())
        using (MemoryStream ms = new MemoryStream())
        {
            int count = 0;
            do
            {
                byte[] buf = new byte[1024];
                count = stream.Read(buf, 0, 1024);
                ms.Write(buf, 0, count);
            } while (stream.CanRead && count > 0);
            ms.Position = 0;
            bytes = ms.ToArray();
        }

        var filename = serial + ".pdf";

        Response.ContentType = "application/pdf";
        Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + filename + "\"");
        Response.BinaryWrite(bytes);
    }
}

This appears to be working in the sense that the download file dialogue is shown with the correct file name and size etc, but the download takes only a couple of seconds (when the file sizes are >30mb) and the files are corrupt when I try to open them.

Any ideas what I'm doing wrong?

Was it helpful?

Solution

Your code looks similar to what Ive used in the past, but below is what I typically use:

    Response.AddHeader("content-length", myfile.Length.ToString())
    Response.AddHeader("content-disposition", "inline; filename=MyFilename")
    Response.AddHeader("Expires", "0")
    Response.AddHeader("Pragma", "Cache")
    Response.AddHeader("Cache-Control", "private")

    Response.ContentType = "application/pdf"

    Response.BinaryWrite(finalForm)

I post this for 2 reasons. One, add the content-length header, you may have to indicate how large the file is so the application waits for the whole response.

If that doesn't fix it. Set a breakpoint, does the byte array content the appropriate length (aka, 30 million bytes for a 30 MB file)? Have you used fiddler to see how much content is coming back over the HTTP call?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top