The question "https://stackoverflow.com/questions/16397785/add-pages-to-mvc-deployed-website" seems to relate closely to the question I want to ask. But it my case, I have not yet developed an application, but I want to develop it in such a way that it can be customized by users after it is deployed by adding files to the deployed directory. What would be the advisable way of doing this? Specifically, I want users to be able to define custom pages, possibly replace existing pages or add controls to existing pages, and possibly define custom WebAPI functions to retrieve custom data. I tried adding .vbhtml files to the Views directory as described, but ran into the same problem described in the linked question.
4 Answers
I don't think I would recommend using the filesystem for this. I think you should save the razor code to the database and then, when you wish to parse it, you may do so according to this Using RazorEngine to parse Razor templates concurrently
Here is another example:
var model = new { Name = "Test" };
var template = "Hello @Model.Name";
var result = Razor.Parse(template, model);
Code taken from Using Razor engine on strings - not views
Edit to answer your questions:
The razor code would be stored in the database along with whatever controller you wanted to run it. When you retrieve the razor code from the database, you would also know the controller, then you could redirect to that controller, sending whatever model you want, to the razor code, and then parse it as shown above. Make sense?

- 1
- 1

- 20,790
- 32
- 144
- 264
-
Does this restrict what can be customized? For example, does it only allow custom views to be defined and not custom controllers or models? Does it only allow existing views to be customized and not allow the creation of new views? Not being clear on how controller, model and view integrate in this scheme, I'm confused about where this code would go. In a controller? In a view? – BlueMonkMN Jan 07 '14 at 21:35
-
There isn't enough information to suggest that you should or should not use the file system to store the views. One could easily use a VirtualPathProvider and store the views in the database instead of the file system. The real question is in what manner does BlueMonkMN want the users to be able to edit them after the are deployed. Assuming that each installation is a single user's site the user would have access to the file system and could modify views. Keep in mind that changing the views does not change how the application behaves as that is all contained within the controller actions. – Nick Bork Jan 07 '14 at 21:38
-
See my edit. Not using the filesystem is just a personal preference based on my experience. – user1477388 Jan 07 '14 at 21:39
-
I'm still confused. With controllers being the entry point to the code, how would ASP.NET MVC know to load a controller from the database when redirecting to it instead of loading it from the dll. Or is the set of controllers pre-determined and hosted on in compiled code as always (un-customizable)? – BlueMonkMN Jan 07 '14 at 21:50
-
See http://stackoverflow.com/questions/7892094/mvc-redirect-to-index-from-another-controller which will show you how you can redirect from one controller to another. On each controller, you could implement a "Render" method which would send the model to the parsed razor view (after retrieving it from the database). – user1477388 Jan 07 '14 at 21:53
-
In ASP.NET MVC, out of the box, the controllers would be compiled and un-customizable. By extending the base features and creating your own custom controller factory to over-ride which controller action gets executed. – Nick Bork Jan 07 '14 at 21:55
-
@user1477388 My confusion is not how to redirect from one controller to another. That's pretty obvious, I assume. My problem is what am I redirecting to/from? Redirecting to another controller doesn't do me any good if there's still no way to incorporate custom code into the mix somewhere. Redirecting from one controller to another doesn't *accomplish* anything toward the goal of allowing custom code to be put in place in a deployed ASP.NET MVC application. – BlueMonkMN Jan 08 '14 at 12:13
Razor views are compiled at runtime, so you always deploy them un-compiled.
What you want is simply Razor pages, so can add them to any directory (not Views) and access them without the file extension (e.g. /Foo/Bar instead of /Foo/Bar.vbhtml).

