我想说的是,您在客户端交互的两个方向上都重复使用了ViewModel一词。如果您狂野地阅读了足够的ASP.NET MVC代码,则可能已经看到了ViewModel和EditModel之间的区别。我认为这很重要。
ViewModel代表呈现视图所需的所有信息。这可能包括在静态非交互式位置渲染的数据,也可能纯粹用于执行检查以确定要渲染的内容的数据。Controller GET操作通常负责为其视图打包ViewModel。
EditModel(或者可能是ActionModel)表示执行用户要对该POST进行的操作所需的数据。因此,EditModel确实试图描述一个动作。这可能会从ViewModel中排除一些数据,尽管相关,但我认为重要的是要意识到它们确实有所不同。
一个想法
也就是说,您可以很容易地从模型-> ViewModel拥有一个AutoMapper配置,而从EditModel->模型得到一个不同的配置。然后,不同的Controller操作仅需要使用AutoMapper。地狱中的EditModel可以具有一个函数,以针对模型验证其属性,并将这些值应用于Model本身。它什么也没做,而且您在MVC中拥有ModelBinder,可以将请求映射到EditModel。
另一个想法
除了最近我一直在考虑的某种动作模型之外,ActionModel的想法还在于,客户端发回给您的内容实际上是用户执行的几个动作的描述,而不仅仅是一个大数据。当然,这需要在客户端使用一些Javascript进行管理,但是我认为这个想法很有趣。
本质上,当用户在您呈现给他们的屏幕上执行动作时,Javascript将开始创建动作对象列表。一个示例可能是用户在员工信息屏幕上。他们更新姓氏并添加新地址,因为该雇员最近结婚了。在封面下产生一个ChangeEmployeeName
和一个AddEmployeeMailingAddress
对象到列表。用户单击“保存”以提交更改,然后提交两个对象的列表,每个对象仅包含执行每个操作所需的信息。
您将需要一个更智能的ModelBinder,然后使用默认的但更好的JSON序列化程序才能处理客户端操作对象到服务器端对象的映射。服务器端的方法(如果您处于2层环境中)可以轻松地使用完成对所使用模型的操作的方法。因此,Controller动作最终只是获取要为Model实例提取的ID和要在其上执行的动作的列表。或者,动作中包含ID,以使它们非常独立。
因此,也许这样的事情在服务器端实现了:
public interface IUserAction<TModel>
{
long ModelId { get; set; }
IEnumerable<string> Validate(TModel model);
void Complete(TModel model);
}
[Transaction]
public ActionResult Save(IEnumerable<IUserAction<Employee>> actions)
{
var errors = new List<string>();
foreach( var action in actions )
{
var employee = _employeeRepository.Get(action.ModelId);
errors.AddRange(action.Validate(employee));
}
foreach( var action in editModel.UserActions )
{
var employee = _employeeRepository.Get(action.ModelId);
action.Complete(employee);
_employeeRepository.Update(employee);
}
}
这确实使回发动作相当通用,因为您依靠ModelBinder来获取正确的IUserAction实例,而IUserAction实例本身可以执行正确的逻辑,或者(更可能)使用信息调用Model。
如果您在3层环境中,则可以将IUserAction设置为简单的DTO,以便跨越边界拍摄并在应用程序层上以类似的方法执行。根据您执行该层的方式,可以很容易地将其拆分并保留在事务中(想到的是Agatha的请求/响应,并利用了DI和NHibernate的身份映射)。
无论如何,我确定这不是一个完美的主意,它需要客户端上的一些JS来管理,而且我还无法做一个项目来了解它的进展情况,但是这篇文章试图考虑如何到达那里然后再回来,所以我想我会发表自己的想法。我希望它能有所帮助,并且我很想听听其他方式来管理交互。