MVC 3 - 这是如何运作的?

17 c# asp.net-mvc poco asp.net-mvc-3

我在一年多前发过这篇文章,我认为更新它是有意义的,因为它得到了不少观点.

我要么失去了一些东西,要么微软已经搞砸了MVC.我从事过Java MVC项目,他们干净简单.然而,这是一个完全混乱的IMO.在线示例如NerdDinner和ASP.Net上讨论的项目太基础,因此他们"简单"工作的原因.请原谅,如果这听起来很消极,但这是我迄今为止的经验.

我有一个存储库和一个与存储库对话的服务.控制器呼叫服务.

我的数据层不是持久性独立的,因为这些类是由SQL metal生成的.因此,我有很多不必要的功能.理想情况下我想要POCO,但我还没有找到实现这个目标的好方法.

*更新:当然微软没有搞砸任何东西 - 我做到了.我没有完全理解我所掌握的工具.我所做的主要缺陷是,我选择了一种错误的技术来坚持我的实体.LINQ to SQL在有状态应用程序中运行良好,因为可以轻松跟踪数据上下文.但是,这不是无状态环境中的情况.什么是正确的选择?实体框架代码首先或代码只能很好地工作,但更重要的是,它应该无关紧要.MVC或前端应用程序必须不应该知道数据是如何持久化的.*

创建entites时我可以使用对象绑定:

[HttpPost]
public ActionResult Create(Customer c)
{
    // Persistance logic and return view
}    
Run Code Online (Sandbox Code Playgroud)

这很有效,MVC在幕后做了一些约束,一切都"快乐好".

这不是"快乐的好".客户是一个领域模型,更糟糕的是,它依赖于持久性介质,因为它是由SQL金属生成的.我现在要做的是设计我的域模型,它将独立于数据存储或表示层.然后我会从我的域模型创建视图模型并使用它.

一旦我想做一些更复杂的事情,例如 - 保存与客户相关的订单,一切似乎都会破裂:

    [HttpPost]
    public ActionResult Create(Order o)
    {
        // Persistance logic and return view
    }
Run Code Online (Sandbox Code Playgroud)

要坚持订单,我需要客户或至少是CustomerId.CustomerId出现在视图中,但是当它到达Create方法时,它已经丢失了CustomerId.我不喜欢坐在调试MVC代码,因为我无法以任何方式在托管环境中更改它.

好的,有点呻吟,抱歉.我现在要做的是创建一个名为NewOrder,SaveOrder或EditOrder的视图模型,具体取决于我想要实现的目标.这个视图模型将包含我感兴趣的所有属性.顾名思义,开箱即用的自动绑定将绑定提交的值,不会丢失任何内容.如果我想要自定义行为,那么我可以实现自己的"绑定",它将完成这项工作.

替代方法是使用FormCollection:

[HttpPost]
public ActionResult Create(FormCollection collection)
{
   // Here I use the "magic" UpdateModel method which sometimes works and sometimes doesn't, at least for LINQ Entities.               
}
Run Code Online (Sandbox Code Playgroud)

这在书籍和教程中使用,但我没有看到方法中有一个替代方法:TryUpdateModel - 如果此崩溃或模型无效,它会尝试以任一方式更新它.你怎么能确定这会起作用?

使用视图模型进行自动绑定在大多数情况下都可以使用.如果没有,那么你可以覆盖它.你怎么知道它会一直有效?你对它进行单元测试,你睡得好.

我尝试过的另一种方法是使用ViewModel - 带有验证规则的包装器对象.这听起来是个好主意,除了我不想为Entity类添加注释.这种方法非常适合显示数据,但在编写数据时你会怎么做?

[HttpPost]
public ActionResult Create(CustomViewWrapper submittedObject)
{
    // Here I'd have to manually iterate through fields in submittedObject, map it to my Entities, and then, eventually, submit it to the service/repository.
}    
Run Code Online (Sandbox Code Playgroud)

**查看模型是一个很好的前进方式.从视图模型到域模型必须有一些映射代码,然后可以将其传递给相关服务.这不是一种正确的方法,但它是一种方法.自动映射工具是你最好的朋友,你应该找到一个适合你的要求,否则你将编写大量的样板代码.**

我错过了什么,或者这是微软MVC3的工作方式吗?我不知道这是如何简化事情的,尤其是与Java MVC的比较.

如果这听起来很消极,我很抱歉,但这是我迄今为止的经历.我感谢框架不断改进,UpdateModel等方法被引入,但文档在哪里?也许是时候停下来思考一下了?我更喜欢我的代码在整个过程中保持一致,但是到目前为止我所看到的,我完全不相信这是正确的前进方向.

我喜欢这个框架.有很多东西需要学习,它并没有比以往任何时候都更令人兴奋.应该发布关于网络表单的另一篇文章.我希望这是有帮助的.

ata*_*ini 17

