A Download Control with a counter with Sitecore

Recently I needed to have some download-able files available on a Sitecore website. One restriction was that although registered users of the site and members of the organisation could download as many files as they liked, Anonymous users were restricted to three downloads per session.

The solution is clearly still to store the downloads (PDFs and the like) in Sitecore, but not to simply offer a URL to them for download.

Well, I can download the file by doing a Response.BinaryWrite, get the bytes from Sitecore and check the count and download in an OnClick handler.

Here is the mark-up:

<div class="related-download-item">
	<div class="download-image">
		<asp:ImageButton id="LinkButtonDownload" runat="server" 
			ImageUrl="/images/pdf-download-small.png" OnClick="Download_Click" /> 
	</div>
	<div class="download-info">
		<asp:LinkButton ID="DownloadNowLink" CssClass="download-link-button"
		Text="Download Link" runat="server" OnClick="Download_Click" />  
	</div>
</div>

I can add the Sitecore item GUID to the download items as a custom attribute to the ImageButton and LinkButton:


Item downloadItem = Sitecore.Context.Database.GetItem("/path/to/item");

LinkButtonDownload.Attributes.Add("xref", downloadItem.ID.Guid.ToString());
DownloadNowLink.Attributes.Add("xref", downloadItem.ID.Guid.ToString());

and then pick it up in my OnClick handler:

protected void Download_Click(object sender, EventArgs e)
{
	var linkButton = sender as WebControl;
	if (linkButton != null)
	{
		var href = linkButton.Attributes["xref"];
		if (!string.IsNullOrEmpty(href))
		{
			var downloadItem = Sitecore.Context.Database.GetItem(new ID(href));
			if (downloadItem != null && CanDownloadFile())
			{
				var media = Sitecore.Resources.Media.MediaManager.GetMedia(downloadItem);
				var stream = media.MediaData.GetStream();
				var buffer = ReadToEnd(stream.Stream);
				Response.ContentType = downloadItem["Mime Type"];
				Response.AddHeader("Content-Disposition",
				string.Format("attachment;filename={0}.{1}", 
                                downloadItem.Name, media.Extension));
				
                                Response.AddHeader("content-length", 
                                buffer.Length.ToString(CultureInfo.InvariantCulture));
				Response.BinaryWrite(buffer);
				Response.End();
			}
		}
	}
}

by adding the bytes as an attachment using the Content-Disposition, the file comes to the browser as a download as expected.

In an appropriate method I can decide if the user should be allowed to download the item or has exceeded their “quota”.

private bool CanDownloadFile()
{
	var memberType = MembershipType();
	if (memberType == MembershipTypes.Member || memberType == MembershipTypes.Registered)
	{
		return true;
	}

	// Limit the number of media displays (aka downloads)
	if(Session[numberOfDownloadsSessionName] != null)
	{
		var downloads = (int)Session[numberOfDownloadsSessionName];
		// code to evaluate number of downloads etc
	}
}