将参数绑定到复杂类型

Binding parameter to complex type

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

<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来自 DB.

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

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

我想在不执行 post-back 的情况下点击上面的控制器,因为我的导航栏中有很多菜单项 links...不确定这是否可行?或者这是否是个好主意?

我已经看到 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) });

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

您的复杂模型应该如下所示

// 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());
}

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

我可以用一点点改变和一个技巧来实现这个

<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 
    }
}

这没有使用模型活页夹。技巧可能会有所帮助。