I have a custom IValueProvider that I wrote to handle json values. It is registered in the globa.asax via
ValueProviderFactories.Factories.Insert(0, new JsonValueProviderFactory());
It works fine, but I just recently needed to post a model back that contains HTML. By default this spawns the old
A potentially dangerous Request.Form value was detected from the client
Error message. It looks like the way to get around that normally is to decorate the model property with an AllowHtml attribute. The problem is my value provider is still throwing the error. Any idea how to get my value provider to respect the AllowHtml attribute?
Here is the relevant code:
public class JsonValueProvider : IValueProvider, IValueDeserializer
{
private ControllerContext context;
public JsonValueProvider(ControllerContext controllerContext)
{
this.context = controllerContext;
}
public bool ContainsPrefix(string prefix)
{
return context.HttpContext.Request.Form.AllKeys.FirstOrDefault(i => i.StartsWith(prefix)) != null; //<!------- The error is thrown here
}
.....
You cannot use validated request data (e.g. Request.Form
, Request.QueryString
) within your custom value provider if you need to handle "potentially dangerous" data.
Instead you should use methods or properties such as Request.Unvalidated
, HttpContext.Request.Unvalidated()
or HttpContext.Request.InputStream
.
If you implement IUnvalidatedValueProvider
on your custom ValueProvider
, then it can also work nicely with DefaultModelBinder
/ AllowHtml
.
IUnvalidatedValueProvider
has an overloaded GetValue
method to tell the provider whether to skip validation (which is what ultimately gets set by AllowHtml
).
public interface IUnvalidatedValueProvider : IValueProvider
{
ValueProviderResult GetValue(string key, bool skipValidation);
}
In your implementation, if skipValidation
is true, then you should retrieve unvalidated request data. Obviously within your ContainsPrefix
you cannot access validated data (e.g. Request.Form
).
Having said that it may be easiest to inherit from NameValueCollectionValueProvider
which is already "unvalidated" aware. Most of the built in value providers inherhit from it. I have linked to the MVC source code...take a look at how the sub-types are implemented.
Allow html works only for model binder IIRC. You can obtain unvalidated form and query strings using ValidationUtility
from Microsoft.Web.Infrastructure.DynamicValidationHelper
but keep in mind that all values won't be validated, not only those with AllowHtml!
Func<NameValueCollection> formGetter;
Func<NameValueCollection> queryStringGetter;
ValidationUtility.GetUnvalidatedCollections(HttpContext.Current, out formGetter, out queryStringGetter);
var form = formGetter();
var queryString = queryStringGetter();