简体   繁体   中英

MVC 3 RTM allowHtml doesn't work when using FormCollection

MVC 3 RTM. Have a model that has an attribute with AllowHtml. In my controller action, if the action has FormCollection as parameter, it throws the exception:

 [HttpPost]
 public ActionResult Edit(FormCollection collection, int id)
 {
   var myEntity = _myRepo.Get(id);

   TryUpdateModel(myEntity);

   return DoSave(myEntity);
 }

A potentially dangerous Request.Form value was detected from the client

However if my controller action uses an object instead of FormCollection it doesn't throw the exception.

 [HttpPost]
 public ActionResult Edit(MyEntity postedEntity, int id)
 {
   var myEntity = _myRepo.Get(id);

   TryUpdateModel(myEntity);

   return DoSave(myEntity);
 }

I've already setup

httpRuntime requestValidationMode="2.0"

Why does it fail when using FormCollection?

You can't use AllowHtml with FormCollection . You could use the [ValidateInput] attribute but obviously this disabled validation for all values:

[HttpPost]
[ValidateInput(false)]
public ActionResult Edit(FormCollection collection, int id)
{
    var myEntity = _myRepo.Get(id);
    TryUpdateModel(objective);
    return DoSave(objective);
}

This being said I would use the following:

[HttpPost]
public ActionResult Edit(MyEntity entity)
{
    if (ModelState.IsValid)
    {
        _myRepo.Save(entity);
        return RedirectToAction("Success");
    }
    return View(entity);
}

For security-reasons, simply disabling validation is not a good solution, as you're inadvertently disabling security for that action-method entirely.

When you need just one GET or POST value, this is extremely annoying - for example, Request.Params["xyz"] will throw if there's an HTML-value anywhere in your GET/POST data, even if the "xyz" value you posted does not contain HTML.

(This is true as of the latest MVC 3.1 release.)

To get around this issue, I extended my Controller base-class with the following method:

    /// <summary>
    /// Gets a value from the current Controller's ValueProvider, bypassing post-data validation.
    /// </summary>
    public string GetUnvalidatedValue(string key)
    {
        ValueProviderResult result;

        if (ValueProvider is IUnvalidatedValueProvider)
        {
            result = ((IUnvalidatedValueProvider)ValueProvider)
                .GetValue(key, skipValidation: true);
        }
        else
        {
            result = ValueProvider.GetValue(key);
        }

        return result == null ? null : result.AttemptedValue;
    }

This effectively allows you to get an individual GET/POST value while bypassing the validation.

I believe this is better, safer and more correct than turning off validation altogether - your application does benefit from the added security, even if the way it's implemented gets in the way, and apparently is pretty painful to get around.

(I don't think this is by design, or at least not by very good design...)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM