Working with Virtual Path Providers
Introduction
In the majority of the web sites web form exist physically on the web server.
However, in some cases you may want to deviate from this storage mechanism. For
example, some Content Management Systems (CMS) allow the end users to add web
forms dynamically. In such cases disk based storage is tedious to manage. More
elegant approach would be to store the web forms in a database and serve them as
and when requested. But how can we accomplish this? ASP.NET Virtual Path
Providers (VPP) is the answer. In this article I will illustrate how a simple
VPP can be developed and plugged in your web site.
What are Virtual Path Providers?
Normally whenever you submit a request for a web form, IIS and ASP.NET assume
that the requested web form (.aspx) exists physically on the hard disk. Virtual
Path Providers (VPP) allow you to deviate from this default assumption. Using
VPP you can serve the request for a web form from a database or any other
storage mechanism. This way the web form need not exist physically on the web
server. VPP approach is best when you have a part of your web site that requires
web forms generated dynamically. If you are thinking of using VPP as a
substitute for the traditional disk based storage then be careful to evaluate
the performance penalty involved.
The System.Web.Hosting namespace provides three important classes viz.
VirtualPathProvider, VirtualFile and VirtualDirectory. Together these classes
allow you retrieve web forms stored in any location. In the following example I
will show you how this can be done.
Creating a VirtualFile
The virtual file is a class that represents a requested file (typically a web
form). In order to create a virtual file you need to write a class that inherits
from VirtualFile base class. The following code shows an example.
public class DbVirtualFile:VirtualFile
{
...
}
Here, we created a class named DbVirtualFile that inherits from VirtualFile
as the base class. The constructor of the VirtualFile base class accepts virtual
path of the file being requested as a parameter. Hence, your class (DbVirtualFile)
needs to pass this parameter to the base class. The following code shows how
this can be done.
public DbVirtualFile(string virtualpath)
:base(virtualpath)
{
string strConn = ConfigurationManager.ConnectionStrings
["connstr"].ConnectionString;
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "select webformcontent from webforms
where virtualpath='" + virtualpath + "'";
object retval = cmd.ExecuteScalar();
cnn.Close();
if (retval != null)
{
WebFormContent = retval.ToString();
}
}
The constructor of DbVirtualFile class accepts virtual path of the file being
requested as a parameter. This parameter is then passed to the base class
VirtualFile. The constructor then reads the web form content from the WebForms
table (see code download for the database). The public property WebFormContent
is then set to the content of the web form we just retrieved.
Now comes the important part. The DbVirtualFile class should override the
Open() method of the VirtualFile base class and return the content of the web
form as a Stream. This way ASP.NET need not know from where the web form was
served. The overridden Open() method is given below:
public override Stream Open()
{
MemoryStream ms = new MemoryStream();
if (WebFormContent != null)
{
byte[] data = ASCIIEncoding.ASCII.
GetBytes(WebFormContent);
ms.Write(data, 0, data.Length);
}
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
The return type of the Open() method is Stream. This abstraction allows us to
return any type of stream (MemoryStream, FileStream etc.) from the method. In
our example we create an instance of MemoryStream. We then write the contents of
the web form into it. Before returning the MemoryStream we take its read pointer
to the beginning. Failing to do so can cause unexpected results (a blank page
for example).
This completes our implementation of virtual file. Now it's time to develop
VirtualPathProvider that makes use of DbVirtualFile class.
Creating a VirtualPathProvider
In order to create your own VirtualPathProvider you need to create a class
that inherits from VirtualPathProvider base class (see below).
public class DbVirtualPathProvider:VirtualPathProvider
{
...
}
Then add a static method named AppInitialize() to the DbVirtualPathProvider
class. This method is called automatically by the ASP.NET framework and it
registers your custom virtual path provider (DbVirtualPathProvider in the above
example) with the ASP.NET framework.
public static void AppInitialize()
{
DbVirtualPathProvider db = new DbVirtualPathProvider();
HostingEnvironment.RegisterVirtualPathProvider(db);
}
The AppInitialize() method simply creates an instance of
DbVirtualPathProvider class and registers it with ASP.NET framework by calling
RegisterVirtualPathProvider() method of the HostingEnvironment class. This is
how ASP.NET framework becomes aware of our virtual path provider.
Next, you need to override two methods of the VirtualPathProvider base class
namely FileExists() and GetFile(). The former method returns a Boolean value
indicating whether the requested file exists or not. The later method returns a
VirtualFile from the underlying storage mechanism (database in our case). These
methods are shown next.
public override bool FileExists
(string virtualPath)
{
string strConn = ConfigurationManager.
ConnectionStrings["connstr"].ConnectionString;
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "select count(*) from webforms
where virtualpath='" + virtualPath + "'";
object retval = cmd.ExecuteScalar();
cnn.Close();
int i = Convert.ToInt32(retval);
if (i <= 0)
{
return false;
}
else
{
return true;
}
}
The FileExists() method simply checks if the requested file exists in the
WebForms table. Notice that the FileExists() method receives the virtual path as
a parameter.
public override VirtualFile GetFile
(string virtualPath)
{
DbVirtualFile file = new DbVirtualFile
(virtualPath);
if (file.WebFormContent == null)
{
return Previous.GetFile(virtualPath);
}
else
{
return file;
}
}
The GetFile() method simply constructs a new instance of DbVirtualFile class.
It then checks if the WebFormContent property has anything and accordingly
returns the DbVirtualFile instance back. Notice the use of Previous inbuilt
property. This property gives a reference to the previously registered
VirtualPathProvider (i.e. the default one in our case). This way if the
requested file doesn't exists in the database ASP.NET will try to get it from
physical file system.
That's it! We have just completed our virtual path provider and are ready to
test our web site. Open the WebForms table in Server Explorer and add an entry
for Test.aspx

Notice that the virtual path of Test.aspx also includes its application name
(VirtualPathProviderDemo). Then run the web site and manually navigate to
Test.aspx. You should get the results as shown below.

Observe that Test.aspx doesn't exist physically but because of our virtual
path provider ASP.NET is able to serve its contents.
|
About the Author
|
|
Bipin Joshi |
|
Bipin Joshi is a blogger and writes about Yoga, spirituality and technology. A former Software Consultant by profession he worked for many years with Microsoft technologies such as C, C++, C#, VB, ASP and ASP.NET. Bipin got selected as a Most Valuable Professional (MVP) by Microsoft for six consecutive years before he decided to take a back seat from the mainstream IT to continue his spiritual interests. More details about him can be read here. |
|