File download issue with Sitecore MVC and resolution

The problem:

while working on the requirement of downloading calendar item(.ics) for an event on the site, I struck with the below given error.

OutputStream is not available when a custom TextWriter is used.

OutputStream is not available when a custom TextWriter is used.

Sitecore MVC error for File as ActionResult for post action

 

Steps to reproduce issue/problem

  1. Using Sitecore MVC form to do the form posting
 @using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post))
 {
     @Html.Sitecore().FormHandler("SeminarWebinarEvent", "DownloadCalendar")
     @Html.Hidden("eventId", @eventObj.Id.ToString())
     <button type="submit">Add to Calender</button>
 }
  1. Controller Post Action
 [HttpPost]
 public ActionResult DownloadCalendar(string eventId)
 {
     var eventItem = Sitecore.Context.Database.GetItem(new ID(eventId));
     if (eventItem == null)
     {
         //// TODO : Put the code for the error handling
     }

     //// get file stream
     var fileStream = this.eventService.GetCalendarFileStream(eventItem);
     return File(fileStream , "text/calendar", string.Format("{0}.ics", eventItem.Name));
 }
  1. Finally, Click on the Download link of the rendering on the page.

Root Cause

For the fix and the root cause I took the help of the God (not the real almighty but Google ;-)). I found that because of the basic page architecture of Sitecore, the page rendering has already started before the rendering control action returns the file response.

Solution :

After applying couple of different solutions(every time with fingers crossed), I found below given solution much handy and does the job. The solution is much simple and easy to implement.
In this case we need to split the whole action into two different actions like shown in below steps.

  1. Step 1

Put the logic of creating file stream in one action

 [HttpPost]
 public ActionResult DownloadCalendar(string eventId)
     {
          var eventItem = Sitecore.Context.Database.GetItem(new ID(eventId));
          if (eventItem == null)
          {
              //// TODO : Put the code for the error handling
          }

          //// read the file stream in the string format
          var fileStream = this.eventService.GetCalendarFileStream(eventItem);
          //// due to limitation of sitecore MVC redirect to the different action which is responsible for actual download
          return RedirectToAction("ActualCalenderDownload", new { fileString = fileStream, fileName = eventItem["Name"] });
        }
  1. Step 2

At the end of the action redirect to another action which is actually responsible for downloading the file.

  1. Step 3

Create the new action which takes the file stream from above action and returns the fileResult

 [HttpGet]
 public ActionResult ActualCalenderDownload(string fileString, string fileName)
 {
      if (string.IsNullOrWhiteSpace(fileString))
      {
          //// TODO : Put the code for the error handling
      }

      return File(Encoding.UTF8.GetBytes(fileString), "text/calendar", string.Format("{0}.ics", fileName));
 }

Happy Coding 🙂

Sitecore controller rendering action results – what can I return?

13 thoughts on “File download issue with Sitecore MVC and resolution

  1. Hi,
    I’ve used this solution. But I’m facing another issue now. If filestream string is lengthy them I’m getting 404 page. Any suggestions?

  2. HI, I want to embed pdf in the page and for that creating Filestream for PDF and returning the same to the view in MVC web app, it renders on the page directly.

    But while implementing this in sitecore it was not working, i tried your solution but now the file is directly downloading. I don not want direct download, it should display the pdf on page.

    Please help.

  3. I am trying to use this solution but I am still not able to download the pdf it redirects to page not found with controller url in browser

  4. Hi Sachin,
    What does the GetCalendarFileStream method do? can u post that.
    I am having a PDF files as bytes and want to download the same using sitecore MVC.

  5. Thanks!! you saved my neck! Even when I did not implement your solution, you gave me the clue with the paragraph “I found that because of the basic page architecture of Sitecore, the page rendering has already started before the rendering control action returns the file response”.

    Cause of that, I suspected immediatly about a cache extension I was using (Donut cache). When I sent the file result, the caching system already started outputting th content. I uninstalled Donut caching completely and the problem went away. I am returning the PDF files just with `return File(ms, “application/pdf”, fileName);` from the action method.

    Cheers
    Jaime

Leave a reply to Parag Daraji Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.