1

I’m tracing down an unexpected behavior in MVC3, having to do with how it gets model metadata.

I had previously talked to one of my developers about using the same EditorTemplate for some data which is collected in two different areas of the system. The data fields are almost identical, except for the [Required] attribute. In one page certain fields are required, in the other page they are not. Theoretically this can be accomplished by using a base model which has the common attributes on each field, and inheriting those models, overriding the properties and adding additional validation attributes. For example:

class BaseModel
{
    [Display(Name=”My Label”)]
    public virtual string MyLabel { get; set ;}
}

class RequiredModel : BaseModel
{
    [Required]
    public override string MyLabel { get; set ;}
}

Then the View can be strongly typed to BaseModel, and calls to @Html.EditorFor(m=>m.MyLabel) in the view should pick up the correct attributes, depending on whether the actual instance of the model is a BaseModel or RequiredModel.

That’s the theory.

And in fact, it works well if you use the “old” HTML helper, e.g. @Html.TextBox(“MyLabel”). Those call ModelMetadata.FromStringExpression(field), which correctly gets the metadata from RequiredModel if the concrete model instance is RequiredModel. The newer helper methods call ModelMetadata.FromLambdaExpression(expression), which does NOT correctly get the metadata from the correct concrete instance.

Is this a bug in MVC? Intentional behavior? Is there a workaround, or a better way to address this problem?

This is of course a trivial example, the actual code we're dealing with has about 20 fields with some complex business rules and interaction, which is the same on both pages EXCEPT for which fields are required.

Mark Shapiro
  • 1,192
  • 10
  • 13

1 Answers1

0

That's the theory.

No, that's not the theory. At least not mine.

My theory is to use separate view models for each views because the requirements of your views are different. So you would have this:

public class UpdateViewModel
{
    [Display(Name = "My Label")]
    public string MyLabel { get; set ;}
}

and:

public class CreateViewModel
{
    [Display(Name = "My Label")]
    [Required]
    public string MyLabel { get; set ;}
}

Personally that's what I would do. I would totally sacrify DRY into designing view models because the requirements of my view change often and I want to have total control.

Obviously in practice I don't even bother with doing validation using declarative DataAnnotations attributes. They limit me. I use FluentValidation.NET which addresses problems like yours in a pretty elegant manner (by simply defining two different validators for the same view model - in case you decide to violate my theory and use the same view model in different views).

Now feel free to downvote my answer. I have just given my 2¢.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Darin, keep in mind that Microsoft gave us Editor Templates, which allow you to use a single view in multiple areas of the application. They just haven't consistently applied the validation attributes when the editor template is for a model containing multiple fields. I think the bigger problem is that @Html.Editor("MyLabel") does it one way, while @Html.EditorFor(m=>m.MyLabel) does it the other way. – Mark Shapiro Jul 18 '11 at 19:32
  • 1
    @Mark Shapiro, I am very well aware of what Microsoft gave us. – Darin Dimitrov Jul 18 '11 at 19:34