2

I have a situation in my MVC webapp where I'm using an implementation of an interface as my ViewModel. While rendering, the view uses the DataAnnotations of the interface instead of the concrete class. My viewModels:

 public interface IAnimalViewModel
{
    [Display(Name = "InterfaceVolume")]
    int Volume { get; set; }
    int NumberOfToes { get; }
}
public class DogViewModel : IAnimalViewModel
{
    [Display(Name = "BarkVolume")]
    public int Volume { get; set; }

    public int NumberOfToes
    {
        get { return 16; }
    }
}
public class CatViewModel : IAnimalViewModel
{
    [Display(Name = "MeowVolume")]
    public int Volume { get; set; }

    public int NumberOfToes
    {
        get { return 18; }
    }
}

Relevant part of my view:

@model IAnimalViewModel
<label asp-for="Volume"></label>
@Model.NumberOfToes

Result:

InterfaceVolume 16

I would expect the rendered label to be "BarkVolume" when I pass a DogViewModelto my View, but it renders "Volume", because the DataAnnotations of IAnimalViewModel are used instead. NumberOfToes show 16, as expected from a DogViewModel object.

Is there a way to have the view use the class's DataAnnotations instead, or is my way of thinking about viewModels fundamentally flawed?

  • Your way of thinking about viewmodels isn't flawed, it's just that as the model is an `IAnimalViewModel` that's where the framework will look for annotations. You'll need to cast it to the concrete class if you want the concrete annotations, which isn't as clean :( – Zhaph - Ben Duguid Oct 03 '18 at 18:55
  • Second link [from Google](https://www.google.com/search?q=asp.net+mvc+dataannotations+interface+concrete+class) (with your question being the first) recommends [converting the interface to an abstract class](http://bradwilson.typepad.com/blog/2011/08/interface-attributes-class-attributes.html). – GSerg Oct 03 '18 at 20:28
  • Short answer is you cannot - your view has `@model IAnimalViewModel` therefore it will use the metadata of `IAnimalViewModel` –  Oct 04 '18 at 00:03

1 Answers1

0

not sure why you are using an interface in the View instead of this

@model IAnimalViewModel
<label asp-for="Volume"></label>

try this in the View using DogViewModel

@Html.LabelFor(model => model.Volume)`

now if your model is IAnimalViewModel u might need

@Html.LabelFor(model => (DogViewModel)model.Volume) 

// this trying to cast IAnimalViewModel to DogViewModel

China Syndrome
  • 953
  • 12
  • 24
  • Thanks for answering! I'm using the interface because I'm trying to get away with using only one View. While the typecast works, I cannot always be sure that the Model in question is a DogViewModel so it's out of the question. – Jason Bright Oct 03 '18 at 19:29
  • then @Html.LabelFor(model => model.Volume)` should work – China Syndrome Oct 03 '18 at 19:45
  • I'm pretty sure the `model => (DogViewModel)model.Volume` will break the model generation similarly to https://stackoverflow.com/q/25333332/11683. – GSerg Oct 03 '18 at 20:29