[Full code sample provided at the bottom of this post]
I use A-Drive from time to time to host small files that I want users to download for various personal projects (mainly to help conceptualize the market for entrepreneur start-up ideas). Lately I needed to use it for a project where I needed to track the number of downloads a particular file had. Normally this is something I could code up real quick, but I literally wanted to get this up and running within minutes. I’m running a site using the Graffiti CMS so I’m doing this to get some quick feedback cycles in regards to if my "product" I’m offering is worth the time to invest a full implementation. (MicroTesting).
I had uploaded the file, and then accessed it from three different networks to realize that the incremental counter was NOT incrementing. WTF?! I messed around with it some more… I deleted my cookies (thinking that maybe they wrote a cookie to verify I downloaded it so it didn’t double dip in the count for my multiple downloads – aka: Unique Downloads). I contacted support, but it was the weekend so I didn’t expect a reply.
Update
I received a reply from the company in regards to their download counter not working:
Dear Donn,
This is currently a bug in our system that we will resolve very soon.
Thanks,
-ADrive Support Team
So.. it was now time to create a simple HttpHandler to count downloads for me.
How To
Note: This is a very very very simple example of how you can count downloads (and no, it does capture unique user downloads). This can be altered very easily to do this.
My Simple Requirements.
– Persistence Medium For The Counter (XML)
– Increment the counter
– Allow the user to download the file
The best place to implement this functionality is inside of an HttpHandler by using the IHttpHandler Interface. The reasons are simple: I don’t need a UI, I don’t need complex business logic (remember – this is a super quick implementation to fix a simple problem).
Code
1 using System; 2 using System.IO; 3 using System.Text; 4 using System.Web; 5 using System.Xml; 6 7 /// <summary> 8 /// Increments a counter and forces a download to the user. 9 /// </summary> 10 public class DownloadHandler : IHttpHandler 11 { 12 private readonly string COUNTER_REPOSITORY = "App_Data/ExampleCounter.xml"; 13 private readonly string MY_FILE = "App_Data/Example.pdf"; 14 private readonly string SAMPLE_DOWNLOAD_COUNT_ELEMENT = "SampleDownloadCount"; 15 16 #region IHttpHandler Members 17 18 ///<summary> 19 ///Enables processing of HTTP Web requests 20 /// by a custom HttpHandler that implements 21 /// the <see cref="T:System.Web.IHttpHandler"></see> interface. 22 ///</summary> 23 ///<param name="context">An 24 /// <see cref="T:System.Web.HttpContext"></see> object that provides 25 /// references to the intrinsic server objects (for example, Request, 26 /// Response, Session, and Server) used to service HTTP requests. </param> 27 public void ProcessRequest(HttpContext context) 28 { 29 IncrementCounter(context); 30 SendFileToUser(context); 31 } 32 33 ///<summary> 34 ///Gets a value indicating whether another request can use 35 /// the <see cref="T:System.Web.IHttpHandler"></see> instance. 36 ///</summary> 37 /// 38 ///<returns> 39 ///true if the <see cref="T:System.Web.IHttpHandler"></see> instance 40 /// is reusable; otherwise, false. 41 ///</returns> 42 /// 43 public bool IsReusable 44 { 45 get { return false; } 46 } 47 48 #endregion 49 50 /// <summary> 51 /// Sends the file to the user. 52 /// </summary> 53 /// <param name="context">The <see cref="HttpContext"/> that 54 /// contains the request.</param> 55 private void SendFileToUser(HttpContext context) 56 { 57 // Send the file to the user. 58 FileInfo fileInfo = new FileInfo(context.Server.MapPath(MY_FILE)); 59 60 context.Response.ContentType = "application/pdf"; 61 context.Response.AddHeader( 62 "Content-Disposition", 63 "attachment; filename=" + fileInfo.Name); 64 context.Response.WriteFile(fileInfo.FullName); 65 context.Response.End(); 66 } 67 68 /// <summary> 69 /// Increments the counter. 70 /// </summary> 71 /// <param name="context">The <see cref="HttpContext"/> that contains t 72 /// he current request</param> 73 private void IncrementCounter(HttpContext context) 74 { 75 int value = int.MinValue; 76 string fileName = context.Server.MapPath(COUNTER_REPOSITORY); 77 using (XmlTextReader reader = new XmlTextReader(fileName)) 78 { 79 reader.ReadStartElement(SAMPLE_DOWNLOAD_COUNT_ELEMENT); 80 value = Convert.ToInt32(reader.ReadString()); 81 } 82 value++; 83 using (XmlTextWriter writer = new XmlTextWriter(fileName, Encoding.ASCII)) 84 { 85 writer.WriteElementString( 86 SAMPLE_DOWNLOAD_COUNT_ELEMENT, 87 value.ToString()); 88 } 89 } 90 91 92 93 94 } 95
How It Works
We have to add a line to the web.config to tell ASP.NET about the Handler and to only listen to the "GET" Http Requests.
1 <httpHandlers> 2 <add path="Download.ashx" verb="GET" type="DownloadHandler"/> 3 </httpHandlers>
When the app is fired up we first access the request, then open an XML file that looks like this:
<SampleDownloadCount>8</SampleDownloadCount>
The file is parsed, the value is incremented and then we write the value back to the file. I’m almost positive there is a more elegant solution to this but remember, I wanted this to get done FAST, I’m not looking for pretty in this implementation. Technically, this is throw away code if my test works (my 1 week MicroTesting phase). Then I go into full development.
After the counter is incremented we send the file to the end user through the response.
Note: The file "Example.pdf" is hard coded in this example but you could easily set this up so that the file represented an identifier through the query string (download.ashx?DownloadId=1) where 1 might equate to "Example1.pdf" and 2 might equate to "Example2.pdf". Think about it awhile and run with it. Remember, this is an extremely simple example for how to count downloads.
Conclusion
It’s very simple to implement this counter in a regular ASP.NET web site. Although its not production quality code, it will work for simple testing and monitoring of file downloads and should supply you with a starting point to move forward with download counters.
In a future post I will show you how you can use this inside of the Graffiti CMS to help track your download counts.
Downloads
You can download a sample example site here: FooTheory.DownloadHandler.Example.zip (7.39 KB)
Coach Outlet Online says
http://www.mycoachoutletstoreonline.com
Carloserei says
Hi sir:
I have some questions need your help.
1.
the “Download.ashx” is not exist, right?? or just spelling error?? (“Download.aspx”)2.
This version is only single file, if I would like to add more file, should I update the code each time?
Thanks
Owen
skype: reicarlose
e-mail: [email protected]
Coach Factory Online says
Business coaching is an informal, open affair. You will meet with the coach and he will assess your business’s needs, and then tailor his services to your precise requirements.
Coach Factory Outlet says
http://buycoachfactoryoutletsz.com