在asp.net-mvc中,移动我的" EditViewModel"是不对的。我的MVC网络项目之外的课程?

时间:2013-08-04 11:29:42

标签: asp.net-mvc viewmodel

我有一个asp.net-mvc网站,几乎是一个CRUD应用程序,但我也做了一些添加& webview之外的更新(从电子表格上传等)。 Based on this article,我试图将MVC项目之外的逻辑放到一个单独的共享项目中,这样我就可以在所有场景中重用相同的代码,我试图隔离和分离我的"阅读&# 34; viewModel绑定到UI以显示来自" edit" viewModels,表示在表单帖子上发布到服务器的内容。

我在解决方案(domainobjects,importexport等)中有许多与其他解决方案共享的项目,而MVC项目在MVC项目中有以下目录

  • 控制器
  • 观看次数
  • ViewModels
  • 脚本
  • EditViewModels

我的ViewModels文件夹表示我绑定到我的视图的对象(通常包含以下内容的容器对象:

  • 域对象和
  • 用于填充UI下拉列表的一堆IEnumerable的SelectListItem

类似的东西:

 public class OrderViewModel
 {
       public Order MyOrder {get;set;}
       public IEnumerable<SelectListItem> OrderTypes {get;set;}
       public IEnumerable<SelectListItem> Sizes {get;set;}
 }

我的EditViewModels文件夹表示我从表单发布到服务器的对象,因此它们通常是更简单的平面对象,只有在我添加或更新数据库之前填充域对象的原始对象:

public class OrderEditViewModel
{
      public int Id {get;set;}
      public int OrderTypeId {get;set;}
      public int SizeId {get;set;}
}

我的主要问题是我的Controller类中有一个方法,通常看起来像这样(简化):

  public ActionResult Update(OrderEditViewModel order)
  {
         var existingOrder = _repository.GetOrder(order.Id);
         existingOrder.Name = order.Name;
         existingOrder.Size = _repository.GetSize(order.SizeId);
         existingOrder.Price = order.Price;
         _repository.Save(existingOrder);
         return Json( Result = "Success");
  }

我试图弄清楚如何在MVC项目之外获得尽可能多的代码,但这迫使我将所有类移到MVC项目之外的EditViewModel中,以便可以重用这些对象。

有没有人认为这些&#34; Post&#34;数据结构归类于MVC项目之外。鉴于它是一个&#34; viewmodel&#34;将它从视图中移开是不合适的,但我没有看到任何其他方式在MVC项目之外共享此代码。也许&#34; viewModel&#34;这里的名字可能错了吗?

8 个答案:

答案 0 :(得分:6)

您的视图模型特定于您的视图,不应与其他任何内容相关。它们包含其他任何不应该关注的内容,例如您的选择列表。因此,他们应该留在你的用户界面。

在我看来,这篇文章是创建一种业务逻辑依赖于UI(或至少是UI模型,即视图模型)的情况,我认为这是错误的方法。 UI应该能够使用业务逻辑,而业务逻辑不知道UI是什么。它可以是一个网站,一个胖客户端,一个移动客户端,一个Web服务等......通过使这个逻辑依赖于您的视图模型,您现在正在制作任何非基于Web的未来服务取决于那些。 / p>

然而,这是一个简单的CRUD应用程序,在简单的CRUD应用程序中,您通常可以采用许多快捷方式,因为它不值得额外的工程工作。我通常不会直接在View Model中将域对象传递给视图。但在这种情况下,它可能是最好的选择。

但是,如果你想“正确”这样做,那么你需要创建更多的关注点分离。您的域和UI层需要更多分离。您可以创建单独的视图和域模型,然后在它们之间进行映射。这可以防止业务层了解有关UI的任何信息。

我可能会创建一个处理逻辑的服务层。例如:

_orderService.UpdateOrder(order.Id, order.Name, order.Price);

答案 1 :(得分:3)

就我而言,我在读取(视图)模型和写入模型之间有所区别。

读取模型非常特定于视图,它们可以包含选择列表以及格式化和本地化的内容。你不应该在你的ui项目之外移动这个模型。当然,您可以使用模型进行单独的组装,也可以为每个模块进行一次组装,但不应该从域层中使用这些模型。

编写模型 - 在我看来 - 并不是特定于您的UI。相反,它们代表命令所需的数据(例如SaveUserCommand)。它们可以包含验证属性,因此您的域层可以轻松验证它们,并且它们可以由域层和UI共享。在我的项目中,每个命令有一个类(例如SaveUserCommand,EditUserCommand,DeleteUserCommand)和相关模型(SaveUserModel,EditUserModel)。有人会评论,它们还包含一些特定于UI的代码(例如属性的IClientValidateable itnerface或属性本身),并且至少IClientValidateable接口是我愿意忽略的问题,以减少模型的数量。我使用这种方法的经验(我也尝试过其他方法)表明,这些模型非常简单,并且很容易绑定到这些模型。

有时您也会遇到问题,您希望在编辑视图中显示一些其他信息。而不是将所有这些信息添加到viewbag,我将有另一个模型,例如:

 class UserEditModel 
 {
     string Password;
 }

 UserEditViewModel
 {
     DateTime Modified;

     UserEditModel Edit;
 }

所以我的建议:

  1. 创建具有特定于您的用例的所有数据和验证逻辑的写入模型。
  2. 创建包含您要显示的所有数据的视图模型,并尝试不使用ViewBag。
  3. 如果您有表单,请将写入模型添加到视图模型中。写模型将所有数据通过POST发送回您的服务器,然后直接发送到您的域层。

答案 2 :(得分:1)

我在两个组件中使用了四个“图层”

{application} .app程序集包含三个名称空间,只是一个常规类库项目。

1){application} .model for domain model

