In this post I will describe how to create virtual views for ASP.NET MVC. These are views that do not exist as files in the regular place in the file system (~/Views/xxx/yyy.aspx), instead they are stored somewhere. Elsewhere in this case can be a database or perhaps a .ZIP file. This is all made possible by the VirtualPathProvider class (and some supporting classes) in ASP.NET. While the example will use MVC framework and views, the class provides much more. With it you can virtualize any web content (css, gif/jpg, js, aspx, etc) and it can be used in any ASP.NET application, nut just MVC.

Use cases

When would you need such a virtual view system?

If you want users to be able to customize Views, but without them having access to the Web solution or source code. In this case the user could upload the View into the database, where it is stored. When the application wants to display the view, instead of reading the view source from the file system it will be read from the database. MVC will not know the difference and believes it is found under the regular ~/Views/... path.

Another possibility would be to use a ZIP file based virtual path provider. Here the user could create a custom skin by creating or customizing views (.ascx, .aspx) and adding new content (css, images). The user would then pack it into a ZIP, upload into the server, and server would serve the custom skin directly from the .ZIP file. This way with multiple skins installed the file system would not be polluted by a vast amount of files.

There are of course many more possibilities I could think of, but I hope you get the point

Getting ready

Before we begin, lets create a simple database table that will store the data for our example. It is very badly designed I have to admit , but will serve our purpose.

I called the table Pages and the idea is that it will serve dynamic pages into my MVC application. Kind of like a very simple CMS. However, I want to customize the view layout (.aspx), and not just the data itself. So I ended up with a table like this:

The table contains the data for the page (Body, Title) and the name/virtual path of the view (ViewName) and of course the view file itself (ViewData, uploaded as binary). Here is an example row. I uploaded a simple .ASPX view into the row.

In my example solution I added a LINQ to SQL .dbml to the solution (named MyMvcVp), dragged and dropped my table into the designer. I could then use the generated data context to access the database.

Controller

Next is my PagesController.cs that will serve our dynamic content pages. To display such a page I decided to use default route already available in the MVC template: /controller/action/id. I added a single Display action to the controller which will get the id parameter as a string value. This will have to correspond to the PageId field in the database. For example: /Pages/Display/d9b07a02-7c47-41d9-8c21-bf546841bb6c. The resulting code follows:

The code is very simple: it uses LINQ to look for the page, and if found, we extract the data from it, and instruct MVC to show it using our ViewName. To make the example very simple I included the virtual path in the database column, so here I use GetFileNameWithoutExtension() to get just the View name.

Because I wanted to keep the example simple I decided not to support virtual folders (which is also possible). So the folder where the virtual files seem to reside needed to be created also. I created a new Pages folder under /Views in the solution. If you implement virtual folders than this step could be left out.

At this point we still miss the actual VirtualPathProvider implementation. Without that you will get an error message when accessing this action, because MVC will not find the View.

VirtualPathProvider
So I added a new file MyVirtualPathProvider.cs to the solution. This contains the MyVirtualPathProvider class, that derives from VirtualPathProvider. I overrided two methods, FileExists() and GetFile(). Both get the virtual path (application relative). The first checks if a file exists, and the second returns the file from the file system - in this case the database.

Here is the code I used. Note that Page in this case refers to the LINQ class that was generated for the Pages table, and not the ASP.NET Page class.

As you can see if I don't find the virtual path in question from the database, the base implementation is called. That will just try to look up the file from the regular file system location.

You should notice that I used a class that I did not yet talk about: MyVirtualFile. This is just a simple implementation of the VirtualFile abstract class. Its purpose is to return a Stream where the file can be read. In my example I will just return a MemoryStream using the data from the database table. But this is where you would read the file from the actual place and pass it back to the framework.

If you wanted to support virtual directories you would also override the DirectoryExists() and GetDirectory() methods from the VirtualPathProvider. You would also need a custom VirtualDirectory derived class.

Registering the custom VirtualPathProvider

As a last step the MyVirtualPathProvider must be registered with ASP.NET. To accomplish this you need to add the following call to the application:

The best place is probably in the Init() override of the application class or perhaps the Application_Start event handler (global.asax, unless you coded a custom application class somewhere in which case that would be the ideal place).

Conclusion

Virtual files and directories can be used to extend an existing MVC application (or a Web Forms application) by allowing you to store files in a place that is different from the regular file system. Be it a database, ZIP file or a remote network location, by using VirtualPathProvider the rest of the application will not have to know anything about the actual storage strategy.

I agree with Wednell, I have not been able to get it to work with MVC5.

