【问题标题】:Binding parameter to complex type将参数绑定到复杂类型
【发布时间】:2019-05-12 03:17:58
【问题描述】:

我有一个导航栏,有几个链接,像这样:

<a href="MyController/Browse/2">MenuItem1</a>

这个请求会命中我的操作方法:

public ActionResult Browse(int departmentId)
{
    var complexVM = MyCache.GetComplexVM(departmentId);
    return View(complexVM);
}

这是我的ComplexVM

public class ComplexVM 
{
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
}

MyCache,是一个部门的静态列表,我保存在内存中,所以当用户传入DepartmentId时,我不需要从数据库中获取相应的DepartmentName

这工作正常...但是如果我能以某种方式在自定义模型绑定器中初始化ComplexVM,而不是在控制器中初始化它,那就太好了...所以我仍然想使用链接(菜单项) ,但这次CustomModelBinder将我的参数2绑定到ComplexVM:它需要从MyCache中查找id = 2的部门名称并初始化ComplexVM,然后ComplexVM将被传递到这个动作方法:

public ActionResult Browse(ComplexVM complexVM)
{
    return View(complexVM);
}

我想在不回发的情况下点击上述控制器,因为我的导航栏中有很多菜单项链接......不确定这是否可能?或者如果这甚至是一个好主意?

我见过this link,它描述了我想要什么...但我不确定路由将如何工作...即路由id:2 => ComplexVM


或者可以在RouteConfig 中执行此操作,如下所示:

routes.MapRoute(
    name: "Browse",
    url: "{controller}/Browse/{departmentId}",
    // this does not compile, just want to explain what I want...
    defaults: new { action = "Browse", new ComplexVM(departmentId) });

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-5 asp.net-mvc-routing model-binding


    【解决方案1】:

    我可以通过一点点改变和一个技巧来实现这一目标

    <a href="MyController/Browse?id=1">MenuItem1</a>
    

    控制器动作

    public ActionResult Browse(ComplexVM complexVM)
    {
    return View(complexVM);
    }
    

    查看模型

    public class ComplexVM
    {
        public int DepartmentId { get; set; }
        public string DepartmentName { get; set; }
        public ComplexVM()
        {
            this.DepartmentId = System.Convert.ToInt32(HttpContext.Current.Request("id").ToString);
            this.DepartmentName = "Your name from cache"; // Get name from your cache 
        }
    }
    

    这没有使用模型绑定器。技巧可能会有所帮助。

    【讨论】:

      【解决方案2】:

      这是可能的。这也是一个好主意 :) 将部分共享责任转移到模型/动作过滤器是很棒的。唯一的问题是因为他们使用了一些特殊的类来继承,测试它们有时可能比仅仅测试控制器稍微困难一些。一旦掌握了窍门,那就更好了。

      你的复杂模型应该是这样的

      // Your model class
      [ModelBinder(typeof(ComplexVMModelBinder)]
      public class ComplexVMModel
      {
         [Required]
         public int DepartmentId { get; set; }
      
         public string DepartmentName { get; set; }
      }
      
      // Your binder class
      public class ComplexVMModelBinder : IModelBinder
      {
           // Returns false if you can't bind.
           public bool BindModel(HttpActionContext actionContext, ModelBindingContext modelContext)
           {
               if (modelContext.ModelType != typeof(ComplexVMModel))
               {
                   return false;
               }
      
               // Somehow get the depid from the request - this might not work.
               int depId = HttpContext.Current.Request.Params["DepID"];
               // Create and assign the model.
               bindingContext.Model = new ComplexVMModel() { DepartmentName = CacheLookup(), DepId = depId };
      
               return true;
           }
      }
      

      然后在您的操作方法开始时,您检查 ModelState 以查看它是否有效。有一些事情可以使模型状态无效(比如没有[Required] 参数。)

      public ActionResult Browse(ComplexVM complexVM)
      {
          if (!ModelState.IsValid)
          {
              //If not valid - return some error view.
          }
      }
      

      现在你只需要注册这个 Model Binder。

      protected void Application_Start()
      {
          AreaRegistration.RegisterAllAreas();
          FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
          RouteConfig.RegisterRoutes(RouteTable.Routes);
          BundleConfig.RegisterBundles(BundleTable.Bundles);
          ModelBinders.Binders.Add(typeof(ComplexVMModel), new ComplexVMModelBinder());
      }
      

      您应该能够使用您提供的路由配置。

      【讨论】:

      • 感谢您的回答...我认为我的问题有点令人困惑...我有一个这样的链接:MenuItem ...我怎么能点击你从这个链接解释的控制器?
      • 还添加了 application_start 注册,只需在您的路由配置中使用默认值:new { action = "Browse" } 这应该可以工作
      • 但是这个条件不应该是假的吗? if (modelContext.ModelType != typeof(ComplexVMModel)) - 因为我传递的是 int 而不是 ComplexVM
      • 否 - 因为您明确绑定 ComplexVMModel。基本上你的方法正在接收一个 int 但它正在绑定一个不同的模型
      • 嗨 Mavi,再次感谢您的回答...您的回答很棒,我给了您一个 +1... 但它解释了自定义模型活页夹的工作原理...我的问题是关于将 int 绑定到 complexVM 而您的答案没有解释这一点...正如我之前提到的,我的 modelContext.ModelType != typeof(ComplexVMModel) 将不起作用,因为我传入的是 int 而不是 ComplexVm...
      猜你喜欢
      • 1970-01-01
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多