What is an ASP.Net MVC View Engine? - asp.net-mvc

There are quite a lot of questions on SO regarding View Engines in ASP.Net MVC, and about using "custom" ones instead of the "default" one. For me as a hobby programmer, the term "View Engine" is new, and I have not been able to understand what it means. So, my questions are:
What is a View Engine?
What does the View Engine do, and which role in the MVC pattern does it play? (Closely related to 1...)
What are the main characteristics/properties of the default View Engine that programmers want to change/avoid by switching to a different View Engine?
What are the main benefits of common other View Engines out there that developers are after when they choose to use a different one than standard? (I've seen the name "Spark View Engine" a bunch of times, and I bet there are others too).
When (in what scenarios) would I want to develop my own View Engine?
There, I think that is all I want to ask (for now). Give me View Engines 101! =)

The "view engine" handles the rendering of the view to html, xml or whatever content type it is created to emit. Within "MVC", it would be an aspect of the View (V).
Different view engines have different syntaxes, etc. to manage rendering. The decision to use another view engine is most likely very project/programmer specific. In some cases they may see an actual or perceived limitation of the default view engine; in other cases it may simply be a different design goal or focus.
As far as Spark goes, their focus is to be much more terse than the default view engine and to remain in HTML-like syntax as much as possible instead of dropping into ASP.NET script blocks.
As an end user, the only time you would want to create your own view engine is probably never. ;) It's not a task to be taken lightly, and you'll probably end up re-implementing functionality that already exists in an existing view engine.
Edit
OK. So are the View.aspx files part of
the View Engine, or is the View Engine
a set of classes that help choose
which View.aspx (or other type of
response) that should be rendered? How
does it work?
The MVC pattern tells you that your model, view and controller will be separate "things". In ASP.NET MVC, the default view engine uses the existing ASP.NET framework, which includes master pages, ASPX files, etc. Spark does something similar, but it's a different engine so it doesn't work exactly the same. So in a general sense the view files are not engine-specific, but the specific files, their layout on disk and their contents are view-engine specific.

In addition to wanting to completely replace the view engine (e.g. Spark), you also might make your own view engine just to make a small change to the behavior of the default view engine. You could do this by creating a new view engine that inherits from the default engine and overrides some behavior.
One common example is tweaking where the view engine looks on the hard drive for the .aspx files. For example, you might want to create a view engine that automatically switches which view.aspx file is used based on whether the user is on a mobile device.
See Mobile Web Sites with ASP.NET MVC and the Mobile Browser Definition File for a really good example implementation of this.
Update:
Scott just posted an updated ViewEngine implementation that has important improvements vs the initial implementation linked above.

Related

MVC 3 project structure

