-
Notifications
You must be signed in to change notification settings - Fork 114
Serves a generated docx from the server
Delivering a file from a web server seems easily but we can quickly fall in some traps due to the different behaviour of the browsers. Keep in mind also your farm administrator can set up some settings to force the file to either be downloaded or to be displayed inside the browser. This is particular true for Pdf where many browsers now natively displaying them in a tab.
You can find below a small snippet to generate a DOCX file and deliver it to the client. For the purpose of this example, we use a basic handler (.ashx):
public class GenerateDocument : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
String documentName = "My Document";
if (documentName.Length > 128) documentName = documentName.Substring(0, 128);
string encodedFilename = documentName.Replace(';', ' ');
// Avoid accent encoding bug
if (request.Browser.Browser.Contains("IE"))
{
encodedFilename = Uri.EscapeDataString(Path.GetFileNameWithoutExtension(encodedFilename)).Replace("%20", " ");
}
// IE cannot download an MS Office document from a website using SSL if the response
// contains HTTP headers such as: Pragram: no-cache and/or Cache-control: no-cache,max-age=0,must-revalidate
// http://support.microsoft.com/kb/316431/
if (!(request.IsSecureConnection && request.Browser.Browser.Contains("IE")))
response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
using (MemoryStream mstream = GenerateDocument())
{
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
context.Response.AppendHeader("Content-Disposition", String.Concat("attachment;filename=\"", encodedFilename, ".docx\""));
context.Response.AddHeader("Content-Length", mstream.Length.ToString());
mstream.WriteTo(context.Response.OutputStream);
}
// use IsClientConnection to avoid an HttpException
// see http://stackoverflow.com/questions/1556073/response-flush-throws-system-web-httpexception
if (context.Response.IsClientConnected) try { context.Response.Flush(); }
catch (System.Web.HttpException) { }
}
private MemoryStream GenerateDocument()
{
...
}
public bool IsReusable
{
get { return false; }
}
}
public class GenerateDocument : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
SPContext spcontext = SPContext.GetContext(context);
SPWebApplication webApplication = spcontext.Site.WebApplication;
String documentName = "My Document";
if (documentName.Length > 128) documentName = documentName.Substring(0, 128);
string encodedFilename = SPHttpUtility.UrlEncodeFilenameForHttpHeader(documentName.Replace(';', ' '));
// ensure whether the farm admin force the user to download the file or to display it inside the browser.
if (webApplication.BrowserFileHandling == SPBrowserFileHandling.Strict)
{
context.Response.AppendHeader("X-Content-Type-Options", "nosniff");
context.Response.AppendHeader("X-Download-Options", "noopen");
}
using (MemoryStream mstream = GenerateDocument())
{
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
context.Response.AppendHeader("Content-Disposition", String.Concat("attachment;filename=\"", encodedFilename, ".docx\""));
context.Response.AddHeader("Content-Length", mstream.Length.ToString());
mstream.WriteTo(context.Response.OutputStream);
}
if (context.Response.IsClientConnected) try { context.Response.Flush(); }
catch (System.Web.HttpException) { }
}
private MemoryStream GenerateDocument()
{
...
}
public bool IsReusable
{
get { return false; }
}
}
Many developers complain that when they deliver DOCX file (using OpenXml SDK), their users are offered a DOC file and once downloaded, it seems corrupted. This is a classic question on StackOverflow and it can be easily answered by using the adequate content type. You should use
application/vnd.openxmlformats-officedocument.wordprocessingml.document.