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

推荐订阅源

WordPress大学
WordPress大学
T
Threatpost
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
F
Fortinet All Blogs
The GitHub Blog
The GitHub Blog
月光博客
月光博客
V
Visual Studio Blog
T
Tailwind CSS Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 聂微东
Jina AI
Jina AI
J
Java Code Geeks
Martin Fowler
Martin Fowler
大猫的无限游戏
大猫的无限游戏
Recorded Future
Recorded Future
C
Check Point Blog
腾讯CDC
N
Netflix TechBlog - Medium
aimingoo的专栏
aimingoo的专栏
罗磊的独立博客
Hacker News: Ask HN
Hacker News: Ask HN
SecWiki News
SecWiki News
博客园 - Franky
Hacker News - Newest:
Hacker News - Newest: "LLM"
N
News | PayPal Newsroom
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Security @ Cisco Blogs
W
WeLiveSecurity
The Last Watchdog
The Last Watchdog
Cloudbric
Cloudbric
F
Full Disclosure
The Cloudflare Blog
Y
Y Combinator Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
S
Schneier on Security
Schneier on Security
Schneier on Security
Spread Privacy
Spread Privacy
L
LINUX DO - 热门话题
AI
AI
N
News and Events Feed by Topic
T
Tor Project blog
P
Palo Alto Networks Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
Google Developers Blog

博客园 - 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节中提出的两个问题。

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