- 28,282
- 11
- 76
- 114
-
But in order to access a view, you apparently need to have a controller compiled in front of it. Or am I missing something? – BlueMonkMN Jan 07 '14 at 21:37
-
Razor pages don't need controllers, just like `.aspx`. See http://www.asp.net/web-pages – Max Toro Jan 07 '14 at 21:41
-
In order for a Razor View to be rendered you need a Controller/Action to answer for the inboud HTTP request. You can build a modified version of the Razor view engine that would be capable of looking for customizated controller action in a plugin like architecture but that is a lot of work to build but can be done. – Nick Bork Jan 07 '14 at 21:43
-
-
When I try to access a razor page outside of the Views directory, I get "The type of page you have requested is not served because it has been explicitly forbidden. The extension '.vbhtml' may be incorrect. Please review the URL below and make sure that it is spelled correctly." – BlueMonkMN Jan 07 '14 at 21:45
-
This is an ASP.NET MVC application, you will not be able to directly access a view. All requests must be routed through the controllers UNLESS it's a request for a static file. – Nick Bork Jan 07 '14 at 21:46
-
-
@NickBork Again, there's a difference between Razor view and Razor page. An ASP.NET application can be a mix of MVC, WebPages, WebForms or any other application framework. – Max Toro Jan 07 '14 at 21:49
-
Yes, a Razor Page COULD be used in an MVC application (http://stackoverflow.com/questions/4886095/what-is-the-function-of-webpagesenabled-in-mvc-3-web-config) the OP doesn't suggest he wants to stray away from MVC. – Nick Bork Jan 07 '14 at 21:51
-
Switching webpages:Enabled to true improved the situation. Is this advisable or is there a better way? I wonder if the discussion in the linked question in my question was suggesting that this wasn't a good idea. I don't want to make a real mess of the architecture here. – BlueMonkMN Jan 07 '14 at 21:53
-
This is the easiest way to let users add pages to your base MVC app, since it doesn't require routes or controllers. – Max Toro Jan 07 '14 at 21:55
-
@NickBork Perhaps the OP thought he was stuck with the MVC pattern and that there was no other way. – Max Toro Jan 07 '14 at 21:57
-
While it will work you're leaving the MVC architecture behind in favor of just disconnected "pages". All work related to the page that you would have done in your controller/actions must now be done inside of your page. A Page is more complex than a View and more similar to how a WebForm page works. Depending on the application you want to build, this may or may not be acceptable to you. – Nick Bork Jan 07 '14 at 22:00
-
I guess the remaining questions are 1) Why is `webpages:Enabled` set to `false` by default and what should I consider before switching it to `true`?; 2) Is there a way to integrate customized partial views into my application? This solution doesn't provide a means to add custom fields to existing views. – BlueMonkMN Jan 08 '14 at 11:32
-
1.) webpages:Enabled prevents people from directly accessing the cshtml/vbhtml views on your site. This is because in the MVC pattern a Controller accepts a HTTP request and performs work and returns a View that is just the UI representation of that view. Max has suggested using Pages and not a Controller / View to do work as a way to customize the pages. This changes the architecture of your application. This assumes that you need the ability for users to customize the work that goes on in the controller. Even if you do need custom controllers there are ways in MVC to allow that. – Nick Bork Jan 08 '14 at 19:17
-
2.) Yes, you can allow customized views in MVC. There are several approaches like custom view engines with customized search locations, using a VirtualPathProvider to store the views in the database or may other ways to do this. What method you choose will largely depend on what type of application you're building and how "users" will customize it. For example, if all users share one single site (software as a service) and each needs to have a unique view for the same page you may need a custom view engine. If it's just a one-user to site type thing you may use a VirtualPathProvider and use DB – Nick Bork Jan 08 '14 at 19:22
-
You might want to consider what your models are and a more appropriate way to allow clients to have "extra" fields, such as a Dictionary (name/value pairs) of additional fields that they customized their install with. Building a more robust way of handling this custom extra data may allow you to customize the application without needing to modify the underlying architecture. You've only given us a small bit of information about your application so it would be hard for anyone to tell you what the best solution might be and StackOverflow really isn't a place to discuss application architecture. – Nick Bork Jan 08 '14 at 19:27
The routing configuration can be customized to identify a URL pattern that identifies all requests for customized code and route them through a common controller that can then load arbitrary views based on information provided in the URL. Notice the route with the name Custom
below, and how it always uses the Index
action of a controller named Custom
, but introduces a new parameter customization
.
Public Class RouteConfig
Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
routes.MapRoute( _
name:="Custom", _
url:="custom/{customization}/{id}", _
defaults:=New With {.controller = "Custom", .action = "Index", .id = UrlParameter.Optional} _
)
routes.MapRoute( _
name:="Default", _
url:="{controller}/{action}/{id}", _
defaults:=New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional} _
)
End Sub
End Class
Once this is set up, add a controller called CustomController to the project that simply passes through to a view determined by the customization
parameter:
Public Class CustomController
Inherits System.Web.Mvc.Controller
'
' GET: /Custom
Function Index(customization As String) As ActionResult
Return View(customization)
End Function
End Class
Publish this code and add a Custom
directory under the Views
directory in the deployed location. Now you can put any .vbhtml
file in the Custom
folder and refer to it with a URL like http://localhost/MyApplication/Custom/MyView
, which will load MyView.vbhtml
from the Views\Custom
directory.

- 25,079
- 9
- 80
- 146
-
The only thing this solution does is allow you to pass the name of a View to a pre-defined controller action and force it to return that view. You're lacking the ability for users to customize the behavior of a controller action and also the model that gets passed to the view. If ALL you want is custom views why not implement a VirtualPathProvider, store the customized views in the database and there would be no need for this "Custom" controller? – Nick Bork Jan 08 '14 at 21:56
-
It also allows me to add code into the Index function to call out to custom code based on which customization is being executed. That effectively allows me to define custom controllers too, once I figure out what a controller needs to do besides select a view (which may be nothing). In this way I can funnel all customizations through one place, but allow an arbitrary number of arbitrarily named customizations. This custom controller seems simpler than implementing a VirtualPathProvider, and also provides a means to call out to custom controller code based on which customization is executing. – BlueMonkMN Jan 08 '14 at 22:41
If the main intent is to provide extensibility, then there is a simpler answer. ASP.Net will probe all assemblies in the bin
directory of the deployed web application and pick up all controllers and models in compiled assemblies there, as well as all un-compiled views in the Views directory. With some effort I was able to determine a minimal set of files necessary to create an independent template project that could be used by people who would develop and deploy custom code into the running (deployed) web application. The details are provided as an answer to a more relevant question I discovered on this topic because it was not straightforward to get Intellisense and other ASP.Net MVC4 apsects of this template project working. See https://stackoverflow.com/a/21122377/78162
Since Visual Studio Express is now available for free, my hope is that such a template project could be loaded as a starting point for developing customizations to another ASP.Net MVC4 application. My limited testing indicates this will work for both the UI layer (as demonstrated in previous link) and the API layers (as discussed at https://stackoverflow.com/a/21028825/78162).

- 1
- 1

- 25,079
- 9
- 80
- 146