2011-06-01 13 views
9

Özel bir ModelBinder aldım ve eylemi almak istiyorum. Yansıma kullanarak eylemin Niteliklerini almak istediğim için eylem adı yeterli değil.Asp.NET MVC ModelBinder, Eylem Metodu Başlarken

benim eylem yöntemi:

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

ve burada tipik ModelBinder

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

herhangi bir öneri, diğer çözümler? Bunu deneyebilirsiniz peşin

+0

bu 'bir eylem filtre veya düz CLR niteliğini MyAttribute' mı? Amacı nedir ve neden model bağlayıcı ile * bağlamanız gerekiyor? –

+0

Evet, MyAttribute bir CLR Özniteliğidir. [ModelBinder (typod (MyModelBinder))] ile argümanları iletmenin bir yolu olmadığından yöntemi "bilgiler" ile imzalardım. – dknaack

+0

@dknaack, bir yolu var: özel bir model binder sağlayıcısı kullanabilirsiniz. –

cevap

4

Hayır,% 100 kesinlikle bir modeli ciltteki güncel eylem alınamıyor. Model bağlayıcı eyleme değil, bir modele bağlanır. Örneğin, bir eylem seçildikten önce bir filtrede

numaralı telefonu arayabilirsiniz. Ayrıca, bir eylem yönteminin, yansıtılabilen bir CLR yöntemi (bkz. http://haacked.com/archive/2009/02/17/aspnetmvc-ironruby-with-filters.aspx) bile olmayabileceğini unutmayın.

Gerçek soru şu ki, tam olarak neyi başarmaya çalışıyorsunuz ve bu doğru yol mu? Eylemden bilgi binderine geçilmesini isterseniz (bilgi bülteni olmadığında model bağlayıcınızın incelikli bir şekilde küçültülmesi tavsiyesine uyarak), bilgileri HttpContext.Items içine koymak için bir eylem filtresi kullanmalısınız (veya Bunun gibi bir yere) ve daha sonra bağlayıcınızı almasını sağlayın.

Bir eylem filtresinin OnActionExecuting yöntemi, ActionDescriptor olan bir ActionExecutingContext alır. Bunun üzerine GetCustomAttributes'ı arayabilirsiniz.

+0

Çok teşekkürler Phil! Bunun birleştirilmiş olmadığını biliyorum (System.Diagnostics.StackFrame kullanarak gördüm). Bir yorumda yapmak istediğimi tanımlamak zor. Şimdi bir ActionFilter kullanarak yapacağım ve çözümüm hakkında daha sonra blog yazacağım. Eğer ilgilenirseniz, blog gönderim bittiyse Twitter üzerinden bir link gönderirim. – dknaack

1

yılında

çok teşekkürler:

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

daha önce denedim. Ama bu isimde ve farklı tartışmalarda birçok metodum olabilir. Yani "controllerContext.Controller.GetType(). GetMethod (actionName);" bir System.Reflection.AmbiguousMatchException – dknaack

+0

tamam, sonra hiçbir fikrim yok sonuçlanır. üzgünüz :) – Fabiano

+0

tabii ki eyleminizin imzası yalnızca MyModel içeriyorsa controllerContext.Controller.GetMethod (actionName, new [] {bindingContext.Model.GetType()}); Ama bu muhtemelen yeterli olmayacaktır – Fabiano

0

Aşağıdaki gibi, eylemin niteliğini almak ve burada belirtilen veya ControllerContext.RequestContext genişletilmiş olarak HttpContext.Current.Items depolamak için ControllerActionInvoker.FindAction() geçersiz olabilir:

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

varsayılan eylem invoker sizin kontrolörün Oluşturucu veya bir ya değiştirilir özel kontrolörleri fabrika: Bu arada

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

, Controller.TempData zatenerişim sağlar ReflectedParameterDescriptor tür bir öğe içerir, dolayısıyla yukarıdaki kod gereksiz olabilir. Ancak, bunun uygulamaya özgü olduğunu unutmayın, bu nedenle zamanla değişebilir.

Son olarak, bağlayıcı sınıfında o depodan niteliği olsun:

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