2)使用存储库模式的数据的{application} .data

3){application} .services for all business logic

用于UI的

{application} .WebUI程序集,这是MVC项目

控制器只调用服务和服务,通过存储库获取和更新数据。

您的应用必须执行的每项操作都有一个服务API,即

OrderServices.Update(existingOrder)

OrderServices.Approve(existingOrder)

服务层只知道域模型,控制器只是使用从服务获得的域模型组装视图模型,将它们发送到视图,并使用从视图中获取的视图模型准备域模型,以将它们发送到适当的服务

这样你最终可以创建一个{application} .WebAPI或任何使用相同{application} .app程序集的程序,重用所有的buissiness逻辑并保持viwemodels属于它们(WebUI项目)

希望这有帮助。

最好的问候。

答案 3 :(得分:0)

您可以使用项目的服务架构,其中所有函数和数据库查询都在此文件中,您只需添加此代码即可使用

 IOrderService<Order> service = new OrderEntityService();

并像

一样使用它
service.Create(Order) or service.Update();

答案 4 :(得分:0)

对我来说很奇怪的是,你正在努力尽可能地分层你的应用程序,但你仍然让你的MVC控制器包含很多你的逻辑。您正在尝试共享对象和模型,但添加新OrderEditViewModel的逻辑不会被共享,它会卡在该控制器中。

我尝试做的是为每个控制器创建一个“帮助器”或“逻辑”类。然后将该逻辑或辅助类注入我的控制器并包装在接口中。我的控制器可以通过我的助手类保存,编辑和删除项目,但不知道它实际上是如何做的。

然后我将这些逻辑类和模型共享给其他项目,允许重复使用大量代码。问题只是确保控制器的“HTTP”性没有潜入您的逻辑类,因为这些必须可以在控制台或winforms应用程序中使用。因此,您必须非常严格,并将许多内容(如HTTPSession或HTTPContext)包装到可以具有非HTTP实现的接口中。

答案 5 :(得分:0)

嗯,我了解你的情况,并且也倾向于使用@MystereMan建议的DDD(领域驱动设计)解决方案。

我有一种方法可以将“模型”分为三类:

  1. ViewModels:拥有在UI中显示内容数据所需的所有信息
  2. RequestModels:拥有发送数据,发送/获取等所需的所有信息。)
  3. AutoBindModels:拥有注入我的MVC绑定模型的所有信息(cookie,会话等)。
  4. 最重要的是,对于我用作DTO / POCO的所有类,实际上它们没有UI依赖代码,只有属性/计算属性,并且可以很容易地在UI项目中引用的任何其他项目中。

    您还可以创建一个Controller类,作为ASP.MVC项目之外的服务,并将其扩展或注入MVC​​控制器。

    希望它有所帮助...

答案 6 :(得分:0)

我从不重用(编辑)ViewModels对象(这不完全正确,我经常在创建和更新之间共享一个EditViewModel,但并非总是如此)。

我为特定视图设计了ViewModel。因此,当UI更改(它一直在变化)时,我不必妥协我的ViewModel。

即使它们是相同的,我也会创建两个不同的ViewModel。我完成了重构共享的ViewModels ..

我会回答你的问题

希望它有所帮助。

答案 7 :(得分:-1)

OrderEditViewModelOrderViewModel都是当天的“ViewModels”。 IMO,即使在同一个“ViewModels”文件夹中,它们也可能在同一个项目中保持在一起。您可以在ViewModels下为“EditViewModels”创建一个子文件夹。

现在,您要清理/整理控制器操作,可能需要使用AutoMapperValueInjecter。您正在手动映射域实体和视图模型。这是一项令人厌倦的工作。使用AutoMapper,您可以执行以下操作:

var customerInfo = Mapper.Map<CustomerViewModel, CustomerInfo>(customerViewModel);