by Alex Yumashev ·
Updated Sep 10 2019
Sometimes you need to allow users to post HTML to the server. And, by default, this is the error you're going to get:
A potentially dangerous Request.Form value was detected from the client
The recommended way of solving this is by adding an [AllowHtml] attribute to the model property:
public class BlogPost
{
public int UserId { get; set; }
[AllowHtml]
public string HtmlBody { get; set; }
}
But what do you do if you're not using a model, but need to skip validation for a particular action parameter?
Some people recommended adding [ValidateInput(false)] to the whole action method, but DON'T DO THAT this puts your app at risk disabling validation for all user input, not just one parameter.
In MVC 3 Beta it was posible to do this:
//does not work any more :(
[HttpPost, ValidateInput(true, Exclude = "fieldName")]
public virtual ActionResult Save(int id, string fieldName)
{
//...
}
But this has been removed from the release
//we need to allow html for "htmlBody" only
public ActionResult AddBlogPost(int userId, string htmlBody)
{
//...
}
Meet custom model binding. The beauty of it is that you can apply custom binders at parameter level. Like this:
public ActionResult AddBlogPost(int userId,
[ModelBinder(typeof(AllowHtmlBinder))] string htmlBody)
{
//...
}
And this is the custom binder we're using above:
public class AllowHtmlBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var name = bindingContext.ModelName;
return request.Unvalidated[name]; //magic happens here
}
}
As you can see I'm accessing the request field using Request.Unvalidated property here, which skips the validation. It was introduced in .NET Framework 4.5 for this exact purpose: "Use this method if you anticipate that the request will contain markup".