惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Simon Willison's Weblog
Simon Willison's Weblog
P
Privacy International News Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Troy Hunt's Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Attack and Defense Labs
Attack and Defense Labs
S
Secure Thoughts
V2EX - 技术
V2EX - 技术
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
O
OpenAI News
Cloudbric
Cloudbric
Google Online Security Blog
Google Online Security Blog
Schneier on Security
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Help Net Security
Help Net Security
Cyberwarzone
Cyberwarzone
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Spread Privacy
Spread Privacy
NISL@THU
NISL@THU
N
News and Events Feed by Topic
T
Tenable Blog
S
Security @ Cisco Blogs
N
News and Events Feed by Topic
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
宝玉的分享
宝玉的分享
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
V
Visual Studio Blog
P
Proofpoint News Feed
Webroot Blog
Webroot Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 三生石上(FineUI控件)
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Jina AI
Jina AI
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
L
LangChain Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东

博客园 - sinlight23

Web开发框架趋势 ASP.NET MVC - PageData的应用 ASP.NET拾遗 - Health Monitoring .NET Xml序列化时会忽略值为"默认值"的Property或Field Enumerable.Range和自定义的IntRange/DateRange HOWTO: Web Deploy时服务器报登录失败的解决方法 HOWTO: 为GitHub for Windows指定代理服务器 ASP.NET MVC - 在MVC 3项目中使用ASP.NET Bundling and Minification机制 脚印:关于错误编码的管理的一些思考 脚印:软件开发随想录 脚印:关于扩展方法的使用 脚印:一次重构讨论 脚印:记录一次重构,将规则生产和规则消费(执行委托)分离 HOWTO: IE8下处理iframe自适应高度 Microsoft ASP.NET 2.0 AJAX 相关信息备忘 MVC 模式在javascript中的应用 VS2010 "SQL Server 2005 Database Project" 使用笔记(二) VS2010 "SQL Server 2005 Database Project" 使用笔记 腳印: 初學者的心態
ASP.NET MVC 实现模式 - ModelBuilder
sinlight23 · 2013-03-31 · via 博客园 - sinlight23

ViewModel的创建过程从Controller中分离到ModelBuilder中,本质上是为了职责的分离,也提高了Controller的可读性。

通常的情况

使用MVC时,在Controller中,会包含很多用于创建ViewModel的代码。
让我们从一个例子开始。
假设我们有一个用于呈现填写订单的页面(~\Order\FT-BJS-95486),对应的Action 如下:

public ActionResult Order(string productNo)
{
    var p = ProductService.GetProduct(productNo);
    var model = new OrderModel
    {
        ProductNo = productNo,
        ProductName = p.ProductName,
    };

    return View(model);
}

其中OrderModel 这个ViewModel的定义为:

public class OrderModel 
{
    public string ProductNo { get; set; }
    public string ProductName { get; set; }
    public int Count { get; set; }
    public string Address { get; set; }
}

接下来,为了接收用户输入的订单信息,我们可能会有这样一个Action

[HttpPost]
public ActionResult Order(OrderModel model)
{
    var p = ProductService.GetProduct(productNo);

    if(!ModelState.IsVaidate())
    {
        // 这里假设:
        // 1. ProductName并没用通过hidden input的方式post回来
        // 2. ProductNo 随同其它用户输入信息post回来
        model.ProductName = p.ProductName;
        return View(model);
    }

    var model2 = new OrderConfirmModel
    {
        ProductNo = model.ProductNo,
        ProductName = p.ProductName,
        Count = model.Count,
        Address = model.Address,
    };
    return View("OrderConfirm", model2);
}

1. 问题

  1. 有些ViewModel的创建可能比较“复杂”,从阅读Controller的角度,不是“主控制流”
  2. ViewModel会在不同阶段被创建出来,不同阶段的创建过程,往往出现一些重复的代码

2. 分析

在上述的例子中,虽然OrderModel本身的结构及创建过程都非常简单,但我们依然可以识别出重复的部分:

var p = ProductService.GetProduct(productNo);
model.ProductName = product.ProductName;

我们可以归纳出这些重复的部分,分属于两个ViewModel被创建的“阶段”:

  1. Create
  2. Rebuild

我们据此抽象出IModelBuilder接口

public interface IModelBuilder<TViewModel>
{
    TViewModel Create();
    TViewModel Rebuild(TViewModel model);
}

3. 改造

我们来写一个OrderModelBuilder,实现IModelBuilder接口

public class OrderModelBuilder : IModelBuilder<OrderModel>
{
    private string _productNo;
    private string _productName;

    public OrderModelBuilder(string productNo, string productName)
    {
        _productNo = productNo;
        _productName = productName;
    }

    public OrderModel Create()
    {
        var model = new OrderModel
        {
            ProductNo = _productNo,
        };
        model = this.Rebuild(model);
        return model;
    }

    public OrderModel Rebuild(OrderModel model)
    {
        model.ProductName = _productName;
        return model;
    }
}

用OrderModelBuilder来简化OrderController

private OrderModelBuilder GetBuilder(string productNo)
{
    var p = ProductService.GetProduct(productNo);
    var builder = new OrderModelBuilder(p);
    return builder;
}

public ActionResult Order(string productNo)
{
    var builder = GetBuilder(productNo);
    var model = builder.Create();
    return View(model);
}

[HttpPost]
public ActionResult Order(OrderModel model)
{
    if(!model.IsVaidate())
    {
        var builder = GetBuilder(model.ProductNo);
        var model = builder.Rebuild(model);
        return View(model);
    }
    // 根据OrderModel创建OrderConfirmModel
    var builder2 = new OrderConfirmModelBuilder(model);
    var model2 = builder2.Create();
    return View("OrderConfirm", model2);
}

这样,就解决了我们在第1节中提出的两个问题。

此文介绍的内容,无关语言和平台。