Bug Fixes and Changes in ASP.NET MVC 3 Beta
Update: This article is outdated. Please read this post for the latest new features.
Introduction:
Few days ago when ASP.NET MVC team released ASP.NET MVC 3 Beta. This beta release includes some new features, some changes, some improvements and bug fixes. For detail of this beta release see Announcing NuPack, ASP.NET MVC 3 Beta, and WebMatrix Beta 2. In this article, I will show you the most important changes and bug fixes. Seeing and knowing new changes will help you when you start using MVC 3 Beta from MVC 3 Preview 1 or MVC 2 because some properties and some classes are renamed in MVC 3 Beta. On the other hand, seeing and knowing bug fixes shows that how quickly ASP.NET MVC team fixes the bugs discussed in forums, which is appreciable.
Description:
So let's see the latest changes and bug fixes in this release,
LayoutPage Property is Renamed:
In MVC 3 Preview 1 you can set the layout page using LayoutPage property of Razor views,
@{ LayoutPage = "~/Views/Shared/_Layout.cshtml"; }
This property is renamed in MVC 3 Beta 1 to Layout,
@{ Layout = "~/Views/Shared/_Layout.cshtml"; }
Razor View Engine Classes are Renamed:
In MVC 3 Preview 1, razor view and razor viewengine were named as CshtmlView and CshtmlViewEngine. In MVC 3 Beta, they are renamed to RazorView and RazorViewEngine. I think this makes much sense to rename Cshtml to Razor because it will clear the confusion.
Razor Views Namespaces are now Configurable:
In MVC 3 Preview 1, if you use a razor view then you can register global namespaces using CodeGeneratorSettings.AddGlobalImport method in Global.asax.cs,
CodeGeneratorSettings.AddGlobalImport("Namespace");
This class is removed in ASP.NET MVC 3 Beta because you can now register global namespaces via web.config. Just open the web.config inside Views folder of ASP.NET MVC 3 beta project, you will find the following configuration,
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> </namespaces> </pages> </system.web.webPages.razor>
Request Validation becomes More Granular:
ASP.NET helps in preventing Cross Site Scripting (XSS) (which is the most dangerous attack) via Request Validation. In previous versions of ASP.NET MVC, you can control request validation using ValidateInputAttriubte or globally control request validation by using a technique discussed in my past article. In the previous MVC versions, all the posted forms, headers, cookies and query string values are validated. In ASP.NET MVC 3 Beta, you can exclude some properties from request validation by introducing a new property Exclude on ValidateInputAttribute. For more details see this article. It is worth here to see how ASP.NET MVC team make granular request validation possible. So let's see.
Default request validator will throw an exception when he see < followed by an exclamation(like <!) or < followed by the letters a through z(like <s) or & followed by a pound sign(like {) as a part of querystring, posted form, headers and cookie collection. It is very interesting to note that a particular key value is only validated once when this key value is read first time. For example, just run an ASP.NET MVC 2 application and append this query string, /?A=<s, you will get a dangerous input exception. Now just update your action as,
public ActionResult Index() { try { string s=Request.QueryString["A"]; } catch { } return View(); }
Again run your application with the same query string, you will get no exception. This shows that request validation for a particular key value only occur when this key value is read first time. Now let's see an interesting difference between MVC 2 and MVC 3 Beta. Create and add the following action in both ASP.NET MVC 2 project and ASP.NET MVC 3 project and run both application, then append the above query string in both applications URL. Make sure you don't set requestValidationMode to 2.0,
[ValidateInput(false)] public ActionResult Index() { return View(); }
In this case you will only get exception in MVC 2 and you will not get any exception in MVC 3. It shows that in ASP.NET MVC 3 Beta someone had already read this query string first time, but who? The answer is GranularValidationModule HTTP Module. You may wonder that GranularValidationModule is not registered in your project's web.config and it is not present in your project. The answer is that GranularValidationModule is present in System.Web.WebPages assembly and it is registered using a new ASP.NET 4 feature, PreApplicationStartMethodAttribute, using the same technique discussed by Nikhil at here.
One thing that may comes into your mind is that what will happen if you have a web form in your MVC 3 Beta project. The ASP.NET MVC team has been aware of this issue, that's why they add a new array list ValidatingArrayList(which is inherited from ArrayList) in System.Web.WebPages assembly. This array list is responsible for calling request validation again. GranularValidationModule is responsible for setting Request.Form, Request.QueryString etc, internal property to ValidatingArrayList instead of ArrayList. For proving this, just add a web form in ASP.NET MVC 3 Beta project, then run this page with the above appended query string and see the exception stack trace.
If you have classic ASP or PHP pages in MVC Beta 3 project then Granular request validation will affect them ,as discussed at here and here . A quick work around (provided by Levi(ASP.NET MVC team member)) is to call InsertEntityBody method of HttpRequest in BeginRequest event. Here is the sample, which will add and register HTTP module,
public class ReinsertionModule : IHttpModule { public void Dispose() { // no-op } public void Init(HttpApplication context) { // hands Request.Form back to IIS for duplication context.BeginRequest += (sender, e) => { ((HttpApplication)sender).Request.InsertEntityBody(); }; } }
<system.webServer> <modules> <add name="ReinsertionModule" type="ReinsertionModule" /> </modules> </system.webServer>
Enhanced Dependency Injection Support:
In ASP.MVC 3 Beta, new services for dependency resolution has been added. For details see Brad(ASP.NET MVC team member) Dependency Injection Series here.
Unobtrusive Ajax and Unobtrusive Client Side Validation is Supported:
In my previous article, I talked about how you can move your client side script at bottom in here. In ASP.MVC 3 Beta, there is no need for doing this because now it separate the javascript behavior from the HTML by emitting HTML5 attributes. For details see Brad's this and this article.
Razor Improvements, Code Run Before, VBHTML Support, New Helpers:
In MVC 3 Beta, Razor syntax is enhanced, new helper methods has been added and vbhtml is supported. Also now you can execute some code before your views execute. For details see these release notes.
Views with Application Relative Path Problem is Fixed:
If you have the following action in MVC 3 preview 1 then it will throws an exception,
public ActionResult Index() { return View("~/Views/Home/Index.cshtml"); }
I explained this bug at here, This bug has been fixed in MVC 3 Beta but not 100% fixed. The following code still throws an exception in MVC 3 Beta. For details see this thread.
public ActionResult Index() { return View("Index", "~/Views/Shared/_Layout.cshtml"); }
Supports Client Side Validation for Overridden Properties :
In previous MVC versions, client side validation will not trigger for overridden model properties. For example, if you the following Model then client side validation will not trigger in old MVC versions but it will work in MVC 3 Beta. I explained the cause of this bug at here.
public class Human { public virtual int Age { get; set; } } public class Men : Human { [Range(10,20,ErrorMessage = "Age is between 10 to 20.")] public override int Age { get; set; } }
Support for DisplayAttribute :
In MVC 2 (and MVC 1), DisplayAttribute is not work because in .NET 3.5 there is no DisplayAttribute and MVC 2 is compiled with .NET 3.5. In MVC 3 preview 1, DisplayAttribute will be honored with the exception of template helpers. Now in MVC 3 Beta, EditorFor and DisplayFor helpers supports the ordering which is specified in the DisplayAttribute.Order property.
DisplayNameAttribute bug is Fixed:
In MVC 3 preview 1, usage of DisplayNameAttribute was broken. This has been fixed in MVC 3 Beta 1.
Page Directive bug is Fixed:
In MVC 3 preview 1, if you use any directive after the Page directive(<%@Page) then your page will break. This was a bug in MVC 3 preview 1 which shows on any page where there are any directives after the page directive. This has been fixed in MVC 3 Beta 1.
Model Property Name bug is Fixed:
In MVC 2 if you have a Model which contains a property named Model and you use it in a HTML helper then it will throws an exception. For example,
public class MyModel { public string Model { get; set; } }
<%=Html.TextAreaFor(m => m.Model)%>
This will throw an exception in MVC 2 while the same sample is work in MVC 3.
Client Side Validation Support for StringLengthAttribute MinimumLength Property:
Client side validation is not supported for StringLengthAttribute MinimumLength property in MVC 2 In MVC 3 client side validation will work for MinimumLength property.
Summary:
In this article I showed you the changes, new features and bug fixes in ASP.NET MVC 3 Beta. This will help a lot when you start using ASP.NET MVC 3 Beta. I also showed you how quickly ASP.NET MVC team fixes the bugs discussed in forums. If you have any questions, suggestions, issues or if you found any bugs when working with this release, please post them to the ASP.NET MVC forum, where ASP.NET community members are frequently able to provide informal support. You can also download the MVC 3 Beta source at here. Hopefully you will enjoy this article too.