Asp.net mvc 访问视图中的域对象

Asp.net mvc 访问视图中的域对象,asp.net-mvc,domain-driven-design,Asp.net Mvc,Domain Driven Design,如果我不想公开域对象的内部状态,但需要显示它们,我可以考虑三种方法。 以下哪一项最“正确”(如果有的话?) “DTO/ViewModel方法”。 这似乎是一种流行的方法 在ASP.NET MVC世界中(尤其是 使用AutoMapper) “装饰方法”。如果我有 “客户”实体,我装饰它 有一个“可显示的客户”,他可以 访问服务器的内部状态 客户(在大多数语言中) 我已经处理过了) “接口” 方法”。在那里我做了一些类似的事情 这: 我投票支持并广泛使用你的#1选项。原因如下: 允许复杂的视图

如果我不想公开域对象的内部状态,但需要显示它们,我可以考虑三种方法。 以下哪一项最“正确”(如果有的话?)

  • “DTO/ViewModel方法”。 这似乎是一种流行的方法 在ASP.NET MVC世界中(尤其是 使用AutoMapper)
  • “装饰方法”。如果我有 “客户”实体,我装饰它 有一个“可显示的客户”,他可以 访问服务器的内部状态 客户(在大多数语言中) 我已经处理过了)
  • “接口” 方法”。在那里我做了一些类似的事情 这:


  • 我投票支持并广泛使用你的#1选项。原因如下:

    • 允许复杂的视图模型,如组合多个我的域对象列表。设想一个PostViewModel,它有一个Post元素和一个挂在上面的IList容器
    • 在我当前的项目中,我们已经将域验证抽象到自定义ViewModels中,并对表单进行了一些灵活的Ajax验证
    • 虽然这个概念不会直接在模型上公开您的域对象,但我可以将PostViewModel的属性挂起
    最后一点是ViewModels概念真正存在的原因。将域对象一直公开到UI甚至视图并不违反DDD,这是由DDD和UI概念设计和预期的。您只能公开域中的对象以供使用,并通过服务和基础结构锁定/保持其状态。因此,您没有违反在UI中使用实际域对象的规定

    当您为UI引入MVC概念,并尝试呈现页面/位置的特定视图时。您可能(也将)拥有与域完全无关的其他显示元素,例如仅用于UI的。进度条只关注UI和应用程序层。它与您的域无关

    因此,我接受的DDD解决方案是在应用程序/UI层中使用一个混合对象,该对象可以包含许多对象:域对象和应用程序对象,以便为一个特定视图进行渲染。这是ViewModel的概念,是其存在的核心原因

    ViewModel概念可以被认为是DDD术语中的应用程序层非业务对象


    稍微偏离主题,讨论一种特定的技术,ASP.NET MVC有额外的特性来帮助使这个概念很好地协同工作。它不是直接内置在ASP.NET MVC中,而是作为Microsoft的一个附加程序集(称为Futures project)提供的

    ,最有用的功能是RenderAction扩展方法:

    这是一个非常强大的概念,它可以启动底层控制器并调用action方法。这样做大大简化了ViewModels,使其只关心渲染的视图。我不再需要附加与视图无关的工具条控件或其他常用数据框、导航栏等

    RenderAction与RenderPartial不同,纯粹是因为DDD的原因:它允许您将业务逻辑移回它所属的控制器中。控制器调用适当的视图来渲染它的显示。这严格遵循DDD和MVC概念

    微软已经声明,在明年发布的ASP.NETMVC2.0中,RenderAction将成为它的一部分


    抱歉,这是一个长篇大论…

    RenderAction看起来与Zend Framework()for PHP中的Action View Helper非常相似。但是框架维护者建议不要使用它,因为它基本上再次经历了整个MVC周期,导致了不必要的开销。RenderAction是否也有同样的缺陷,或者它的设计是否有所不同?是的,它类似于Ruby中建议不要使用的Action视图(正如您所发现的)。但是在Asp.NETMVC中,将输出插入到输出文本流中是非常有效的。这就是Asp.NETMVC相对于Asp.NETWebForms(旧方法)的优势。WebForms需要旋转整个页面生命周期,Mvc不依赖页面生命周期在控制器类文件上呈现动作方法。
    class Customer {
        ....
        public void renderWith(CustomerRenderer renderer) {
             renderer.renderCustomer(address,name);
        } 
    }
    
    interface CustomerRenderer {
        public void renderCustomer(Address address, Name name);
    }