2017-10-12 3 views
2

J'essaie d'obtenir la balise Attribute d'un contrôleur API afin que je puisse voir quel verbe HTTP il autorise à l'exécution. De l'exemple de code ci-dessous, je veux être en mesure d'obtenir le tag [HttpGet].Récupère la balise Attribute d'une méthode de contrôleur dans MVC?

[HttpGet] 
public void MyResource() 
{ 
    // Controller logic 
} 

J'utilise actuellement System.Reflection pour recueillir d'autres informations sur mon API en cours d'exécution, mais jusqu'à présent, je suis incapable de récupérer la balise [HttpGet et d'autres Http balises de verbe. J'ai essayé chacune des solutions ci-dessous sans succès:

public void GetControllerMethodHttpAttribute() 
{ 
    MethodInfo controllerMethod = typeof(TestController).GetMethods().First(); 

    // Solution 1 
    var attrs = controllerMethod.Attributes; 

    // Solution 2 
    var httpAttr = Attribute.GetCustomAttributes(typeof(HttpGetAttribute)); 

    // Solution 3 
    var httpAttr2 = Attribute.GetCustomAttribute(controllerMethod, typeof(HttpGetAttribute)); 

    // Solution 4 
    var httpAttr3 = Attribute.IsDefined(controllerMethod, typeof(HttpGetAttribute)); 
} 

Toutes les questions précédentes que j'ai fait des recherches sur ce sujet uniquement lié à Custom Attribute tags et en tirant les valeurs de ceux-ci, mais je ne pouvais pas trouver toute information sur l'obtention du cadre inclus Attribute tags.

Est-ce que quelqu'un sait comment je peux obtenir l'étiquette d'attribut [HttpGet]?

Merci!

+0

Avez-vous besoin de "cette action prend en charge get/post/etc", ou les informations complètes à l'intérieur des attributs (ordre, template, etc)? – gunr2171

+1

Avez-vous vérifié que 'typeof (TestController) .GetMethods(). First()' renvoie la méthode attendue? – thehennyy

+0

@ gunr2171 l'information complète serait préférable, mais le plus important, je veux être en mesure de dire quels verbes chaque méthode prend en charge. –

Répondre

3

Les solutions proposées 3 et 4 fonctionnent.

Vous devez vérifier que vous référencez le bon HttpGetAttribute. Il y en a un au System.Web.Http.HttpGetAttribute et il y en a un au System.Web.Mvc.HttpGetAttribute.

Le code suivant répertorie les méthodes publiques du contrôleur API ValuesController avec les informations indiquant si elles possèdent des attributs HttpGet ou HttpPost.

var methods = typeof(ValuesController).GetMethods(); 
string infoString = ""; 

foreach(var method in methods) 
{ 
    // Only public methods that are not constructors 
    if(!method.IsConstructor && method.IsPublic) 
    { 
     // Don't include inherited methods 
     if(method.DeclaringType == typeof(ValuesController)) 
     { 

      infoString += method.Name; 

      if(Attribute.IsDefined(method, typeof(System.Web.Http.HttpGetAttribute))) 
      { 
       infoString += " GET "; 
      } 
      if(Attribute.IsDefined(method, typeof(System.Web.Http.HttpPostAttribute))) 
      { 
       infoString += " POST "; 
      } 


      infoString += Environment.NewLine; 
     } 
    } 
} 

Vous devez échanger avec System.Web.Http.System.Web.Mvc. lorsque le contrôleur est un contrôleur MVC au lieu d'un contrôleur API.

+0

Merci beaucoup! Je n'ai pas réalisé qu'il y avait deux espaces de noms avec le même nom d'attribut. –

1

Voilà comment je fini par le faire:

public static IEnumerable<Attribute> GetSupportedVerbsForAction<T>(
    Expression<Func<T, IActionResult>> expression) 
    where T : Controller 
{ 
    //only consider a list of attributes 
    var typesToCheck = new[] { typeof(HttpGetAttribute), typeof(HttpPostAttribute), 
     typeof(HttpPutAttribute), typeof(HttpDeleteAttribute), typeof(HttpPatchAttribute)}; 

    var method = ((MethodCallExpression)expression.Body).Method; 

    var matchingAttributes = typesToCheck 
     .Where(x => method.IsDefined(x)) 
     .ToList(); 

    //if the method doesn't have any of the attributes we're looking for, 
    //assume that it does all verbs 
    if (!matchingAttributes.Any()) 
     foreach(var verb in typesToCheck) 
      yield return verb; 

    //else, return all the attributes we did find 
    foreach (var foundAttr in matchingAttributes) 
    { 
     yield return method.GetCustomAttribute(foundAttr); 
    } 
} 

Supposons que vous avez le contrôleur et les actions suivantes:

public class HomeController : Controller 
{ 
    // implicit get 
    public IActionResult Index() => View(); 

    // explicit get 
    [HttpGet] 
    public IActionResult GetAction() => View(); 

    // extra info 
    [HttpPost(Name = "some name", Order = 5)] 
    public IActionResult PostAction() => View(); 

    [HttpPut] 
    [HttpDelete] 
    [HttpPatch("my template", Name = "patch name", Order = 333)] 
    public IActionResult MultiAction() => View(); 
} 

Vous pouvez les appeler comme ceci:

var indexVerbs = GetSupportedVerbsForAction<HomeController>(x => x.Index()).ToList(); 
var getVerbs = GetSupportedVerbsForAction<HomeController>(x => x.GetAction()).ToList(); 
var postVerbs = GetSupportedVerbsForAction<HomeController>(x => x.PostAction()).ToList(); 
var multiVerbs = GetSupportedVerbsForAction<HomeController>(x => x.MultiAction()).ToList(); 

Cela renverra l'attribut complet que vous avez défini au cas où vous J'ai ajouté des données personnalisées.

enter image description here

Deux choses à noter:

  1. Vous aurez besoin de fournir des paramètres à l'appel de fonction. Ils n'ont pas besoin d'être valides car la méthode elle-même ne sera pas appelée, mais je n'ai pas compris comment vous permettre de faire GetSupportedVerbsForAction<HomeController>(x => x.Index).
  2. La méthode passera en revue une liste de Attribute, utilisez le mot-clé is pour savoir si c'est le type que vous voulez.
+0

J'ai peut-être tort, mais je pensais que si elle n'avait pas d'attributs, cela signifierait qu'elle accepterait n'importe quoi, pas seulement? – Chris

+0

@Chris Nope, la valeur par défaut est GET: http://www.tutorialsteacher.com/mvc/actionverbs-in-mvc. Voici un peu [meilleur lien] (https://forums.asp.net/t/1928761.aspx?What+is+default+http+verb+for+action+method), mais je suis toujours à la recherche de documentation officielle . – gunr2171

+0

https://stackoverflow.com/questions/11767911/mvc-httppost-httpget-for-action est une question de dépassement de pile pertinente. Comme vous pouvez le voir à partir des tests (et pris en charge par la documentation https://msdn.microsoft.com/en-us/library/system.web.mvc.httpgetattribute(v=vs.118).aspx), l'attribut restreint ce est autorisée. Sans attribut, il n'y a pas de restauration. Je soupçonne dans le cas de cet exemple que vous avez lié que MVC est assez intelligent pour dire si on est libre et que l'on est post seulement alors si c'est un post alors utilisez le post plus restreint seulement. – Chris