ASP.NET MVC 3 RC Bug and Quick Solution
Update: This issue has been fixed.
Introduction:
ASP.NET MVC 3 RC includes a cool feature called Granular Request Validation which allows you to make request validation granular by introducing a new attribute SkipRequestValidationAttribute. All your model properties with this attribute are not validated during request validation. For further details of this new feature please see Granular Request Validation in ASP.NET MVC 3. However there is a bug in this new feature that when you bind FormCollection or use Request.Form, Request.QueryString (and so on) which contains HTML input then it throws a dangerous input exception even you use ValidateInput(false). So in this quick article, I will show you the work around of this bug. But I am sure that in RTM release this bug will be fixed.
Description:
The quick work around of this bug(provided by Levi genius) is to remove FormCollection parameter from the action method and instead use Request.Unvalidated().Form inside your action method body. Unvalidated is an extension method present in System.Web.Helpers namespace. See this thread for details. This may be easy for you to change up to 5 methods manually but if you have hundred of action methods then it may be difficult to change all action methods manually. That's why I created a regular expression which automatically do this.
First of all you need to add a reference of System.Web.Helpers namespace which contains the Unvalidated extension method. So open Find and Replace window. Select Look In: "Entire Solution" or "Current Project" and checked the Use: "Regular expressions". Then type using System.Web.Mvc;[ ]*{\n} in the Find what box and type using System.Web.Mvc;\1using System.Web.Helpers;\1 in the Replace with box.
Now you need to remove the FormCollection parameter and add this line inside your method body,
FormCollection form = new FormCollection(Request.Unvalidated().Form);
Again open Find and Replace window. Select Look In: "Entire Solution" or "Current Project" and checked the Use: "Regular expressions". Then type ({[(]}:Wh*FormCollection:Wh*{[^,)]*}:Wh*[,]*)|([,]:Wh*FormCollection:Wh*{[^,)]*}){}{([^{]|\n)*[{]}[ ]*{\n} in the Find what box and type \1\5\6\t\t\tFormCollection \2\3 = new FormCollection(Request.Unvalidated().Form);\6 in Replace with box.
If you have the following actions in your project,
public ActionResult ActionA(FormCollection form1) { return View(); } public ActionResult ActionB(int i,FormCollection form) { return View(); } public ActionResult ActionC(int i, FormCollection formABC, string j, [Bind(Include = "Name,Address")] Student s) { return View(); } public ActionResult ActionD(int i, string j,FormCollection f , string k, string t) { return View(); } public ActionResult ActionE(FormCollection form123, string t, string t2) { return View(new Student { Age = 30, Name = "Akbar" }); }
Then using the above method, it will be converted to the following actions,
public ActionResult ActionA() { FormCollection form1 = new FormCollection(Request.Unvalidated().Form); return View(); } public ActionResult ActionB(int i) { FormCollection form = new FormCollection(Request.Unvalidated().Form); return View(); } public ActionResult ActionC(int i, string j, [Bind(Include = "Name,Address")] Student s) { FormCollection formABC = new FormCollection(Request.Unvalidated().Form); return View(); } public ActionResult ActionD(int i, string j, string k, string t) { FormCollection f = new FormCollection(Request.Unvalidated().Form); return View(); } public ActionResult ActionE( string t, string t2) { FormCollection form123 = new FormCollection(Request.Unvalidated().Form); return View(new Student { Age = 30, Name = "Akbar" }); }
Finally if you are using Request.Form, Request.QueryString, Request.Cookies or Request.Headers then just replace them with Request.Unvalidated().Form, Request.Unvalidated().QueryString, Request.Unvalidated().Cookies, and Request.Unvalidated().Headers.
Update: If you have any problem using method overloading after using the above regex then instead Replace,
({[(]}:Wh*FormCollection:Wh*{[^,)]*}:Wh*[,]*)|({[,]}:Wh*FormCollection:Wh*{[^,)]*}):Wh*{[,)]}{([^{]|\n)*[{]}[ ]*{\n}
With
\1\3string unused\5\6\7\t\t\tFormCollection \2\4 = new FormCollection(Request.Unvalidated().Form);\7
Summary:
In this article I showed you a bug in MVC 3 RC and showed you how you can work around this bug quickly in your application using Regular Expression feature of Visual Studio. Hopefully you will enjoy this article too.