The ASP.NET Virtual Path Provider - An Example Implementation
I started reading Programming Microsoft ASP.NET 2.0 Applications: Advanced Topics again recently and ran across something in Dino’s book that was piqued my interest. ASP.NET 2.0 comes built with this concept of the Virtual Path Provider.
The virtual path provider system is a method of raising the layer of abstraction when it comes to ASP.NET and the file system. In ASP.NET 1.1 System.IO was used directly by ASP.NET to access the file system. In 2.0 it works through the MapPathBasedVirtualPathProvider class. That class, in turn, uses the MapPathBasedVirtualFile class to access the files through System.IO.FileStream. This is not significant, of course, unless they allow you to hook into this provider model and take over the process...which they do.
This virtual path provider system is primarily driven by three abstract classes in the System.Web.Hosting namespace, VirtualPathProvider, VirtualFile, and VirtualDirectory. ASP.NET 2.0 has implementations of these in the same namespace, MapPathBasedVirtualPathProvider, MapPathBasedVirtualFile, and MapPathBasedVirtualDirectory. I do not see any documentation on these on MSDN, but they aren’t too hard to find with Reflector. To those familiar with ASP.NET "MapPath" should remind you of Server.MapPath, something you can use if you need the physical location of a file and all you have is the virtual path. The MapPathBasedVirtualPathProvider and its helpers do the "MapPath" work for ASP.NET, fetching the physical files for processing.
What extending your application with a custom implementation of the VirtualPathProvider gives you is the ability to change how that works, allowing you to access the file system differently, or more likely, allowing you to look anywhere you choose for the content you need to fulfill the page request. This feature was, according to Dino, added for the Sharepoint team. Sharepoint stores quite a bit of content in Sql Server (so I understand...I haven’t used it much myself), so creating this allows them (or anyone else) to pull pages not from the file system but from anywhere. You could get your aspx files from Sql Server, you could pull them from a zip file, you could construct them from .txt files (not that that would be a good idea), you could get them by calling a web service (though surely only the insane would do this), or whatever. The sky (or more accurately, the full capabilities of the .NET framework) is the limit.
Why and When?
So this is cool, but does it have any practical application? I think it does. Take, for example, how Community Server "archives" posts. For our example we will look at the last post on the North Dallas .NET User Group blog aggregator. You can find it here. Note the "archive/2007/04/02/Telligent-Internship-Program.aspx" page. If you were to hack their servers and check their file system, you would find that those directories and that .aspx file do not exist. They create these "fake" pages through url rewriting. You are not really seeing that aspx page; you are seeing data served up from Sql Server. This is a great method for avoiding something like "http://cs.nddnug.net/blogs/postviewer.aspx?id=789452798", which is similar to how I am currently showing posts on this blog (but not for long). The url is not very informative and it is also not (from what I hear) search-engine friendly. So they use url rewriting to make you and search engine crawlers everywhere think that there are really pages there.
I have not seen anybody mention this as a possible application for extending the virtual path provider model, but it totally makes sense to me. That seems like exactly what it was made for. Community Server would not be using it because this feature was added in ASP.NET 2.0. This would explain why every method I have seen of doing something like this uses url rewriting. But should we be doing something else now that ASP.NET 2.0 is out?
At the bottom is a link to download a sample that implements this. There are three important pieces. First, included is a script for creating a "Posts" table and filling it with some data. To run the sample you will need to create a database and run the script. Second is a web application project that has the basic web code called "VirtualPathProviderTest". Third is a class libary called VirtualPathProviderLib.
VirtualPathProviderTest: There are three files of significance. First is the web.config. Change the connection string to point to your own database. Second is the MasterPage, which has the repeater that will list the posts. Third is the Global.asax. This latter file is the only one that is truly pertinent to the implementation. In Application_Start the custom VirtualPathProvider is registered. Doing this is simple enough (it only takes two lines), but is necessary.
VirtualPathProviderLib: There are several files in this library that are there simply for the sake of making the example functional (Post.cs, PostCollection.cs, and Data.cs). The actual implementation of the logic for the virtual path provider system are found in CustomPathProvider.cs and CustomVirtualFile.cs.
I annotated the code in various places to explain why certain things are done the way they are. I hope you find that helpful.