将参数绑定到复杂类型
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
}
}
这没有使用模型活页夹。技巧可能会有所帮助。
我有一个导航栏,有几个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
}
}
这没有使用模型活页夹。技巧可能会有所帮助。