use*_*457 4 asp.net-mvc model-binding asp.net-mvc-4
ASP.NET MVC(MVC4)中是否有任何有用的钩子可以让您在调用操作方法之前访问Action方法参数(View模型),然后还可以(例如,取决于您在操作方法中检查的内容的值)参数)让你阻止调用动作方法,即将视图模型对象(动作方法参数)转发到另一个动作方法或直接转发到某个视图(即动作方法中没有任何进一步处理)?
如果您不理解这个问题,请参阅下面的代码示例,它应该说明我正在寻找的代码类型...(虽然我不知道是否确实存在这样的接口并且可能将实现挂钩到MVC框架)
如果这确实可行,我想看一个关于如何做到的代码示例的答案(而不仅仅是对某人声称例如"尝试使用方法'ActionFilterAttribute.OnActionExecuting'或'IModelBinder.BindModel'的响应",因为我已经尝试过这些并且无法使其工作).另外,请尊重我不希望这个帖子成为关于为什么这样做的讨论,但是想看看如何做到这一点.(即我不想与诸如"你究竟想要实现什么?"或"你想做什么可能更好的事情......"这样的回答进行讨论.)
这个问题可以分成三个子问题/代码示例,下面我自己的代码示例试图说明:(但希望它们"重构"为使用真实存在类型的REAL代码)(显然,下面包含子字符串的每个类型)一些"是我已经弥补的东西,我正在寻找相应的真实......"
(1)在使用视图模型对象参数调用实际操作方法之前,如何在通用位置访问(并可能修改)视图模型对象(操作方法参数)的示例.
我正在寻找的那种代码示例可能类似于下面但不知道使用什么类型的接口以及如何注册它以便能够执行以下操作:
public class SomeClass: ISomeInterface { // How to register this kind of hook in Application_Start ?
public void SomeMethodSomewhere(SomeActionMethodContext actionMethodContext, object actionMethodParameterViewModel) {
string nameOfTheControllerAboutToBeInvoked = actionMethodContext.ControllerName;
string nameOfTheActionMethodAboutToBeInvoked = actionMethodContext.MethodName;
// the above strings are not used below but just used for illustrating that the "context object" contains information about the action method to become invoked by the MVC framework
if(typeof(IMyBaseInterfaceForAllMyViewModels).IsAssignableFrom(actionMethodParameterViewModel.GetType())) {
IMyBaseInterfaceForAllMyViewModels viewModel = (IMyBaseInterfaceForAllMyViewModels) actionMethodParameterViewModel;
// check something in the view model:
if(viewModel.MyFirstGeneralPropertyInAllViewModels == "foo") {
// modify something in the view model before it will be passed to the target action method
viewModel.MySecondGeneralPropertyInAllViewModels = "bar";
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
(2)如何防止执行目标操作方法的示例,而是调用另一个操作方法.该示例可能是上述示例的扩展,如下所示:
public void SomeMethodSomewhere(SomeActionMethodContext actionMethodContext, object actionMethodParameterViewModel) {
... same as above ...
if(viewModel.MyFirstGeneralPropertyInAllViewModels == "foo") {
actionMethodContext.ControllerName = "SomeOtherController";
actionMethodContext.MethodName = "SomeOtherActionMethod";
// The above is just one example of how I imagine this kind of thing could be implemented with changing properties, and below is another example of doing it with a method invocation:
SomeHelper.PreventCurrentlyTargetedActionMethodFromBecomingExecutedAndInsteadExecuteActionMethod("SomeOtherController", "SomeOtherActionMethod", actionMethodParameterViewModel);
// Note that I do _NOT_ want to trigger a new http request with something like the method "Controller.RedirectToAction"
}
Run Code Online (Sandbox Code Playgroud)
(3)如何防止执行正常动作方法的示例,而是将视图模型对象直接转发到视图而不进行任何进一步处理.
该示例将是上面第一个示例的扩展,如下所示:
public void SomeMethodSomewhere(SomeActionMethodContext actionMethodContext, object actionMethodParameterViewModel) {
... same as the first example above ...
if(viewModel.MyFirstGeneralPropertyInAllViewModels == "foo") {
// the below used razor view must of course be implemented with a proper type for the model (e.g. interface 'IMyBaseInterfaceForAllMyViewModels' as used in first example above)
SomeHelper.PreventCurrentlyTargetedActionMethodFromBecomingExecutedAndInsteadForwardViewModelToView("SomeViewName.cshtml", actionMethodParameterViewModel);
}
Run Code Online (Sandbox Code Playgroud)
您可以使用操作过滤器并覆盖OnActionExecuting事件:
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们看看您可以从filterContext传递给此方法的参数中提取哪些有用的信息.您应该寻找的属性被称为ActionParameters并代表一个IDictionary<string, object>.顾名思义,此属性包含通过名称和值传递给控制器操作的所有参数.
所以我们假设您有以下控制器操作:
[MyActionFilter]
public ActionResult Index(MyViewModel model)
{
...
}
Run Code Online (Sandbox Code Playgroud)
以下是在模型绑定后检索视图模型的值的方法:
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var model = filterContext.ActionParameters["model"] as MyViewModel;
// do something with the model
// You could change some of its properties here
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们看看你问题的第二部分.如何将控制器动作短路并重定向到另一个动作?
这可以通过为Result属性赋值来完成:
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
... some processing here and you decide to redirect:
var routeValues = new RouteValueDictionary(new
{
controller = "somecontroller",
action = "someaction"
});
filterContext.Result = new RedirectToRouteResult(routeValues);
}
}
Run Code Online (Sandbox Code Playgroud)
或者例如,您决定短路控制器操作的执行并直接呈现视图:
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var viewResult = new ViewResult
{
ViewName = "~/Views/FooBar/Baz.cshtml",
};
MyViewModel someModel = ... get the model you want to pass to the view
viewResult.ViewData.Model = model;
filterContext.Result = viewResult;
}
}
Run Code Online (Sandbox Code Playgroud)
或者您可能决定呈现JSON结果:
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
MyViewModel someModel = ... get the model you want to pass to the view
filterContext.Result = new JsonResult
{
Data = model,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
Run Code Online (Sandbox Code Playgroud)
因此,您可以看到可能性无限的可能性.
| 归档时间: |
|
| 查看次数: |
5307 次 |
| 最近记录: |