At times, you would wish to see the number of downloads your app (or any file) gets. The following tip discusses how this could be achieved. The intention is, if the user enters the url (for ex.) http://localhost:12345/downloads/CalendarControlSrc.zip
, track the download and then return the file that the user requested. This is how you do them in ASP.Net MVC 3 (should also work in MVC 2).
The first step would be to access the database layer to save the count. I am not discussing this as its out of scope for this tip. As we intend to serve a file instead of a view, we just need to return a FileResult that takes in 3 parameters (other overloads are also available). The parameters expected are:
- The url as received from Url.Content [Url.Content expects a virtual directory]
- The application type of the file to be served. In this case it's a zip file and so the
applicationType
is "application/x-compressed"
public ActionResult DownloadLink1()
{
string url = Url.Content("~/Content/downloads/CalendarControlSrc.zip");
return File(url, "application/x-compressed");
}
You may also wish to track the number of downloads you app (or some file) gets, when its hosted on another site. In that case, you cannot just use Url.Content as it expects a virtual path. So you will have to use the WebClient
class to first download this file and then return it. In this case we use another overload of FileResult, as we are downloading the file and then presenting it to the user. This overload takes in a 3rd parameter which is the file name that the client sees while the download link is clicked (the client is free to change the name, of course). This overload of FileResult takes in a byte stream as the first parameter instead of a path returned by Url.Content
. The first step just like the previous method would be to access the database layer to save the count.
public ActionResult DownloadLink2()
{
byte[] file = null;
using (var client = new WebClient())
{
file = client.DownloadData("http://www.codeproject.com/KB/webforms/Calendar/CalendarControlSource.zip");
}
return File(file, "application/x-compressed", "CalendarControlSource.zip");
}
Now, I will give an example as to how these action methods could be used. Lets assume these 2 action methods are in a controller called DownloadsController. We need to generate routes so that they could be added to various views. If you observe, unlike normal routes which doesn't have an extension in the url (in mvc), these url's need to have an extension so that the url indicates that it is indeed pointing to the path of the file about to be downloaded. So instead of just using Html.ActionLink
we need to use Html.RouteLink
, which generates url's depending on the format given in Global.asax.cs
file. To achieve this, add the 2 routes to the Global.asax.cs
file's RegisterRoutes
method (text in bold).
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("DownloadRt1", "downloads/CalendarControlSrc.zip",
new { controller = "Downloads", action = "DownloadLink1" });
routes.MapRoute("DownloadRt2", "downloads/CalendarControlSource.zip",
new { controller = "Downloads", action = "DownloadLink2" });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Finally, given below is a cshtml file that utilizes these 2 links
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@Html.RouteLink("download link 1", "DownloadRt1")
<br />
@Html.RouteLink("download link 2", "DownloadRt2")
The above Html.Routelink would generate the following links (assuming base url is http://localhost:12345) - http://localhost:12345/downloads/CalendarControlSrc.zip
and http://localhost:12345/downloads/CalendarControlSource.zip
. Html.RouteLink
is a helper method that generates links using the route name (From Global.asax.cs
passed in as the 2nd parameter. Clicking on these links would would call the database layer to log this download. Hope this tip was hepful!