• Asp.net MVC的Model Binder工作流程以及扩展方法(2)


    上篇文章中分析了Custom Binder的弊端: 由于Custom Binder是和具体的类型相关,比如指定类型A由我们的Custom Binder解析,那么导致系统运行中的所有Action的访问参数,只要是类型A, 都会使用Custom Binder. 这篇文章将会介绍Binder Attribute方式扩展MVC的Model Binder, 这种方式更加的灵活和可操控。

    本篇文章参考了ModelBinder——ASP.NET MVC Model绑定的核心, 结合Artech的这篇文章,对于MVC的Model Binder一定能够理解的更加深刻。

    阅读目录:

    一. Asp.net MVC Model Binder的源码分析

    二. Model Binder的优先顺序以及扩展点

    三. 自定义Binder Attribute - SessionUserBinderAttribute

    四. 应用SessionUserBinderAttribute

    五. 总结

    一,Asp.net MVC Model Binder的源码分析

    在实际使用Binder Attribute之前,我们先来看看Model Binder在MVC中是如何工作的。

    1.1  首先, 在MVC中, 当一个请求发送到服务器,先是要经过Route匹配, 找到对应的Controller和Action, 然后才是构建Action中的参数,也就是Model Binder的过程。这个可以从MVC的源码, ControllerActionInvoker中看出来。
    在ControllerActionInvoker.cs的函数GetParameterValue函数中,调用了GetModelBinder方法来获取构建该Action参数的Binder.

    1.2 GetModelBinder方法,将会优先使用ParameterDescriptor描述中指定的Binder。这是本篇文章介绍的Model Binder扩展点 -- 为Action参数指定Binder.

    1.3 在ParameterDescriptor没有指定Binder的情况下,按照这个优先顺序获取Binder

      a. 从BinderProvoder中获取
          b. 从global table中获取.  第一篇中的Custom Model Binder就是这里的扩展,定义一个Model Binder注册到global table中
          c. 从参数类型Attribute上指定的Binder获取。参数类型定义类的定义处,也可以使用Binder Attribute,指定该类的Action参数由指定的Binder处理。
          d. 使用MVC默认的Default Binder

    blog-justrun1983

    二,Model Binder的优先顺序以及扩展点

    从上面MVC中Model Binder的源代码分析中,可以知道,参数如何构建取决于Binder,而获取Binder的源的优先顺序是:

    1. PrameterDescriptor
    2. Binder Provider
    3. Global table
    4. 参数类型定义的Binder Attribute
    5. MVC的DefaultBinder

    所以Model Binder的扩展点也是上面5处, 第一篇文章中介绍的是扩展点3, 这篇中介绍的是扩展点1, 下篇文章中,将会介绍扩展点5,也就是DefaultBinder.

    三,自定义Binder Attribute - SessionUserBinderAttribute

    还是以解决上篇文章中的Session依赖问题为入手。我们定义SessionUserBinderAttribute 继承自CustomModelBinderAttribute,重写方法GetBinder(),该Binder将从Session中获取值来构建Action参数。

    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] 
    public class SessionUserBinderAttribute : CustomModelBinderAttribute 
    { 
           public override IModelBinder GetBinder() 
           { 
               return new UserAccountModelBinder(); 
           } 
    }
    
    public class UserAccountModelBinder : IModelBinder 
    { 
           public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
           { 
               if (controllerContext.HttpContext.Session["UserAccuont"] != null) 
               { 
                   return controllerContext.HttpContext.Session["UserAccuont"]; 
               } 
               return null; 
           } 
    }

    四,应用SessionUserBinderAttribute

    使用我们的SessionUserBinderAttribute改造Index方法

    原有的Index方法是这样的:

    public ActionResult Index() 
    { 
              var user = Session["UserAccuont"] as UserAccount; //从Session中获取当前登录用户的信息 
              //send email 
              var email = user.Email; 
              return new EmptyResult(); 
    }

    改造后的函数如下, 使用SessionUserBinder指定user参数的值,是从session中获取。

    public ActionResult Index([SessionUserBinder]UserAccount user) 
    { 
               //send email 
               var email = user.Email; 
               return new EmptyResult(); 
    }

    同时, 如果在新增一个UserAccount表单提交的时候,由于没有使用SessionUserBinderAttribute, 该useraccount将会由MVC中的DefaultBinder处理,也就是从form中提取值。

    [HttpPost] 
    public ActionResult Create(UserAccount useraccount) 
    { 
        return View(); 
    }

    五,总结

    这篇文章中,介绍了MVC中的model binder流程,以及罗列了model binder中5个的扩展点:

    1. PrameterDescriptor
    2. Binder Provider
    3. Global table
    4. 参数类型定义的Binder Attribute
    5. MVC的DefaultBinder

    其中这篇文章涉及的是扩展点1.
    扩展点2 Artech的文章ModelBinder——ASP.NET MVC Model绑定的核心中有介绍。
    扩展点3在文章Asp.net MVC的Model Binder工作流程以及扩展方法(1) - Custom Model Binder中 
    扩展点4也是利用Binder Attribute,不同的地方是,它关联的不是参数,而是类型定义。作用和扩展点3范围一样,不在写文章展开。
    扩展点5是MVC中的DefaultBinder, 下篇文章中,将会详细介绍。

    Custom Model Binder是以类型指定binder, 我们比喻为全火力覆盖,这里介绍的CustomModelBinderAttribute可以达到定点清除的效果,也就是只有我指定的参数才由特定的binder处理。理解两者应用范围的不同,有助于我们选择使用哪种方式扩展。

  • 相关阅读:
    工作总结系列---【端口被占用,如何取消端口进程】
    封装工具系列---【封装H5页面管理机构和证件类型下拉框数据处理的方法】
    工作总结系列---【vue页面实现导出表格效果】
    vscode---【内网开发下,离线安装vscode插件vsix文件】
    工作总结系列---【IDE深色背景下,鼠标移动也变成黑色,看不清怎么解决???】
    node系列---【为什么要设置镜像源?怎么配置?】
    git系列---【如何在本地修改别人的代码图解】
    git系列---【git如何回退到上一个版本??】
    封装工具系列---【补零操作】
    封装的各类工具系列---【时间格式化为YYYY-MM-DD格式 】
  • 原文地址:https://www.cnblogs.com/JustRun1983/p/3627549.html
Copyright © 2020-2023  润新知