0

This is an ASP.Net MVC 5 project

I have a simple model whose one of its properties allows a HTML input:

public class FooModel {
    //other properties

    [AllowHtml]
    public string BarField { get; set; }
}

And a controller which uses the model as shown below:

[OutputCache(NoStore = true, Duration = 0, Location = OutputCacheLocation.None)]
public class FooController : Controller {
    //some other codes...

    // GET: Foo/Create
    public ActionResult Create(int? id, int number = 0) {
      //some code
    }

    // POST: Foo/Create
    [HttpPost]
    public ActionResult Create(FooModel fooModel) {
        //some code
    }

    // GET: Foo/Edit/5
    public ActionResult Edit(int? id, int number = 0) {
        //some code
    }

    // POST: Foo/Edit/5
    [HttpPost]
    public ActionResult Edit(FooModel model, FormCollection collection) {
        //some code
    }
}

Upon reading some of the posts in SO:

  1. AllowHtml attribute not working
  2. AllowHtml attribute doesn't work
  3. AllowHtml not working

I know that the following must be done to ensure the AllowHtml attribute to work:

  1. use <httpRuntime requestValidationMode="2.0" /> in the web.config
  2. clear up cache of the controller where the model is passed and used [OutputCache(NoStore = true, Duration = 0, Location = OutputCacheLocation.None)]

Thus, I have the following complete element for my <system.web> in the web.config:

  <system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.6" />
    <httpRuntime targetFramework="4.5" requestValidationMode="2.0" />
    <httpModules>
      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
    </httpModules>
  </system.web>

And, as you can see, I also have put the OutputCache attribute on top of the controller:

[OutputCache(NoStore = true, Duration = 0, Location = OutputCacheLocation.None)]

Now, this works very well for Create Action (that is, I can insert HTML element in the BarField and the post is accepted and the Action is called without problem).

But when I do the Edit Action, the action is not even called and the error:

A potentially dangerous Request.Form value was detected from the client ( BarField="...words here <i>and also here</i><...").

Description: ASP.NET has detected data in the request that is potentially dangerous because it might include HTML markup or script. The data might represent an attempt to compromise the security of your application, such as a cross-site scripting attack. If this type of input is appropriate in your application, you can include code in a web page to explicitly allow it. For more information, see http://go.microsoft.com/fwlink/?LinkID=212874.

is shown on the page. Why is this so?

Community
  • 1
  • 1
Ian
  • 30,182
  • 19
  • 69
  • 107
  • Remove the `FormCollection collection` parameter from the `Edit()` method –  Sep 05 '16 at 12:25
  • @StephenMuecke That's it! It works! thanks, Pal... :D But why does the `FormCollection` hinders the form submission? – Ian Sep 05 '16 at 12:30
  • Because your binding the posted values to your model (and the `[AllowHtml]` handles the request on the `BarField` property), but your also binding to `FormCollection` (a `NameValueCollection`) which does not have the attribute applied to it (and can't have anyway) although you could use `[ValidateInput(false)]` but there is no reason to bind the same values to 2 different models and there should no reason to ever use `FormCollection` in MVC –  Sep 05 '16 at 12:34
  • @StephenMuecke I see... So that's how it works... Thanks again! You have helped me a couple of times by now! I have just put a bounty in one question which you answered to express my gratitude: http://stackoverflow.com/questions/29142422/rendering-partial-view-on-button-click-in-asp-net-mvc – Ian Sep 05 '16 at 12:37
  • Not necessary, but appreciated :). I tried to find a suitable dupe for this but mostly found only unanswered questions or answers without any explanation. If I don't find anything, I'll add an answer later and then use my dupe hammer to close some similar unanswered questions. –  Sep 05 '16 at 23:31

1 Answers1

2

The exception is thrown because you have included an additional parameter FormCollection collection in the Edit() method.

When you apply the [AllowHtml] attribute, its sets the RequestValidationEnabled property of the properties ModelMetadata to false. During the model binding process, the DefaultModelBinder checks this value and because its false, no exception is throw when binding to your model.

However, FormCollection is just a NameValueCollection and is populated by reading the Request.Form values. There is no model and associated metadata, so the exception is thrown. Exactly the same would happen if you were to use

var barField= Request["BarField"];

although using the Unvalidated property of Request will work

var barField = Request.Unvalidated.Form["BarField"];

You could also make it work by applying the [ValidateInput(false)] attribute to the method but that will apply to the whole model and is the least secure way to disable request validation.

Removing the FormCollection collection parameter in the Edit() method will solve the problem, and in any case, there is really no reason to ever use FormCollection in MVC (you should always bind to a model).