I am trying to find the best way to layout my MVC 3 project. When searching online I came across a suggestion that basically said right click on project and add area. What this did was create an area folder with same controller/view/model structure in the same project. This is not what I want. I want the flexibility of having separate projects. I will keep only the views in the main web project. Everything else in a separate project.
Towards that attempt I created a separate project for my controllers. Now I am stuck with pointing a controller action to a view. In all the online examples it was right click and add view. This being a class library project I don't have that flexibility. Where am I going wrong?
All examples that I have found including the ones I have gone through on Asp.net basically explain how to create study applications, which is only good for learning purposes. A large commercial application can't possibly have all the views/models/controllers in one project. Or is that the way it is supposed to go in MVC? I am not sure if doing everything with mouse clicks is also a good idea. In the webforms world also there were a lot of study-for-beginners applications that used mouse clicks to create basic CRUD applications, but in real commercial projects, we never used those methods.
What are your thoughts, guidance on this?
Thanks for your time...
MVC is based on a convention; the convention is you put all the views on /views, the models in /models and the controllers in /controllers. You can change the convention but it will not make your life easier.
From a conceptual point of view this does make sense. If you keep all domain logic and data access in separate projects all you are left with is the web related stuff, your controllers, view models and views. That's your MVC project.
Note that if you want to split off parts into separate projects you may find portable areas useful.
I don't see why you can't use the built in generators as a base for your views and controllers? Nothing says that you have to leave them as generated. I personally thinks that's it's really nice to get a base generated for me (with mouse clicks).
The MVC project is just a UI layer. It's madness to put logic in it for large scale applications. It's therefore usually fine to have one project for all the UI. It actually makes it easier to get an overview of the UI.
That said, there are ways to get a plugin based solution where you can move the controllers (, models and views) to class libraries. But it's not easy.
You need to create a virtual path provider (to find the views)
Make all views embedded
Modify the project file to get the "Add view" dialog etc.
Use areas (makes it easier)
Tell the BuildManager that your plugin DLL exists.
You also need to modify the virtual path provider to access the views from your plugin folders if you want to be able to modify the views during runtime in visual studio. Any change would otherwise require a rebuild of the plugin DLL.
Update
Video for MVC2 (MVC3 areas works the same): http://www.asp.net/mvc/videos/mvc-2/how-do-i/aspnet-mvc-2-areas
Do note that that video is for areas in the same project. Having areas in separate class libraries are more complex. The easiest solution is to use the portable areas as suggested by someone else.
Why keep only your views in the 'main web project' - I think you are missing the point with MVC.
It's the controllers that are your 'main web' part. They are what your users request and post back to, not the view.
The view is only there to provide a means to layout HTML for the controller to push to the browser.
The Models which I think should really be ViewModels, are there to provide substance (i.e. real data) for your views.
So you can see that the MVC layout really wants all three of these to be grouped sensibly together. Controllers interact with your user, get the view (the layout) and populate it with your ViewModel/Model (the data). This is your user interface, all three parts of MVC (if you go with the ViewModel anyway) are only for UI.
Where the data comes from, your real models and whatever you want to do with it can easily reside in a dll somewhere or on the other side of a set of web services or whatever.

With MVC3 can I call / use a view that's in another project?

I didn't see anyone talking about this. What I have is login logic that's common to three projects. I have my model in one project (shared).
Can I have the controller and views in another shared project? I just don't want to have to duplicate things in each.
Also interested in any other ideas people may have to solve this problem.
Robert
Take a look at Precompiled Razor Views
Well, when it comes down to loading views, you can implement your own ViewEngine and instruct it to load your view from wherever you want (database, dll, ...). I just saw a nice video from TechEd NA yesterday, where the creator of the spark view engine shows how to implement it. In your case, you can just fetch the view and feed it into the razor view engine. You should have no problems, since razor was designed to be flexible, and you can easily spawn your own instance of the engine to have it render your loaded view.

Mixing spark and webform view engines

Is it possible to use multiple view engines? I have a large(ish) site that is already using the webforms view engine, but we would like to move to spark for new features.
Is this supported? any documentation online that details how to do this?
I use Spark and default view engine. There is not much to do. You have to register SparkViewFactory by calling ViewEngines.Engines.Add() and Spark will handle *.spark files and default view engine (WebFormViewEngine) will handle old views. Just don't remove webforms engine from ViewEngines.Engines list.
That's what I did; I installed Spark and did couple of views. Eventually I ended up with all views being .spark; no WebForms in the project. I think you can even use partials of one engine from different engine using RenderPartial (though I'm not sure); and of course RenderAction will work with any combination.
The process is very simple as described by LukLed; I just second his answer here so that you have more "success story" cases.
The only problem that you may find is that master pages are not compatible; you'll have to keep them in sync. You can find a question about this here.

Is it possible with ASP.NET MVC to render a view from a template pulled from a database?