I posted this sample with Mvc5:
http://forums.asp.net/t/1990471.aspx?GetFile+not+beeing+called+in+VirtualPathProvider+Mvc5+

GetFile is never called and an exception is thrown as soon as FileExists returns true and a File does not exist.

I do not know where to go from here, Kind blessings

Re: ASP.NET MVC and virtual views

written by
ali
@ Tuesday,
03 June 2014 14:58

hi
my virtualpathprovider work when i run project with visual studio and iis express
but not work when i publish this on iis
plz help

Re: ASP.NET MVC and virtual views

written by
Lenard Gunda
@ Saturday,
10 May 2014 11:05

Hi Wednell,

I played around in MVC 5 recently with compiling and serving Razor views from a .DLL. I will have to check what I did, because I did not run into any trouble there. Of course there I did much more than just serve views as I needed to compile them as well, but the basics should be the same. Let me get back to you on this one.

/Lenard

Re: ASP.NET MVC and virtual views

written by
Wednell
@ Wednesday,
07 May 2014 19:31

Maybe it worked in mvc4 but in mvc5 this does not work GetFile is never called. If FileExits returns true asp.net is bypassed and IIS assumes it can get it which results in a:

HTTP Error 404.0 - Not Found

The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

Any suggestions?

Re: ASP.NET MVC and virtual views

written by
amir
@ Friday,
02 May 2014 08:08

LIKEEEEEE

Re: ASP.NET MVC and virtual views

written by
Krishna
@ Friday,
10 January 2014 14:53

Could u please post the source code of the example

Re: ASP.NET MVC and virtual views

written by
Lenard Gunda
@ Sunday,
20 October 2013 20:57

Hi Mohsen,

Thank you for your feedback! I will try to fit in the time to publish the source code for this article sometime in the future.

/Lenard

Re: ASP.NET MVC and virtual views

written by
Mohsen
@ Thursday,
10 October 2013 23:12

Hi Lenard
Your articles are great but I can't use them!
Is it possible put sample application with download link in your articles?

Re: ASP.NET MVC and virtual views

written by
Lenard Gunda
@ Tuesday,
01 October 2013 07:13

Hi Anthony,

I don't think you should use my approach of virtual views to create dynamic menus for users.

You are talking about menus, so I assume you have a repeating list of elements, maybe on multiple levels (sub-menus). I would recommend doing only one view to display your menu structure.

What I would then do in the model or controller, is filter the list based on the role of the user. Maybe even load only those elements (from the datastore) which the current user has rights to.

By including this kind of logic in your Views, you are going against the Model-View-Controller pattern. Your view should be dumb - just display the things it gets. Simple if statements are acceptable or things that affect how things look ("is this a green button or a blue button").

But doing conditional logic that affects WHAT is displayed is something I would leave to the Model itself. The Menu view should already get a filtered list of the items to be displayed.

Re: ASP.NET MVC and virtual views

written by
anthony fernandes
@ Wednesday,
04 September 2013 01:15

Very interesting and thank you for the article.
I wanted to use this for creating dynamic menus and needed your advice
Option 1:
If (role==admin)
load partial_view_admin
if(role==user)
load partial_view_user
if(role==agent)
load partial_view_agent
This requires me to create x views for x roles. So this is out

Method 2:

The other approach was to render the menu options dynamically in the partial view

if(role==admin)
load partial view dynamically for admin from the db and cache the result.

I was wondering if you could help me decide between method 2 and 3 with regards to performance and ease of maintenance. With method 2, I still need to create the menu object from the cache well as in case of method 3, I load the partial view itself from the cache. Hence the confusion.
Please advise.

Thanks!

Re: ASP.NET MVC and virtual views

written by
Lenard Gunda
@ Friday,
15 March 2013 08:28

Kevin, I did not try this with Razor yet, so I cannot say how you would do that.

wirol, I don't understand your question. Validation would work the same way in the views that are served from the database as they would work with regular views?

Andrej, good idea to try with partial views.

Maybe I will revisit the subject given how much time passed since the article was published and add support for Razor and partial views

Re: ASP.NET MVC and virtual views

written by
Kevin Boss
@ Tuesday,
22 January 2013 09:58

Hey, I just wanted to ask you if there is any solution to implement the namespaces which are usually served by the Web.config file. I have to call methods from Razor but i can't since i don't have anything to call.

Re: ASP.NET MVC and virtual views

written by
wirol
@ Saturday,
22 September 2012 18:59

This is a very nice approach to use dynamic virtual views.
But how could we use the dataannotaion/validation attributes in this scenarios?

