我有一个asp.net-mvc网站,几乎是一个CRUD应用程序,但我也做了一些添加& webview之外的更新(从电子表格上传等)。 Based on this article,我试图将MVC项目之外的逻辑放到一个单独的共享项目中,这样我就可以在所有场景中重用相同的代码,我试图隔离和分离我的"阅读&# 34; viewModel绑定到UI以显示来自" edit" viewModels,表示在表单帖子上发布到服务器的内容。
我在解决方案(domainobjects,importexport等)中有许多与其他解决方案共享的项目,而MVC项目在MVC项目中有以下目录
我的ViewModels文件夹表示我绑定到我的视图的对象(通常包含以下内容的容器对象:
类似的东西:
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;这里的名字可能错了吗?
答案 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;
}
所以我的建议:
答案 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(领域驱动设计)解决方案。
我有一种方法可以将“模型”分为三类:
最重要的是,对于我用作DTO / POCO的所有类,实际上它们没有UI依赖代码,只有属性/计算属性,并且可以很容易地在UI项目中引用的任何其他项目中。
您还可以创建一个Controller类,作为ASP.MVC项目之外的服务,并将其扩展或注入MVC控制器。
希望它有所帮助...
答案 6 :(得分:0)
我从不重用(编辑)ViewModels对象(这不完全正确,我经常在创建和更新之间共享一个EditViewModel,但并非总是如此)。
我为特定视图设计了ViewModel。因此,当UI更改(它一直在变化)时,我不必妥协我的ViewModel。
即使它们是相同的,我也会创建两个不同的ViewModel。我完成了重构共享的ViewModels ..
我会回答你的问题是。
希望它有所帮助。
答案 7 :(得分:-1)
OrderEditViewModel
和OrderViewModel
都是当天的“ViewModels”。 IMO,即使在同一个“ViewModels”文件夹中,它们也可能在同一个项目中保持在一起。您可以在ViewModels下为“EditViewModels”创建一个子文件夹。
现在,您要清理/整理控制器操作,可能需要使用AutoMapper或ValueInjecter。您正在手动映射域实体和视图模型。这是一项令人厌倦的工作。使用AutoMapper,您可以执行以下操作:
var customerInfo = Mapper.Map<CustomerViewModel, CustomerInfo>(customerViewModel);