What I'm trying to do is generate email content using different templates.
I think ASP.NET MVC could be a good fit for this. My controller would get the necessary data for the email and decide which view (template) to render. (It's more that just a simple mail-merge, there would need to be conditional blocks, foreach's, etc.)
I want to be able to store these templates in a database rather than as files in the web application, so new templates can be easily added from the web application itself.
Is this possible? I would prefer to be able to use the WebForms view engine, but would consider other view engines if that's not possible. I would ideally like to use typed views.
Unfortunately, the WebForms ViewEngine uses some internal classes to compile the aspx and ascx files, so this is not possible. That ViewEngine requires that the Views are available as files in a folder inside the site's root (virtual folder will also work IIRC).
There are other ViewEngines that may fit your purpose better, including some that use XSLT.
AFAIR it is possible to mix several ViewEngines in the same application, so you could use the WebForms engine for your normal web pages, and a different one for your emails.
You can indeed use multiple view engines in the same application. The framework will ask each of the engines whether it is capable of rendering the requested view. Check MvcContrib for other available view engines ...
As stated in the previous answer, the WebForms ViewEngine makes the assumption that the views (aspx, ascx) are stored physically on the file system, just like ASP.NET does (although in ASP.NET you have something like the VirtualPathProvider) that was - I believe - originally added to the framework to support e.g. SharePoint).
If you want to create your own view engine, you should implement IViewEngine, and add the view engine to the ViewEngines collection e.g. in Application_Start.
Phil Haack has a great article on something similar here.
I think it could be adapted to your needs.
Kindness,
Dan
You have to create your viewengine and so your buildmanager. Your viewengine can simply retreive the aspx part from a db and invoke the webform engine. Not easy but doable, it mostly depends on how bad you need this and how will it rewards you with a nice ROI.

What is the best/cleanest way to implement A-B testing in asp.net mvc?

What is the best and cleanest way to implement A-B testing in asp.net mvc? That is, when we make new changes to an asp.net mvc web site, we want to test the new html/css/js with a certain subset of visitors (defined on cookie, login id, etc) and then analyze some metrics (page response time, number of pages visited, $$$ in sales, etc) afterwards to measure the level of success of the changes.
I am looking for a clean way to implement a way of choosing what view (html/css/js, etc...) to render using asp.net mvc.
Check out FairlyCertain (http://www.fairtutor.com/fairlycertain/) when you get a chance. It's a .NET A/B library that you can pretty much just drop into your project and start writing tests.
Unlike the Javascript libraries from Google and VisualWebsiteOptimizer, everything happens on the server so you don't suffer any performance, user experience or SEO issues. I've been using it in my stuff for a while now and it works quite well.
There is an A/B testing framework specifically for ASP.NET MVC. This is an open source software I wrote myself when, just like you, didn't find a free tool which works nicely with ASP.NET MVC and doesn't require much setup.
Google Content Experiments? It's a Javascript-based solution that doesn't require anything from your backend.
You include Google's Javascript on your page
The script randomly substitutes elements on your page as defined by your A/B test
Google's site shows you a nice breakdown of the results...
If you are using the spark view engine, you could probably do it with a variation of the theme filter (http://sparkviewengine.com/documentation/viewlocations#Extendingfilepatternswithdescriptorfilters). For each new visitor to the site, determine if you want them to see the existing or new version of the site and set a cookie. Wire up a descriptor filter that looks for the presence of the cookie and modify the view location to look in the folder containing the modified views. If an alternative view exists, the Spark engine will automatically render it in place of the "normal" view, otherwise it will render the normal view.
If you are using the normal WFVE, then the simplest way to manage this would be to define a folder under Views where your view alternatives live. When you want to provide an alternative view, you place it in a location that matches its position within the normal Views folder but rooted at the alternatives folder e.g. to provide an alternative to Views/Users/login.aspx place your new view at Views/Alternative/Users/login.aspx.
With a convention in place for locating your alternative views, you can extend the WebFormViewEngine and overload CreatePartialView / CreateView to inspect some aspect of the ControllerContext to determine whether to render the default or overloaded view and alter the path as appropriate e.g. changing .../Views/Users/login.aspx to .../Views/Alternative/Users/login.aspx.
I suggest you use Display Modes to achieve A/B testing.
But Display Modes just support simple problems by default.
If you already implement Display Modes in some other scenario. You can consider DisplayModeMatrix (just google it). It helps you use Display Modes more efficiency.
https://www.nuget.org/packages/DisplayModeMatrix/
Wth Display Modes you can simply delete/rename views after A/B testing to clean up your project.
I think there isn't a ready to use solution for this and you will have to improvise.
Try to override your current functionality in well defined points without breaking it. Explicitly draw a border where your regular code and A-B testing code lives.
Inversion of control principle might help a lot here too (i.e. - controller factory could provide derived controller instead of original one). For views&partialviews - you could change viewengine so it would try to look for 'MyPartialViewAB.ascx' instead of 'MyPartialView.ascx'.
And it might be a good idea to take a look what performance counters are (in case you haven't).

Resources