【问题标题】:Get the Attribute tag from a Controller Method in MVC?从 MVC 中的控制器方法获取属性标记?
【发布时间】:2017-10-12 15:30:59
【问题描述】:

我正在尝试从 API 控制器获取属性标记,以便我可以查看它在运行时允许的 HTTP 动词。从下面的示例代码中,我希望能够获得[HttpGet] 标签。

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

我目前正在使用System.Reflection 在它运行时收集有关我的 API 的其他信息,但到目前为止我无法检索到 [HttpGet 标记和其他 Http 动词标记。我已经尝试了以下每个解决方案,但都没有成功:

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

我之前研究过的关于这个主题的所有问题都只与Custom Attribute tags 相关并从中提取值,但我找不到任何有关获取包含框架的Attribute tags 的信息。

有人知道我如何获得[HttpGet] 属性标签吗?

谢谢!

【问题讨论】:

  • 你需要“这个动作支持get/post/etc”,还是属性里面的完整信息(订单、模板等)?
  • 你确认typeof(TestController).GetMethods().First()返回了预期的方法吗?
  • @gunr2171 最好提供完整信息,但最重要的是我希望能够说出每种方法支持哪些动词。
  • @thehennyy 该行是对我的应用程序实际操作的简化。我有一段更大的代码,它从给定的控制器类中检索所有方法并遍历每个方法;所以我的实际代码无疑会遇到一个带有Http 标签的方法
  • 解决方案 3 适合我。

标签: c# asp.net-mvc reflection


【解决方案1】:

建议的解决方案 3 和 4 有效。

您必须注意您引用的是正确的HttpGetAttributeSystem.Web.Http.HttpGetAttribute 有一个,System.Web.Mvc.HttpGetAttribute 有一个。

以下代码列出了ValuesController API 控制器的公共方法以及它们是否具有 HttpGet 或 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;
        }
    }
}

当控制器是 MVC 控制器而不是 API 控制器时,您需要将 System.Web.Http.System.Web.Mvc. 交换。

【讨论】:

  • 非常感谢!我没有意识到有两个名称空间具有相同的属性名称。
【解决方案2】:

这就是我最终这样做的方式:

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

假设您有以下控制器和操作:

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

你可以这样称呼他们:

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();

这将返回您设置的 full 属性,以防您添加了任何自定义数据。

需要注意的两点:

  1. 您需要为函数调用提供参数。它们不需要有效,因为方法本身不会被调用,但我不知道如何让你做GetSupportedVerbsForAction&lt;HomeController&gt;(x =&gt; x.Index)
  2. 该方法将传回Attribute 的列表,因此请使用is 关键字来确定它是否是您想要的类型。

【讨论】:

  • 我可能错了,但我想如果它没有属性意味着它会接受任何东西,而不仅仅是 get?
  • @Chris 不,默认是 GET:tutorialsteacher.com/mvc/actionverbs-in-mvc。这里稍微better link,不过我还在找官方文档。
  • stackoverflow.com/questions/11767911/… 是一个相关的堆栈溢出问题。正如您从测试中看到的(并由文档 msdn.microsoft.com/en-us/library/… 支持),该属性限制了允许的内容。没有属性就没有限制。我怀疑在您链接的那个示例的情况下,MVC 足够聪明,可以说如果一个是不受限制的,一个是仅发布的,那么如果它是一个帖子,那么只使用一个更受限制的帖子。
  • @Chris 是的,听起来你是对的。在这种情况下,您只需返回所有属性,而不是返回一个 GET 属性。
猜你喜欢
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 2017-10-29
  • 1970-01-01
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多