• .NET MVC学习之模型绑定


    ASP.NET MVC学习之模型绑定(2)

     

    ASP.NET MVC学习之模型绑定继续

    3.手工调用模型绑定

    很多情况下我们都是通过形参的方式接收来自http流中的数据,这看似是完美的,但是缺少了很多过程中的控制,所以我们就需要使用手工的方式进行绑定。下面我们通过一个例子来说明,首先打开Views/Home/Index.cshtml页面,并输入如下代码:

    复制代码
     1 @{
     2     ViewBag.Title = "Index";
     3 }
     4 
     5 @if (TempData.ContainsKey("msg"))
     6 {
     7     <h1>
     8         @TempData["msg"].ToString()
     9     </h1>
    10 }
    11 
    12 @using (Html.BeginForm())
    13 {
    14     <input type="text" name="id" />
    15     <input type="submit" value="submit" />
    16 }
    复制代码

    接着打开HomeController并写入如下代码(关于ActionName可以点击这进行参考):

    复制代码
     1 namespace MvcStudy.Controllers
     2 {
     3     public class HomeController : Controller
     4     {
     5         private class TestA
     6         {
     7             public String id { get; set; }
     8         }
     9 
    10         public ActionResult Index()
    11         {
    12             return View();
    13         }
    14 
    15         [HttpPost]
    16         [ActionName("Index")]
    17         public ActionResult IndexPost()
    18         {
    19             TestA ta = new TestA();
    20             UpdateModel(ta);
    21             TempData["msg"] = ta.id;
    22             return View();
    23         }
    24     }
    25 }
    复制代码

    这里我们通过UpdateModel进行手动绑定,最终的结果和采用形参的方式相同,读者可以进行测试可以发现输入的值都显示了,但是读者一定会奇怪,因为TestA中的id不仅仅存在于表单,同时还存在与RouteData中以及查询字符串中,我们可以用?id=123来测试这个页面可以发现并不会修改最终结果,而通过手动调用模型绑定的优点之一就是我们可以控制数据来源,比如我们修改HomeController代码如下所示:

    复制代码
    1         [HttpPost]
    2         [ActionName("Index")]
    3         public ActionResult IndexPost()
    4         {
    5             TestA ta = new TestA();
    6             UpdateModel(ta,new FormValueProvider(ControllerContext));
    7             TempData["msg"] = ta.id;
    8             return View();
    9         }
    复制代码

    这里我们可以发现我们给UpdateModel传递了第二个参数,FormValueProvider这表示数据源只能来自于表单中,同样我们还可以修改成RouteDataValueProvider或者QueryStringValueProvider,具体的效果读者你自行替换之后,输入http://localhost:1201/Home/Index/123?id=asdsad测试,可以看看最后显示的内容是不是来自于我们指定的来源。再使用形参的方式中我们有时会遇到http流中不存在我们需要的值,并且这个形参的类型不能为null,或者我们不希望它为null,这个时候就会出现异常或者赋值为null,而通过UpdateModel则可以通过try…catch…的形式捕获InvalidOperationException异常从而手动处理,如果读者不希望通过这种方式也可以像下面这种形式来处理:

    复制代码
    1             if (TryUpdateModel(ta, new QueryStringValueProvider(ControllerContext)))
    2             {
    3                 //正确时的操作
    4             }
    5             else
    6             {
    7                 //异常时的操作
    8             }
    复制代码

    这样我们只要通过if判断即可。

    4.自定义值提供器

    通过上面的我们发现ASP.NET MVC自带的模型绑定器已经提供了很多我们所需要的功能,但是有时候我们想某些值不是来自于http流中而是我们自己来填充的,那么这节知识会让你感兴趣,因为下面我们将要自定义一个值提供器来完成我们的需求。首先介绍需要用的接口和类,首先是IValueProvider接口:

     View Code

    namespace System.Web.Mvc
    {
    // 摘要:
    // 定义 ASP.NET MVC 中的值提供程序所需的方法。
    public interface IValueProvider
    {
    // 摘要:
    // 确定集合是否包含指定的前缀。
    //
    // 参数:
    // prefix:
    // 要搜索的前缀。
    //
    // 返回结果:
    // 如果集合包含指定的前缀,则为 true;否则为 false。
    bool ContainsPrefix(string prefix);
    //
    // 摘要:
    // 使用指定键来检索值对象。
    //
    // 参数:
    // key:
    // 要检索的值对象的键。
    //
    // 返回结果:
    // 指定的键的值对象。
    ValueProviderResult GetValue(string key);
    }
    }

    其中ContainsPrefix用来判断这个值的前缀是不是我们能够处理的(因为ASP.NET MVC其实自带了很多这种值提供器,最后会通过循环调用的方式调用这些提供器,直到有一个返回值。)然后就是GetValue方法就是返回对应的值了,当然光有这个还不够,还需要一个工厂去创建它,以提供调用,这个类就是ValueProviderFactory,而我们仅仅只需要实现GetValueProvider方法即可,其实就是new一个值提供器并返回,当然你也可以通过这个方法的ControllerContext从而有选择性的返回一个值提供器,下面我们简单的举一个例子来处理ns

    首先我们创建一个Provider文件夹,然后新建一个NSValueProvider类并在文件中写入如下代码:

    复制代码
     1 namespace MvcStudy.Provider
     2 {
     3     public class NSValueProvider : IValueProvider
     4     {
     5 
     6         public bool ContainsPrefix(string prefix)
     7         {
     8             return String.Compare("ns", prefix, true) == 0;
     9         }
    10 
    11         public ValueProviderResult GetValue(string key)
    12         {
    13             if (ContainsPrefix(key))
    14             {
    15                 return new ValueProviderResult("from ns", null, CultureInfo.InvariantCulture);
    16             }
    17             return null;
    18         }
    19     }
    20 
    21     public class NSValueProviderFactory : ValueProviderFactory
    22     {
    23         public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    24         {
    25             return new NSValueProvider();
    26         }
    27     }
    28 }
    复制代码

    最后打开Global.asax将它注册:

    1 ValueProviderFactories.Factories.Insert(0, new NSValueProviderFactory());

    最后我们需要修改HomeController以便能够看到结果:

    1         public ActionResult Index(string ns)
    2         {
    3             TempData["msg"] = ns;
    4             return View();
    5         }

    重新编译之后刷新页面我们就可以看到如下的结果:

    这样我们就完成了一个值提供器了,看到这个读者一定会想模型提供器怎么去自定义呢,其实模型绑定器就是依靠这些值提供器完成的,大家想想就可以明白了。

    5.模型绑定器

    模型绑定器跟值提供器很相似,只是需要做的工作比较多,因为你要负责将一个类的属性填充,所以比较麻烦。下面是需要实现的接口IModelBinder:

    复制代码
     1 namespace System.Web.Mvc
     2 {
     3     // 摘要:
     4     //     定义模型联编程序所需的方法。
     5     public interface IModelBinder
     6     {
     7         // 摘要:
     8         //     使用指定的控制器上下文和绑定上下文将模型绑定到一个值。
     9         //
    10         // 参数:
    11         //   controllerContext:
    12         //     控制器上下文。
    13         //
    14         //   bindingContext:
    15         //     绑定上下文。
    16         //
    17         // 返回结果:
    18         //     绑定值。
    19         object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
    20     }
    21 }
    复制代码

    这里重点是bindingContext参数,里面包含了很多绑定所需要的值和方法,下面我们举一个简单的例子,就是自定义一个模型绑定器负责绑定如下类:

    1         public class TestA
    2         {
    3             public String id { get; set; }
    4         }

    同时还要规定只能通过namens.id获取值,并不会根据参数的名称去获取,下面就是我们实现接口的代码:

    复制代码
     1 namespace MvcStudy.Provider
     2 {
     3     public class NSModelBinder : IModelBinder
     4     {
     5 
     6         public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
     7         {
     8             TestA a = (TestA)bindingContext.Model ?? new TestA();
     9             bool isHave = bindingContext.ValueProvider.ContainsPrefix("ns.id");
    10             if (isHave)
    11             {
    12                 a.id = bindingContext.ValueProvider.GetValue("ns.id").AttemptedValue;
    13             }
    14             else
    15             {
    16                 a.id = "asd";
    17             }
    18             return a;
    19         }
    20     }
    21 }
    复制代码

    最后一步当然还是需要注册(Global.asax):

    1 ModelBinders.Binders.Add(typeof(MvcStudy.Controllers.HomeController.TestA), new NSModelBinder());

    然后我们重新编译,并在页面中输入值并提交,可以发现TestAid并不是我们输入的值而是模型绑定器中的值,但是如果我们将Views/Home/Index.cshtml中的文本框的name改成ns.id之后,我们再输入值,最后显示的就是我们输入的值了,由此可以看出来模型绑定器是依赖于值提供器的。

    至此关于模型绑定的部分就结束了,下面我们将开始学习模型验证。

    在满足必要的经济的条件下,研究更佳高深的技术.满足自己的野心
     
    分类: ASP.NET MVCC#
    标签: C#asp net mvcmodel
  • 相关阅读:
    python 元组及操作
    python 字典所有操作
    python 列表操作
    python 运算符
    python while循环
    python 分支语句 等值判断 逻辑运算符
    GDI+_从Bitmap里得到的Color数组值分解
    服务器设计策略
    服务器设计策略
    IOCP的缓冲区
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3754044.html
Copyright © 2020-2023  润新知