65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET MVC 自定义模型绑定器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (42投票s)

2013年6月12日

CPOL

2分钟阅读

viewsIcon

250916

MVC 自定义绑定。

引言

在下面的示例中,我希望在视图中将日期分解为三个字段:日、月和年,但我希望我的模型只有一个属性来存储这些字段的组合。

背景

最近,我正在研究一个不寻常的问题,我们需要临时向视图添加自定义字段。如果 MVC 应用程序直接与数据源通信,这并不是什么大问题。但我的应用程序是通过多个基于 REST 的服务进行的,这些服务与分布在多个域中的 CRM dynamics 后端通信。这意味着我们必须在整个系统中更改数据模型。这时我意识到我们可以有一个专门的字段来存储所有临时字段数据,使用 JSON 或 XML,并将其附加到现有字段之一。这可能不是理想的解决方案,但正是在这时我发现了 MVC 的自定义绑定。我想与您分享使用自定义绑定解决类似问题的简单易用性。

Using the Code

视图

在我的视图中,我将在表单中为日期准备三个字段。

<form id="Home" action="" method="POST">
    Day     <input id="Day" name="Day" value="" type="text" />
    Month   <input id="Month" name="Month" value="" type="text" />
    Year    <input id="Year" name="Year" value="" type="text" />    
            <input id="Submit" type="Submit" value="Submit" />
</form>

模型

在我的模型中,我将只为这三个字段有一个属性,名为 Date

public class HomePageModels
{
    public string Title { get; set; }
    public string Date { get; set; }
}

自定义绑定

自定义绑定类需要继承自 IModelBinder。在这里,我们捕获当前的请求并单独提取表单字段。然后,我们可以以任何方式操作这些字段。在这个例子中,如你所见,我将它们添加到一个名为 Date 的单个属性中。

public class HomeCustomBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, 
                            ModelBindingContext bindingContext)
    {
        HttpRequestBase request = controllerContext.HttpContext.Request;

        string title = request.Form.Get("Title");
        string day = request.Form.Get("Day");
        string month = request.Form.Get("Month");
        string year = request.Form.Get("Year");

        return new HomePageModels
                   {
                       Title = title,
                       Date = day +"/"+ month +"/"+ year
                   };
    }
} 

或者,如果我们不想为应用程序中的每个模型和属性都实现自定义绑定,我们可以继承自 DefaultModelBinder 并重写 BindModel 方法,如下所示

public class HomeCustomDataBinder : DefaultModelBinder
    {

        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(HomePageModels))
            {
                HttpRequestBase request = controllerContext.HttpContext.Request;

                string title = request.Form.Get("Title");
                string day = request.Form.Get("Day");
                string month = request.Form.Get("Month");
                string year = request.Form.Get("Year");

                return new HomePageModels
                {
                    Title = title,
                    Date = day + "/" + month + "/" + year
                };

                //// call the default model binder this new binding context
                //return base.BindModel(controllerContext, newBindingContext);
            }
            else
            {
                return base.BindModel(controllerContext, bindingContext);
            }
        }

    } 

完成自定义类的编码后,我们需要注册该类,我会在 Global.asaxApplication_Start() 下进行注册。

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterAuth();
    ModelBinders.Binders.Add(typeof(HomePageModels), new HomeCustomBinder());
}

控制器 (Controller)

最后,我们需要告知控制器要使用哪个绑定。我们可以使用属性 [ModelBinder(typeof(HomeCustomBinder))] 来指定,如下所示

[HttpPost]
public ActionResult Index([ModelBinder(typeof(HomeCustomBinder))] HomePageModels home)
{
    if (ModelState.IsValid)
    {
        ViewBag.Title = home.Title;
        ViewBag.Date = home.Date;
    }
    return View();
}

兴趣点 

虽然你可以认为我们可以通过在控制器内部手动捕获请求并操作属性填充方式来实现相同的功能,但使用自定义绑定的目的是为了促进重用,从而避免手动连接视图和模型。

© . All rights reserved.