2011-06-01 89 views
9

我有一个自定义的ModelBinder,我想要得到的动作。因为我想使用反射来获取动作的属性,所以动作名称是不够的。Asp.NET MVC ModelBinder,获取操作方法

我的操作方法:

[MyAttribute] 
public ActionResult Index([ModelBinder(typeof(MyModelBinder))] MyModel model) 
{ 
} 

这里是典型的ModelBinder的

public class MyModelBinder : IModelBinder 
{ 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     // here i would like to get the action method and his "MyAttribute" 
    } 
} 

任何建议,其他的解决方案?

许多在此先感谢

+0

这是'MyAttribute'动作过滤器或一个普通的CLR属性?它的目的是什么?为什么你需要将它与模型绑定器绑在一起? – 2011-06-01 12:59:21

+0

是的,MyAttribute是一个CLR属性。我会用“信息”来签名该方法,因为没有办法用[ModelBinder(typeof(MyModelBinder))]传递参数。 – dknaack 2011-06-01 13:09:32

+0

@dknaack,有一种方法:您可以使用自定义模型联编程序提供程序。 – 2011-06-01 14:25:45

回答

4

不,你不能100%的把握得到一个模型绑定当前操作。模型联编程序不是耦合到动作,而是绑定到模型。例如,您可以拨打

TryUpdateMode(model) 

在选择动作之前的过滤器中。另外请注意,一个操作方法甚至可能不是CLR方法(参见http://haacked.com/archive/2009/02/17/aspnetmvc-ironruby-with-filters.aspx),可以反映出来。

我认为真正的问题是,你究竟想要完成什么,这是正确的方式?如果您希望将来自动作的信息传递给模型联编程序(如果信息不存在,请注意模型联编程序应优雅地降级的建议),则应使用动作筛选器将信息放入HttpContext.Items(或就像那样),然后让你的活页夹检索它。

一个动作过滤器的OnActionExecuting方法接收一个ActionExecutingContext,它具有一个ActionDescriptor。你可以调用GetCustomAttributes。

+0

非常感谢菲尔!我知道它没有耦合(使用System.Diagnostics.StackFrame看到它)。在评论中很难描述我想要做什么。我现在将在稍后使用ActionFilter和博客介绍我的解决方案。如果你感兴趣,我会通过twitter向你发送一个链接,如果我的博客文章完成了。 – dknaack 2011-06-01 16:10:01

1

你可以试试这个:

var actionName = controllerContext.RouteData.GetRequiredString("action"); 
var myAttribute = (MyAttribute) Attribute.GetCustomAttribute(controllerContext.Controller.GetMethod(actionName), typeof(MyAttribute)); 
+1

我之前尝试过。但是我可以有很多方法使用这个名字和不同的参数。所以“controllerContext.Controller.GetType()。GetMethod(actionName);”将导致一个System.Reflection.AmbiguousMatchException – dknaack 2011-06-01 12:47:36

+0

好吧,那么我不知道。对不起:) – Fabiano 2011-06-01 12:56:57

+0

当然,如果你的行为的签名只包含MyModel,你可以使用controllerContext.Controller.GetMethod(actionName,new [] {bindingContext.Model.GetType()});但是这可能不够用 – Fabiano 2011-06-01 13:02:15

0

您可以覆盖ControllerActionInvoker.FindAction()得到行动的属性,如这里所提到的,或延长ControllerContext.RequestContext其存储在HttpContext.Current.Items,如下:

public class MyControllerActionInvoker : ControllerActionInvoker 
{ 
    protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) 
    { 
     var action = base.FindAction(controllerContext, controllerDescriptor, actionName); 

     if (action != null) 
     { 
      var requestContext = ExtendedRequestContext.Bind(controllerContext); 
      var attr = action.GetCustomAttributes(typeof(MyAttribute), false).FirstOrDefault(); 

      if (attr != null) 
       requestContext.CustomAttribute = (MyAttribute)attr; 
     } 

     return action; 
    } 
} 

public class ExtendedRequestContext : RequestContext 
{ 
    public MyAttribute CustomAttribute { get; set; } 

    public static ExtendedRequestContext Bind(ControllerContext controllerContext) 
    { 
     var requestContext = new ExtendedRequestContext 
     { 
      HttpContext = controllerContext.RequestContext.HttpContext, 
      RouteData = controllerContext.RequestContext.RouteData 
     }; 

     controllerContext.RequestContext = requestContext; 
     return requestContext; 
    } 
} 

默认操作调用在控制器的构造函数或在更换或者自定义控制器厂:

public MyController() : base() 
{ 
    ActionInvoker = new MyControllerActionInvoker(); 
} 

顺便说一句,Controller.TempData已经包含ReflectedParameterDescriptor类型的项目,它使您可以访问ActionDescriptor,所以上面的代码可能是多余的。但是,请注意这是特定于实现的,因此可能随时间而改变。

最后,得到的是存储属性,在粘合剂类:

var requestContext = (ExtendedRequestContext)controllerContext.RequestContext; 
if (requestContext.CustomAttribute != null) 
{ 
    // apply your logic here 
}