Or how should we design the model validation for virtual views?

Thanks.

Re: ASP.NET MVC and virtual views

written by
Marcos Lima (marcoslimagon)
@ Tuesday,
08 May 2012 02:28

I will try to implement this post using MVC 3 + RAZOR + caching and also trying run the controller by some kind of F# "Engine", to make a easy to go approach... this post gave me useful crazy ideas =)

Thanks!

Re: ASP.NET MVC and virtual views

written by
Andrej
@ Thursday,
14 July 2011 16:25

Have you thought about extending the code to render partial views?

Re: ASP.NET MVC and virtual views

written by
Lenard Gunda
@ Wednesday,
02 March 2011 07:33

@Brian,

Are you using IIS hosting or the VS development web server? Or perhaps IIS Express?

I created this example some while back, but created a new one with .zip files that I published yesterday. As I was testing that (the .zip version) I specifically used features like ViewBag to verify functionality was not lost. Have you tried running that example? You can download that in source code format as well.

Re: ASP.NET MVC and virtual views

written by
Brian
@ Tuesday,
01 March 2011 20:54

The loading part works great, but when the view executes, it can't find Razorish concepts like ViewBag.

Thanks for the heads up, nice to hear you found this useful! Looking forward to reading the book

Re: ASP.NET MVC and virtual views

written by
Andrew Siemer
@ Sunday,
22 August 2010 04:57

This seems to hit the database quite frequently. I am thinking that a list of excluded paths and/or file extensions should be stored somewhere to bypass the number of queries made against the db. Anyways - very nice post. I will probably include some parts of this (along with your name and a link back to this article) in my upcomming book "ASP.NET MVC Cookbook". You can find a public preview of the book here if your interested: http://groups.google.com/group/aspnet-mvc-2-cookbook-review Your bits will be covered in chapter 7!

Thanks!

Re: ASP.NET MVC and virtual views

written by
Adam Lawrence
@ Thursday,
22 July 2010 18:10

I have implemented something just like this for a CMS system, the idea being that the virtual view would always be refreshed from the Database, this works nicely when my application is first strated after that the open() overriden method in my virtualfile class is never hit when I put a break point in after the initial time. I have tried adding a cachedependency to expire the cached item but nothing works. Any ideas?

Re: ASP.NET MVC and virtual views

written by
Adrian
@ Thursday,
21 January 2010 15:19

Apologies - my mistake. My data store / VPP combination was returning a file when it should have fallen through to the base methods, therefore bypassing the controller.

Next time, I'll test a bit more thorougly before I shout for help.

Thanks for the post!

Re: ASP.NET MVC and virtual views

written by
Lenard Gunda
@ Thursday,
21 January 2010 08:52

Abhi:
I will try to make an example with ZIP files, sometime in the future.

Adrian:
As far as I recall, it should be possible to put view logic into the views using this approach. I will have to get back to you on this one, as soon as I get back home on friday.

Re: ASP.NET MVC and virtual views

written by
Adrian
@ Wednesday,
20 January 2010 14:03

Hi - Found this post potentially useful, but, my stumbling block is that I don't appear to be able to put View Logic inside my View (as stored in the DB), ie. <%=DateTime.Now%> renders as <%=DateTime.Now%> and doen't show the current datetime.

Is this possible using this approach - for the record, I am using the current beta MVC 2.

Apert from my method of storage, all my code is identical to that provided in this post.

Re: ASP.NET MVC and virtual views

written by
Abhi
@ Monday,
28 December 2009 17:30

Thanks for the post; a very thoughtful idea - storing MVC views in the DB. Although I found the idea to read views from the zip file for dynamic themes to be a more practical implementation. But yeah this could be a good beginning for creating a CMS based on ASP.NET MVC on the lines of gosted/unghosted pages in MS Sharepoint.

Re: ASP.NET MVC and virtual views

written by
Alex
@ Thursday,
24 December 2009 22:10

Khalid, what were the issues you experienced? I am curious as I have done this on several occasions and been happy but may not have run into all the potential issues. One must be careful to use caching appropriately for decent performance since pages change rarely and thus the hits to the database should be rare as well.

Re: ASP.NET MVC and virtual views

written by
Khalid Abuhakmeh
@ Wednesday,
23 December 2009 20:29

Pretty good example, terrible idea to store your views in the database.

I'm having flashbacks now to previous projects where the idea of storing ASP.NET pages in a database sounded like a good idea.

I would have liked to see the implementation of the views stored in a zip file, that would be kind of cool.