Iai*_*ain 23 c# asp.net-mvc mvvm asp.net-mvc-viewmodel
我对使用ViewModel相当新,我想知道,ViewModel是否可以将域模型的实例包含为属性,或者这些域模型的属性是否应该是ViewModel本身的属性?例如,如果我有一个班级Album.cs
public class Album
{
public int AlbumId { get; set; }
public string Title { get; set; }
public string Price { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
您是否通常让ViewModel保存Album.cs该类的实例,或者您是否让ViewModel具有每个Album.cs类属性的属性.
public class AlbumViewModel
{
public Album Album { get; set; }
public IEnumerable<SelectListItem> Genres { get; set; }
public IEnumerable<SelectListItem> Artists { get; set; }
public int Rating { get; set; }
// other properties specific to the View
}
public class AlbumViewModel
{
public int AlbumId { get; set; }
public string Title { get; set; }
public string Price { get; set; }
public IEnumerable<SelectListItem> Genres { get; set; }
public IEnumerable<SelectListItem> Artists { get; set; }
public int Rating { get; set; }
// other properties specific to the View
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*fan 40
最有趣的部分:这不局限于@Html.EditorFor在Id,它实际上是"美好的旧数据/业务/ UI层",即关注点分离的分离-的问题.我稍后会说明这一点,但是现在; 请记住,它也适用于hidden任何其他设计模式.
ViewModel是否可以包含域模型的实例?
基本上不是,虽然我看到它发生了很多.这取决于Id你的项目的水平.
让我举个例子.想象一下以下视图模型:
public class FooViewModel
{
public string Name {get;set;}
}
public class DomainModel
{
public string Name {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
和以下 automapper
public void Method1(FooViewModel input)
{
//duplicate code: same mapping twice, see Method2
var domainModel = new DomainModel { Name = input.Name };
//logic
}
public void Method2(FooViewModel input)
{
//duplicate code: same mapping twice, see Method1
var domainModel = new DomainModel { Name = input.Name };
//logic
}
Run Code Online (Sandbox Code Playgroud)
因此,在控制器的某个位置填充FooViewModel并将其传递给您的视图.
现在,请考虑以下方案:
1)域模型发生变化.
在这种情况下,您可能还需要调整视图,这在关注点分离的背景下是不好的做法.
如果已将ViewModel与DomainModel分开,则对映射(ViewModel => DomainModel(和back))进行微调就足够了.
2)DomainClass具有嵌套属性,您的视图只显示Foo.FooProp.
我在实际场景中看到过这个问题.
在这种情况下,常见的问题是使用OtherFoo.FooProp将导致嵌套对象的输入.这可能包括viewmodels和其他敏感信息.按照本课程,您将发现自己创建domainmodels输入.如果将它与服务器端模型绑定或者自动化结合起来DTO's,使用像firebug这样的工具来阻止对隐藏文件的操作是非常困难的.
虽然阻止其中一些字段可能很容易,但是你拥有的域/数据对象越多,保护这部分就越复杂.请记住,您可能希望更改您的DomainModel,原因不一定是针对视图.因此,对于DomainModel中的每次更改,您都应该意识到它可能会影响控制器的视图和安全性方面.
3)在asp.net-MVC中,通常使用验证属性.
您真的希望您的域包含有关您的观点的元数据吗?或者将视图逻辑应用于数据层?您的视图验证是否始终与域验证相同?它是否具有相同的验证逻辑?您使用的是域模型交叉应用程序吗?等等
我认为这显然不是采取的路线.
4)更多
我可以给你更多的场景,但这只是一个品味更具吸引力的问题.我只希望在这一点上你能得到点:)尽管如此,我答应了一个例子:
现在,真的很脏,domainmodels它会起作用,但我不认为你应该想要它.
构建视图模型只需要多一点努力,通常与域模型类似,为80 +%.这可能感觉就像做了不必要的映射,但是当出现第一个概念差异时,你会发现它值得努力:)
因此,作为替代方案,我建议对一般情况进行以下设置:
domainlayer来创建从一个到另一个的映射(这将有助于映射logic到domainmodels)好处是,例如; 如果在其中一个数据库表中创建一个额外的字段,它将不会影响您的视图.它可能会触及您的业务层或映射,但它会停止.当然,大多数时候你也想改变你的观点,但在这种情况下你不需要.因此,它将问题隔离在代码的一部分中.
web api/data-layer
另一个具体示例说明了它在Web-API/EF场景中的工作原理:
注意
正如@mrjoltcola所说:还有一个过于引擎的组件要记住.如果上述情况不适用,并且用户/程序员可以信任,那么你的好处就是去.但请记住,由于DomainModel/ViewModel混合,可维护性和可重用性会降低.
cod*_*eim 16
从技术最佳实践和个人偏好的混合看,意见各不相同.
在视图模型中使用域对象,甚至使用域对象作为模型都没有错,而且很多人都这样做.有些人强烈建议为每个视图创建视图模型,但就个人而言,我觉得许多应用程序都是由开发人员过度设计的,他们学习并重复他们习以为常的方法.事实上,有几种方法可以使用较新版本的ASP.NET MVC来实现目标.
当您为视图模型以及业务和持久层使用通用域类时,最大的风险是模型注入.向模型类添加新属性可以在服务器边界之外公开这些属性.攻击者可能会看到他不应该看到的属性(序列化)并改变他不应该改变的值(模型绑定器).
为防止注射,请使用与您的整体方法相关的安全实践.如果您计划使用域对象,请确保在控制器中或通过模型绑定器注释使用白名单或黑名单(包含/排除).黑名单更方便,但是编写未来修订版的懒惰开发人员可能会忘记它们或者不了解它们.白名单([Bind(Include = ...)]是强制性的,在添加新字段时需要注意,因此它们充当内联视图模型.
例:
[Bind(Exclude="CompanyId,TenantId")]
public class CustomerModel
{
public int Id { get; set; }
public int CompanyId { get; set; } // user cannot inject
public int TenantId { get; set; } // ..
public string Name { get; set; }
public string Phone { get; set; }
// ...
}
Run Code Online (Sandbox Code Playgroud)
要么
public ActionResult Edit([Bind(Include = "Id,Name,Phone")] CustomerModel customer)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
第一个示例是在整个应用程序中强制执行多租户安全的好方法.第二个示例允许自定义每个操作.
在您的方法中保持一致,并清楚地记录项目中用于其他开发人员的方法.
我建议您始终使用视图模型进行登录/配置文件相关功能,以强制自己"编组"Web控制器和数据访问层之间的字段作为安全练习.
| 归档时间: |
|
| 查看次数: |
13376 次 |
| 最近记录: |