在Asp.net MVC中从视图模型继承是不好的做法吗?

时间:2016-02-09 16:51:54

标签: c# asp.net-mvc design-patterns

我有一种情况,我在视图模型中有一堆常见属性,但在某些情况下我需要扩展它。我创建了几个开源视图模型,我将其视为期望派生视图模型的视图。 (我意识到我可以使用Polymorphic Binder,但我很高兴现在只传递派生的视图模型。

代码看起来像这样:

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; }    
}

代码审查员希望我有三个不同的视图模型并像这样复制代码:

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; }
}

现在请记住,现实生活中的视图模型比我在这里展示的要复杂得多;我讨厌解决方案应该是复制代码,因为它对我来说是一种非常糟糕的DRY违规行为。

我知道通常有理由说我们会谨慎继承和支持组合,但在他的情况下,继承工作正常,特别是因为系统的这一部分将来可能会发生变化。

总之,他是对的吗?这是一个我应该满意复制代码的情况吗?在这种情况下继承的优点和缺点是什么?

感谢您的想法

3 个答案:

答案 0 :(得分:1)

如果底层基类的所有属性都用在表单/派生类上,那么在我看来没有问题。如果您有视图模型属性,可能会出现安全问题,这些属性由于欠载/叠加攻击而未在表单上使用。

请考虑以下情形。您的域中有一个User类:

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

现在假设您的登录视图模型只是继承了您的域模型,如下所示:

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

如果用户以某种方式了解您的域模型体系结构,则可以在登录页面上添加隐藏字段,将IsAdmin属性设置为true。这就是所谓的叠加攻击。此字段将映射到您的模型,因为您从User继承并可能映射到您的域模型并更改用户在数据库中的角色。

显然,这一切都取决于攻击者(心怀不满的员工可能?)了解您的架构和业务逻辑没有检查这种情况,但在适当的情况下是可能的。我猜你的代码评论员可能过于小心以防万一,但在你的情况下,我认为你做的很好。

答案 1 :(得分:0)

在MVC中,您希望避免创建派生模型,因为它会锁定您的代码以使用它们。

想象一下,如果使用基本模型的视图发生更改但与其他视图无关,则将来会发生变化。现在,您的所有其他视图都将具有您为基础模型更改而添加的访问属性。或者您可以打破基础模型,但是您需要更新所有视图以使用不同的模型。

当每个模型对于它的视图或部分视图(或多个视图/部分视图)是唯一的时,维护MVC站点要容易得多。

其次,有ORM和Micro Orm可以从数据库中为您生成这些模型,它看起来并不像您使用的那样。

即使您不想使用EntityFramework 6,您也可以使用像Peta Poco这样的Micro ORM,它具有T4模板,可以自动生成所有Poco(模型)。

由于我的sql数据库中的表都有3个常见的Sql Columns(Active,Created,Updated),因此我的所有模型都有“Active,Created,Updated”的属性,因为我没有写我的模型,Peta Poco没有。

Peta Poco将所有模型生成为部分类,因此如果我需要向不是数据库驱动的模型添加属性,我可以在同一名称空间中创建一个具有相同名称的类,并将其定义为部分类我的补充将被添加到peta poco模型中。

现在让我们说我想在PetaPoco生成的每个模型中添加一个得到的类......我仍然可以这样做。我只想创建一个新类,然后为每个peta poco模型创建一个局部类,并在partials中为我的类创建。

我可以在我的项目中修改Peta Poco的T4模板,将我的基类添加到它正在生成的模型中。

答案 2 :(得分:0)

这基本上需要一些分析,并且会因情景而异。

让我们说我有一个虚拟方法/属性的列表,它只以给定的数量重新使用,并且为了休息我最终重载了功能,在这里我需要选择是否应该允许单个类包含这些或创建一个基类并继承它,它应该是基本实际的代码可重用性。

如果我具有所有或我的大多数相关类所使用的具体功能,我将创建一个基类并继承而不是在更改常用方法时更改单个类。