0

I have Asp.Net MVC Web application with form. When I submit form app runs method:

[HttpPost]
public ActionResult MyMethod(MyViewModel model)
{
    FileStreamResult document = CreateDocument(model);
    return document;
} 

And browser opens generated file (PDF) in the same tab. I'm doesn't want to open this file, instead I want to download it to disk. How to implement this action?

Oblomingo
  • 668
  • 3
  • 10
  • 29

2 Answers2

3

You will need to tell the browser that it is a download, rather than a file.

You can do this by setting 2 headers (content type and content disposition), and then writing your PDF to the response stream.

[HttpPost]
public ActionResult MyMethod(MyViewModel model)
{

     HttpResponseBase response = ControllerContext.HttpContext.Response;

    response.ContentType = "application/pdf";
    response.AppendHeader("Content-Disposition", "attachment;filename=yourpdf.pdf");

    FileStreamResult document = CreateDocument(model);
    //Write you document to response.OutputStream here
    document.FileStream.Seek(0, SeekOrigin.Begin);
    document.FileStream.CopyTo(response.OutputStream, document.FileStream.Length);

    response.Flush();

    return new EmptyResult();
} 
Slicksim
  • 7,054
  • 28
  • 32
  • How to write document to response.OutputStream (OutputStream doesn't have setter)? I have third party library that returns only FileStreamResult object. – Oblomingo Oct 30 '15 at 08:41
  • I've updated it with some pseudo code, you might need to tweak it a bit – Slicksim Oct 30 '15 at 08:46
  • Thank a lot, now it works perfectly! Actually, we even doesn't need to write OutStream, enough to change ContentType and AppendHeader! – Oblomingo Oct 30 '15 at 08:59
  • Is it possible to implement loading spinner in form. Show spinner on submit (easy to do) and hide on getting file (how to get event?). – Oblomingo Oct 30 '15 at 09:06
0

You should return a FileStreamResult (this will force a download together with the "FileDownloadName". By specifying an ActionResult as a method return value you have the flexibility of returning other stuff as well (HttpStatusCodes, View()'s, or Content()'s).

public ActionResult DownloadSomeFile()
    {
        using (var ms = new MemoryStream())
        {
            var response = GetMyPdfAsStream(); // implement this yourself
            if (response is StreamContent)
            {
                var responseContent = response as StreamContent;
                await responseContent.CopyToAsync(ms);
                byte[] file = ms.ToArray();
                MemoryStream output = new MemoryStream();
                output.Write(file, 0, file.Length);
                output.Position = 0;

                return new FileStreamResult(output, "application/pdf") { FileDownloadName = fileName };
            }
            else
            {
                return Content("Something went wrong: " + response.ReasonPhrase);
            }
            return null;
        }

    }
Erik J.
  • 799
  • 6
  • 19
  • How to "implement this"? How to convert FileStreamResult to StreamContent? – Oblomingo Oct 30 '15 at 08:43
  • This stackoverflow answer shows you how to read a file into a memory stream directly. [http://stackoverflow.com/a/8624188/1430141](http://stackoverflow.com/a/8624188/1430141) – Erik J. Oct 30 '15 at 11:31