1)对于保存订单而不存在CustomerId的情况.如果Order有一个CustomerId属性,并且您有一个强大的类型视图,那么您可以通过添加将其保留回控制器操作

@Html.HiddenFor(model => model.CustomerId)
Run Code Online (Sandbox Code Playgroud)

这样做会让默认的模型绑定器为您填充内容.

2)关于使用视图模型,我建议采用这种方法.如果您使用类似AutoMapper的东西,您可以从冗余映射方案中消除一些痛苦.如果您使用类似Fluent验证的内容,那么您可以很好地区分验证问题.

这是一个关于一般ASP.NET MVC实现方法的良好链接.

  • @vikp:您也可以将POCO与ASP.NET MVC一起使用,但是您的问题提到在您的情况下这不是一个选项.无论如何,这种方法很快就会崩溃,你最终会得到松散合同和不可测试的意大利面条代码的观点.此外,正确的第三方添加可能非常有用,为您节省大量时间和精力 - 您不应该这么快就解雇它们.如果您使用[NuGet](http://nuget.codeplex.com/),它们基本上可以像任何其他程序集一样轻松添加到项目中. (2认同)

egl*_*ius 10

我不认为你的问题是asp.net MVC,而是你选择一起使用的所有部分.

你想要它原始和简单?

全方位使用POCO,并在您需要的地方实施存储库.

我没有使用过Java MVC,但是如果你包括如何解决那里的特定问题,它会让整个问题看起来不像是一个咆哮.

让我们清楚一些误解或误解:

  • 您可以通过帖子将复杂对象传递给视图.但是如果它有意义,你只想这样做,见下一个项目符号
  • 你在那里挑选的样品会发出一些警报.接受订单的客户数据或客户ID而不检查授权可能是一个很大的安全漏洞.根据您接受/允许的内容,订单也可以这样说.无论是POCO,LINQ,Asp.net MVC还是Java MVC,这都是使用ViewModel的一个巨大案例.
  • 您可以将未通过帖子显示的简单值传递给视图.它完成了隐藏字段(asp.net MVC非常简单地支持使用模型值),并且在某些情况下它会为您生成隐藏字段.
  • 你绝不会被迫使用linq2sql和Asp.net MVC.如果您发现它缺乏打算如何使用它,请远离它.注意我喜欢linq2sql,但它如何与你对使用asp.net mvc做什么的看法联系起来很奇怪.
  • "我参与了Java MVC项目,它们很简洁".处理项目与自己设计项目不同.设计技巧确实会影响你从中获得的东西.不是说你的情况,但只是想指出这一点,因为缺乏你在Java MVC中缺少的细节.
  • "我的数据层不是持久性独立的,因为这些类是由SQL金属生成的.因此我有很多不必要的功能.理想情况下我想要POCO,但我没有找到实现这个目标的好方法然而".你选错了技术,linq2sql并不适合这个要求.它在我使用它的项目中并不是一个问题,但是所有东西都是以这样一种方式设计的,这种方式与你的细节相比没那么紧密.也就是说,转移到其他东西.顺便说一下,你应该分享你在Java MVC中使用的内容.
  • "CustomerId出现在视图中,但到创建方法时,它已经丢失了CustomerId." 如果该属性处于有序状态,您可以打赌您的代码有错误.现在,这是一个完全不同的真实问题,为什么它不使用CustomerId /这样的问题会带来:您的客户类,视图,您传递给视图的内容......答案将包括,但是不限于:检查浏览器中的HTML源代码以查看您实际使用源发布的值(或者使用fiddler查看相同的值),确保CustomerId在将其传递给View时确实具有该值.
  • 你说:""魔术"UpdateModel方法,有时可以工作,有时不会".这不是魔术,你可以看到它做了什么,当然可以找到它的信息.您发布的信息中有一些内容,我的下注是非可选字段或解析信息的错误值...视图支持为此添加验证.没有验证,这可能是缺乏的.
  • 您在评论中说:"在调用UpdateModel后,我无法显式设置CustomerId,我将不得不检索客户对象,然后将其分配给订单,这似乎是一个开销,因为我需要的只是CustomerId "...您正在接受用户输入的CustomerId(即使它是隐藏字段),您真的想要验证该输入.此外,您自相矛盾,您声称只需要CustomerId,但之后您说您需要与订单绑定相关的完整客户对象.这就是它,如果您只绑定CustomerId,您仍然需要获得该客户并将其分配给该属性.除了场景之外没有任何魔力......
  • 同样在评论中:"更新模型是我现在完全避免的事情,因为我不知道它将如何与LINQ实体一起运行.在视图模型类中,我创建了将LINQ实体转换为我的视图模型的构造函数.控制器中的代码量,但仍然感觉不对".使用ViewModel(或EditModel)的原因不是因为它是linq2sql ...这是因为,在许多其他原因中,您正在公开一个模型,允许操作方式超出您实际想要允许用户修改的方式.暴露原始模型,如果它具有不允许用户修改的字段,则是真正的问题.