0

I have the following ActionResult:

[Authorize]
public ActionResult DownloadFile(Guid id)
{
    AdjusterFile file = (from f in db.AdjusterFiles
                         join a in db.Adjusters
                         on f.adjusterID equals a.id
                         join u in db.Users
                         on a.userID equals u.id
                         where u.username == HttpContext.User.Identity.Name
                         && f.id == id
                         select f)
                        .FirstOrDefault();

    return new FileContentResult(file.fileContent.ToArray(), file.fileContentType);
}

It works perfectly for word documents (DOC/DOCX). However, whenever I try to download PDFs which are uploaded by the same process, it says, "Failed to load PDF document" in Chrome. In IE, it says, "The file is damaged and could not be repaired."

The content type is "application/pdf."

How can I download PDFs in MVC?

Relevant file upload code:

using (MemoryStream ms = new MemoryStream())
{
    file.InputStream.CopyTo(ms);
    byte[] array = ms.GetBuffer();

    AdjusterFile newFile = new AdjusterFile();

    newFile.id = Guid.NewGuid();
    newFile.adjusterID = adj.id;
    newFile.type = "eo";
    newFile.fileName = file.FileName;
    newFile.fileContent = array;
    newFile.fileContentType = file.ContentType;

    db.AdjusterFiles.InsertOnSubmit(newFile);
}
2
  • Instead of return new FileContentResult() try return File() (I don't remember in what version of MVC that was added, but it's definitely in 4). Barring that, there's no difference in the file result functionality between any file types. Are you sure the PDF itself isn't damaged in some way? Maybe some character encoding issue when it was stored in or retrieved from the database? Commented Jul 10, 2013 at 14:34
  • @David I tried changing it to return File(... but it still doesn't work (I get the same error). I have edited to question to include the code I am using to upload the file. Perhaps you can determine whether or not there is something I am doing wrong for PDF documents. Commented Jul 10, 2013 at 14:38

1 Answer 1

3

You don't need a MemoryStream, try like this:

byte[] array = new byte[file.ContentLength];
file.InputStream.Read(array, 0, array.Length);

AdjusterFile newFile = new AdjusterFile();

newFile.id = Guid.NewGuid();
newFile.adjusterID = adj.id;
newFile.type = "eo";
newFile.fileName = file.FileName;
newFile.fileContent = array;
newFile.fileContentType = file.ContentType;

db.AdjusterFiles.InsertOnSubmit(newFile);

The reason why your code doesn't work lies in the following quote from the MSDN documentation of the GetBytes method that you are using on the MemoryStream:

Note that the buffer contains allocated bytes which might be unused. For example, if the string "test" is written into the MemoryStream object, the length of the buffer returned from GetBuffer is 256, not 4, with 252 bytes unused. To obtain only the data in the buffer, use the ToArray method; however, ToArray creates a copy of the data in memory.

So basically with the GetBytes method you might not always get the exact bytes you have written to the Stream. Alternatively you could have used the ms.ToArray() method which would have behaved correctly in your scenario, but honestly you don't need this MemoryStream at all. You are just allocating some unnecessary space where you could directly read the contents of the upload file into a byte array as shown in my answer.

Important remark: I hope you realize that by loading the entire byte array in-memory, the memory consumption could grow pretty fast on your webserver especially if you start working with big files. The ideal solution would have been to store the file either on the file system or if you are using MS SQL 2008 or higher take advantage of the new FILESTREAM type.

Sign up to request clarification or add additional context in comments.

6 Comments

I tried replacing the code and uploaded a new file; however, I get the same error. Again, my .rtf document downloads without error.
Your rtf document works because in the RTF format it doesn't matter at all whether there might be some random bytes at the end of the file, whereas for PDF it does matter. If this doesn't work, chances are that the file is corrupted even before uploading it to the server.
Sorry, you are correct (as usual). It does work; I didn't replace the entire using block. Excellent, and thanks for your added remarks.
Here's what you could try. Once the file is uploaded on your server do the following call on the byte array to verify if the uploaded file is OK: System.IO.File.WriteAllBytes(@"c:\test.pdf", array); and then open the PDF file to check if it has been successfully uploaded.
You shouldn't even have an using block by the way as shown in my answer.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.