I think you are attacking it from the wrong angle by trying to encode all posted data.
Note that a "<
" could also come from other outside sources, like a database field, a configuration, a file, a feed and so on.
Furthermore, "<
" is not inherently dangerous. It's only dangerous in a specific context: when writing strings that haven't been encoded to HTML output (because of XSS).
In other contexts different sub-strings are dangerous, for example, if you write an user-provided URL into a link, the sub-string "javascript:
" may be dangerous. The single quote character on the other hand is dangerous when interpolating strings in SQL queries, but perfectly safe if it is a part of a name submitted from a form or read from a database field.
The bottom line is: you can't filter random input for dangerous characters, because any character may be dangerous under the right circumstances. You should encode at the point where some specific characters may become dangerous because they cross into a different sub-language where they have special meaning. When you write a string to HTML, you should encode characters that have special meaning in HTML, using Server.HtmlEncode. If you pass a string to a dynamic SQL statement, you should encode different characters (or better, let the framework do it for you by using prepared statements or the like)..
When you are sure you HTML-encode everywhere you pass strings to HTML, then set ValidateRequest="false"
in the <%@ Page ... %>
directive in your .aspx
file(s).
In .NET 4 you may need to do a little more. Sometimes it's necessary to also add <httpRuntime requestValidationMode="2.0" />
to web.config (reference).
There appears to be a bug in the sharp architecture SetEntityCollectionProperty method. Its in the last four lines:
foreach (object entity in (value as IEnumerable)) {
entityCollectionType.InvokeMember("Add",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, entityCollection,
new object[] { entity });
}
Its intent seems to be to populate the model collection class (entityCollection) from the values in the IEnumerable passed in as value. However, these two objects are the same reference. It's already populated. When the "Add" method is invoked, the entityCollection is modified which is the same object that is being iterated. Then the exception is thrown.
Comment or delete that code block and your code should run.
Best Answer
You have a few options.
On the model add this attribute to each property that you need to allow HTML - best choice
On the controller action add this attribute to allow all HTML
Brute force in web.config - definitely not recommended
In the web.config file, within the tags, insert the httpRuntime element with the attribute requestValidationMode="2.0". Also add the validateRequest="false" attribute in the pages element.
More info: http://davidhayden.com/blog/dave/archive/2011/01/16/AllowHtmlAttributeASPNETMVC3.aspx
The above works for usages of the default modelbinder.
Custom ModelBinder
It appears that a call to bindingContext.ValueProvider.GetValue() in the code above always validates the data, regardless any attributes. Digging into the ASP.NET MVC sources reveals that the DefaultModelBinder first checks if request validation is required and then calls the bindingContext.UnvalidatedValueProvider.GetValue() method with a parameter that indicates if validation is required or not.
Unfortunately we can’t use any of the framework code because it’s sealed, private or whatever to protect ignorant devs from doing dangerous stuff, but it’s not too difficult to create a working custom model binder that respects the AllowHtml and ValidateInput attributes:
The other required piece is a way to retrieve an unvalidated value. In this example we use an extension method for the ModelBindingContext class:
More info on this at http://blogs.taiga.nl/martijn/2011/09/29/custom-model-binders-and-request-validation/