开发者

Can I add a ModelState.AddModelError from a Model class (rather than the controller)?

I want to display an error to the user in an ASP.MVC 3 input form using ModelState.AddModelError() so that it automatically highlights the right field and puts the error next to the particular field.

In most examples, I see ModelState.AddModelError() and if(ModelState.IsValid) placed right in the Controller. However, I would like to move/centralize that validation logic to the model class. Can I have the model class check for model errors and populate ModelState.AddModelError()?

Current Code:

// Controller
[HttpPost]
public ActionResult Foo(Bar bar)
{  
    // This model check is run here inside the controller.
    if (bar.isOutsideServiceArea())
        ModelState.AddModelError("Address", "Unfortunately, we cannot serve your address.");

    // This is another model check run here inside the controller.
    if (bar.isDuplicate())
        ModelState.AddModelError("OrderNumber", "This appears to be a duplicate order");

    if (ModelState.IsValid)
    {
        bar.Save();
        return RedirectToAction("Index");
    }
    else
        return View(bar)
}

Desired Code:

// Controller
[HttpPost]
public ActionResult Foo(Bar bar)
{  
    // something here to invoke all tests on bar within the model class

    if (ModelState.IsValid)
    {
        bar.Save();
        return RedirectToAction("Index");
    }
    else
        return View(bar)
}


...
// Inside the relevant Model class
if (bar.isOutsideServiceArea())
    ModelState.Add开发者_开发技巧ModelError("Address", "Unfortunately, we cannot serve your address.");

if (bar.isDuplicate())
    ModelState.AddModelError("OrderNumber", "This appears to be a duplicate order");


If you are using MVC 3, you should checkout IValidatableObject, it's what you're after.

Scott Gu mentions it in his MVC3 Intro blog posting.


You can do something like this using custom data annotations or using RuleViolations like what they did in the NerdDinner example.


Perhaps you could create an error interface like IErrorHandler and pass that into a public method called Validate on you model class assuming its a partial class and you can seperate your data model from your rules.

With the interface you could create a class in your contoller that wraps the ModelState error handler. So the inteface might have AddError and in that metghod tou just delegate to your local modelstate.

So your method might be something like:

IErrorHandler errorHandler = CreateErrorHandler();
model.Validate(errorHandler);

if(errorHandler.IsValid())
... do something


You would use custom validation via the IValidatableObject interface on your model.

Custom validation example


If you're after least amount of code, a hacky way of doing it is to stuff that message into the Session from your View Model, then add that message from your Controller, for example:

// In Model (or elsewhere deep inside your app):
string propertyName = "Email";
string errorMessage = "This is the error message, you should fix it";

Session["DeepModelError"] = new KeyValuePair<string, string>(propertyName, errorMessage);

// In Controller
var model = new LoginModel();
if (Session["DeepModelError"] != null)
{
    var deepError = (KeyValuePair<string, string>)Session["DeepModelError"];
    if (deepError.Key == "Email" || deepError.Key == "Password")
    {
        ModelState.AddModelError(deepError.Key, deepError.Value);

        Session["DeepModelError"] = null;
    }
}

Let me reiterate that I realize that this is kind of hacky, but it's simple and it gets the job done...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