Prologue: I've read many questions about fixing 'A potentially dangerous request' errors:
- A potentially dangerous Request.Form value was detected from the client
- ASP.NET MVC A potentially dangerous Request.Form value was detected from the client when using a custom modelbinder
- Handle "potentially dangerous Request.Form value..."
Among many others. I know how to fix it several different ways, however I do not want to turn off request validation.
I would like to add form validations to all string view model properties site-wide to guard against the "A potentially dangerous request" exception, since throwing an exception is not ideal if a user can correct their input. I've only been able to think of two different solutions:
- Add a regular expression validator to each view model property that accepts a - stringdatatype, which is executed on the browser. This will prevent form submissions, but is a lot of work coding wise for our application
- Somehow magically add a validator that is executed on each request that is triggered on all string view model properties that does this validation and gives the user a friendlier message than the Yellow Screen of Doom (tm). 
The validation message that should show up by the form field, regardless of solution, should be something like:
The X field contains potentially dangerous characters. Either remove all '<' characters, or ensure a space or punctuation mark occurs before them.
Or something to that affect. Basically, I want a validation message that helps the user resolve the situation instead of blowing the whole application sky-high, which causes them to lose all of their work inputting data into a form.
I did come up with a solution, that involves adding a custom model binder for string properties that gets the value of the property without triggering the validations, and then testing it with a regular expression. A match on the regex then causes a new model state error to be added to that property.
public class MaliciousStringInputModelBinder : IModelBinder
{
    private static readonly Regex maliciousStringPattern = new Regex(@"<[a-zA-Z0-9]");
    private const string validationMessageFormat = "The {0} field contains potentially dangerous characters. Either remove the '<' characters, or ensure a space or puncuation character immediately follows them.";
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // Call extension method to safely get model value without
        // triggering any validations
        var valueResult = controllerContext.GetValueFromProvider(bindingContext);
        if (valueResult == null || valueResult.AttemptedValue == null)
        {
            return null;
        }
        else if (valueResult.AttemptedValue == string.Empty)
        {
            return string.Empty;
        }
        else if (maliciousStringPattern.IsMatch(valueResult.AttemptedValue))
        {
            bindingContext.ModelState.AddModelError(bindingContext.ModelName, string.Format(validationMessageFormat, bindingContext.ModelMetadata.DisplayName));
        }
        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueResult);
        return valueResult.AttemptedValue;
    }
}
This works, but feels like a hack. I'm not binding the model property, I'm validating it.
I've been looking into ASP.NET MVC action filters, but again I'm jumping through lots of hoops without a clear solution.
How can I add a universal form validation to all string view model properties site-wide in ASP.NET MVC to show a validation message to users instead of throwing an exception?
