In our solution we have some particular cases where we want to provide a "download media" link instead of a straightforward media link.

We don't want to force download for any particular file types, we want to provide a URL that forces download. So setting the <forceDownload> element in <mediaLibrary><mediaTypes> isn't an option.

We implemented this some years ago in 6.4, and we're now on 7.2 (which has some extended media options - for instance, we use the AcceptRangeRequests setting to allow partial requests)

Our solution was to build a custom media handler that was inserted into the pipeline. The media handler called the base handler ProcessRequest(context) method and then set the content-disposition header to "attachment"

We need to call ProcessRequest prior to setting the content-disposition header, as it fills the context object with data we needed, particularly the filename which needs to be set in the header.

This seemed to be working OK, mostly, but we've discovered that when media is served from the server disc cache the headers are appended too late, giving us an error in the logs - "can't append headers after response is sent". This doesn't occur if the media is fetched from the database (we assume the response must be sent to the client differently if media is served from cache, possibly just handed off to IIS?).

We're hoping to avoid replacing ProcessRequest with custom code.

We can also see that ProcessRequest contains it's own methods for determining and setting headers, and that there's a

Sitecore.Resources.Media.MediaStream ForceDownload


Are there properties or methods on the context object we can work with to do this, prior to calling ProcessRequest(context)? Or is there some way of modifying how headers are set (a pipeline?) within ProcessRequest?


1 Answer 1


One way to deal with it, is to just not let this be a problem for the server to deal with. You are right, in that serving media takes a different route through the system based on the particular Media Cache situation. This is further made troublesome if you are offloading to a CDN cache where you will never see the request.

So the alternative.

Tell the client (browser) to download it

Modern browsers allows use of the download attribute. It works like this:

This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want).

Reference: HTML Element Reference - A

It really depends on what type of business logic you have in mind. Seems to me however, that this approach would be the path of least resistance for you.

Alternatively, @JammyKam also blogged quite extensively on the various options.

  • I'm remembering that for future reference, that's excellent, though I think I may still need to investigate other options in case I need to work with other headers for non-browser apps. Thanks. Sep 29, 2017 at 13:18
  • And IE of course sigh Sep 29, 2017 at 13:27
  • Edge supports it. And you can workaround IE with a small JS hack. navigator.msSaveBlob(blob, fileName);
    – Mark Cassidy
    Sep 29, 2017 at 14:17
  • 1
    I think I'd prefer to handle it in one place, server side really. There's a Q/A here using JammyKam's event handler and some lesser known methods that looked really interesting sitecore.stackexchange.com/questions/134/… What I like is it restricts itself to only doing the bare minimum and letting Sitecore carry the rest of the logic (as opposed to coding the entire response) - so 304 unchanged, range requests etc are handled natively. It's not an exact answer to this Q, but I think it provides an interesting model for us. Sep 29, 2017 at 14:49

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.