How to control error keys using ModelStateWrapper=

263 views Asked by At

I’m using the a service layer with a ModelStateWrapper as shown here.

What’s he proper way to control the error keys to use when validating in the service layer so they correspond to the input names in my views?

e.g. I have the following ViewModel for a customer:

public class CustomerViewModel
{
    public string Name { get; set; }
    /*…*/
}

And the following ViewModel for some use case’s View (the user can create two customers on the fly in this use case by entering their names):

public class SomeOtherUseCaseViewModel
{
    public CustomerViewModel BuyingCustomer { get; set; }
    public CustomerViewModel SellingCustomer { get; set; }
    /*… */
}

Which I use in the View like this:

<!-- … -->
<%: Html.EditorFor(model => model.BuyingCustomer.Name) %>
<%: Html.ValidationMessageFor(model => model.BuyingCustomer.Name) %>
<!-- … -->
<%: Html.EditorFor(model => model.SellingCustomer.Name) %>
<%: Html.ValidationMessageFor(model => model.SellingCustomer.Name) %>

In my customer service I’ve the following validation method which gets called when creating the customer (note that this is a different Customer class, this is a domain class):

public bool ValidateCustomer(Customer customer)
{
    /* Check if there is another customer with the same name */
    if (/*…*/)
    {
        _validationDictionary.addError(“Name”, “There is another customer with the same name”); //the _validationDictionary holds the ModelStateWrapper
        return false;
    }
}

Do you see my problem?

Depending on the View, the error should be added with the key “BuyingCustomer.Name” or “SellingCustomer.Name” (or eventually there will be two errors, one with each key) instead of just “Name”; otherwise the framework won’t properly highlight the fields and show the errors.

What is the proper way to solve this situation neatly? I don't want to pass the "error key prefix" to the service layer, because that's a UI concern and not a service layer concern, (right?).

1

There are 1 answers

0
Chad Ruppert On BEST ANSWER

I'd take it later you query the service for any validation errors?

Either query service immediately after validation then reset the errors, or have the method call the return validation errors. If you do either of those you can prefix them with( prefix(this validationDictionaryObject, string pfx) ) an extension method for the dictionary, the api wouldn't be too bad that way. A second extension method (HasErrors()) for the dictionary would do the same as your boolean return

For the problem you are having alone, i tend to eschew querying the service for errors.

It's convenient to have the service collect them all, but then you are adding error state to a service that doesn't really belong, its not that the service is broken, but one model it checked was. If you need to call that service again (like you are doing) it has old state. You have to manage that. Either that or return errors because after all, its a validation method. Have it return validation results. :)

var errs = service.ValidateCustomer(sellinCustomer);
if (errs.HasErrors()){
   errs.Prefix("SellingCustomer");
   //add to model state dictionary for view here.
}