0

I have a situation where I have a bunch of common properties in a view model but have certain cases where I need to extend it. I created a couple of derrived view models, which I pas into views that expect the derived view Model. (I realize I could use a Polymorphic Binder but I'm happy with just passing in the derived view model for now.

The code looks something like this:

public class CommmonViewModel 
{
     public int? CommonA{ get; set; } 
     public int? CommonB{ get; set; } 
     public int? CommonC{ get; set; } 
}

public class SpecificViewModel1 : CommmonViewModel 
{
     public int? SpecificD{ get; set; }    
}

 public class SpecificViewModel2 : CommmonViewModel 
{
     public int? SpecificE{ get; set; }    
}

The code reviewer wants me to have three distinct view models and duplicate the code like so:

public class SpecificViewModel1 
{
     public int? CommonA{ get; set; } 
     public int? CommonB{ get; set; } 
     public int? CommonC{ get; set; } 

     public int? SpecificD{ get; set; }
}

public class SpecificViewModel2 
{
     public int? CommonA{ get; set; } 
     public int? CommonB{ get; set; } 
     public int? CommonC{ get; set; } 

     public int? SpecificE{ get; set; }
}

Now bearing in mind that the real life view models are quite a bit more complex than what I have shown here; I hate that the solution should be to duplicate the code as it feels like a pretty bad violation of DRY to me.

I know there are generally reasons why we would be careful with inheritance and favor composition but in his case inheritance works fine, especially since this part of the system is likely to change in future.

In short, is he right? is this a case where I should be happy with duplicating code? What are the advantages\disadvantages of inheriting in this scenario?

Thanks for your thoughts

Community
  • 1
  • 1
davy
  • 4,312
  • 9
  • 43
  • 64
  • 2
    Did you ask the code reviewer? This seems pretty opinion based, and there may be some business reasons specific to your situation that may dictate the reason why the VM should be duplicated. – sous2817 Feb 09 '16 at 16:55
  • 2
    Why do you need the override? You can just define the model on the base class and inherit it. You can bind to public properties on a derrived class for properties that were inherited from it's base class without having to override them. – Ryan Mann Feb 09 '16 at 16:57
  • 2
    I'd expect the reviewer to comment on *overriding* `CommonA` with an identical property in the specific models. What's the point? – Panagiotis Kanavos Feb 09 '16 at 16:58
  • The overrides in practice have attributes on them thst make them different. I will edit the question. – davy Feb 09 '16 at 17:36
  • @davy having to override in order to use different attributes is ugly. I'd tell you to use different classes simply for that. The kind of attributes also matters. Are they validation atrributes? The same data structure can have different validation rules based on its usage. – Panagiotis Kanavos Feb 09 '16 at 17:44
  • @Panagiotis - they are only used for additional data like what label to display when using editor for - fluent validation iala used. Again, this is how our framework works and I can't change that. – davy Feb 09 '16 at 17:48
  • Actually, I could undo the overridden property. what about all the other proowrties, which are not virtual? Is it better to just copy and paste a bunch of times? – davy Feb 09 '16 at 17:52

3 Answers3

1

If all of the properties from the underlying base class are used on your forms/derived classes, then in my opinion there is no issue. There could be security issues if you have view model properties which are not used on the form due to underposting/overposting attack.

Consider the following scenario. You have a User class in your domain:

public class User 
{
   public string Username { get; set; }
   public string Username { get; set; }
   public bool IsAdmin { get; set; }
}

Now suppose your login view model simply inherits from your domain model like this:

public class Login : User
{
   // Whatever overrides you have...
}

If the user is in some way aware of your domain model architecture he can add a hidden field on your login page which sets the IsAdmin property to true. This is what's called a overposting attack. This field will map to your model, because you are inheriting from User and possibly map to your domain model and change the user's role in the database.

Obviously this all depends on attacker (disgruntled employee maybe?) being aware of your architecture and your business logic not checking for such a scenario but it is possible under the right circumstances. I'm guessing that your code reviewer is maybe being too careful just in case, but in your case I think what you did is fine.

Marko
  • 11,003
  • 8
  • 43
  • 55
  • thanks, in my case this is not an issue but it is an excellent point. Obviously, I agree with you. It seems quite a divisive issue...;) – davy Feb 09 '16 at 18:05
  • 1
    Worth noting that over-posting attacks such as this can be avoided in MVC by using the Bind[] parameter on a controller action. Create([Bind("SpecificD,CommonA")] SpecificViewModel1 model) – defect833 Oct 10 '17 at 23:08
0

In MVC, you want to avoid creating derived models because it locks your code into using them.

Imagine in the future if the View using the Base Model changes but not in relation to other views. Now all of your other views will have the access properties you added for the change to the base model. Or you could break the base model out, but then you need to update all of your views to use different models.

It's much easier to maintain an MVC site when each model is unique to it's view or partial view (or multiple views/partial views).

Secondly, there are ORM's and Micro Orm's that generate those Models for you from the database, it doesn't look like you are using one.

Even if you don't want to use EntityFramework 6, you can use a Micro ORM like Peta Poco which has T4 templates that can automatically generate all of your Poco's (Models).

As my sql database has tables that all have 3 common Sql Columns (Active, Created, Updated), all of my models have Properties for "Active, Created, and Updated" because I didn't write my models, Peta Poco Did.

Peta Poco generates all of the models as Partial Classes, so if I need to add properties to a model that are not database driven, I can just create a class with the same name in the same namespace and define it as partial and my additions will get added to the peta poco model.

Now let's say I want to add a derrived class to every Model generated by PetaPoco.. I can still do that. I would just create the new class, then create a partial class for each peta poco model and Derrive from my class in the partials.

Optionally I could modify the T4 Template for Peta Poco in my project to add my base class to the models it is generating.

Ryan Mann
  • 4,820
  • 25
  • 40
  • thanks. This model will not change. As unusual as that sounds, it is fixed. Also, I hear the stuff about the ORM but I work on a huge shared platform and it is not the way it is done here.... – davy Feb 09 '16 at 17:13
0

This would basically need some analysis and would vary from scenario.

Let us say I have a list of virtual method/ property which is only resused in given amount and for rest I end up overloading the functionality, here I need to make a choice of whether I should allow individual class contain these or create a base class and inherit it which should be basis actual amount of code reusability.

If I have concrete functionality to be used by all or my most set of related classes,I would create a base class and inherit rather than changing individual classes in case of change to the common method.

Vinay Pandey
  • 7,596
  • 8
  • 33
  • 50
  • thanks. All the base properties are used by all the derived models. Only one is virtual. All other properties in derived classes extend the base (which is very unlikely to change) – davy Feb 09 '16 at 17:44
  • If your virtual is changing in most of cases then is fair to let it be in individual classes, but then in oop way you clearly differentiating these properties from base and never would be able to use as parentObject.YourProperty. – Vinay Pandey Feb 09 '16 at 17:54
  • I've edited the question to remove the virtual and override, just interested in inheriting common properties from a common view model and extending where required. – davy Feb 09 '16 at 17:59