My MVC5 application is being scanned/spammed, and I'm getting 1,000's of exceptions in my logs. How can I resolve this?
Here's my model:
public class MyModel
{
public bool IsRememberMe { get; set; }
}
Here's my view:
@Html.CheckBoxFor(m => m.IsRememberMe)
Here's my action:
[HtmlPost]
public ActionResult MyAction(MyModel model)
{
if (ModelState.IsValid)
{
// Do work
}
return View(model);
}
When a spammer submits manually, a value such as "IsRememberMe=foo" in the POST, ModelState.IsValid==false, as expected and model.IsRememberMe==false as expected. However, when rendering the resulting view, Html.CheckBoxFor(m => m.IsRememberMe) throws an exception:
System.InvalidOperationException: The parameter conversion from type 'System.String' to type 'System.Boolean' failed.
Inside the controller, if I add:
string value = ModelState["IsRememberMe"].Value.AttemptedValue;
then value equals foo (the input value).
Note that under normal conditions, everything is working correctly.
It looks like Html.CheckBoxFor() is pulling the value from ModelState rather than model.IsRememberMe.
What is the best way to resolve this?
Update
Based on the comments and feedback, it looks like the use of data from ModelState is by design. I'm OK with that under normal circumstances.
Some comments have suggested this is a duplicate. While the solution may be similar, I argue that it is not a duplicate since the problem I am trying to solve is different: I am not actively trying to change the submitted value in my controller.
I am trying to prevent an exception in MVC caused by the submission of invalid data. I am posting my own answer below.
PostRedirectPattern, redirect back to the GET action.ModelStateand perform my own model validation to know whether to redirect or not?IsValid == falseif the other fields on the form failed validation. In that case, I don't want to redirect to back to GET. There, I want to returnView(model)along with the model state errors so the user can retry.[ValidateAntiForgeryToken]on the action along with@Html.AntiForgeryToken()in the view. That part is working fine. This is not a forgery case. I can replicate this problem using PostMan or curl.