![](/img/trans.png)
[英]How to check if method has an attribute with Castle Interceptor?
[英]How to check if method has an attribute
我有一個例子課
public class MyClass{
ActionResult Method1(){
....
}
[Authorize]
ActionResult Method2(){
....
}
[Authorize]
ActionResult Method3(int value){
....
}
}
現在我要寫的是一個返回true / false的函數,可以像這樣執行
var controller = new MyClass();
Assert.IsFalse(MethodHasAuthorizeAttribute(controller.Method1));
Assert.IsTrue(MethodHasAuthorizeAttribute(controller.Method2));
Assert.IsTrue(MethodHasAuthorizeAttribute(controller.Method3));
我說到了
public bool MethodHasAuthorizeAttribute(Func<int, ActionResult> function)
{
return function.Method.GetCustomAttributes(typeof(AuthorizeAttribute), false).Length > 0;
}
適用於Method3。 現在,我該如何以將字符串和類也作為參數的方式來實現該泛型?
您的代碼的問題是public bool MethodHasAuthorizeAttribute(Func<int, ActionResult> function)
的簽名。 MethodHasAuthorizeAttribute
只能與與您指定的委托的簽名匹配的參數一起使用。 在這種情況下,方法將返回帶有int
類型參數的ActionResult
。
當像MethodHasAuthorizeAttribute(controller.Method3)
這樣調用此方法時,編譯器將執行方法組轉換。 這可能並不總是需要的,並且可能會產生意想不到的結果(方法組轉換並不總是很簡單)。 如果嘗試調用MethodHasAuthorizeAttribute(controller.Method1)
,則將發生編譯器錯誤,因為沒有任何轉換。
可以使用表達式樹和著名的“ MethodOf”技巧來構建更通用的解決方案。 它使用編譯器生成的表達式樹來找到調用目標:
public static MethodInfo MethodOf( Expression<System.Action> expression )
{
MethodCallExpression body = (MethodCallExpression)expression.Body;
return body.Method;
}
您可以像這樣使用它,但是它也可以與任何方法一起使用:
MethodInfo method = MethodOf( () => controller.Method3( default( int ) ) );
有了這些,我們可以構建一個通用的實現:
public static bool MethodHasAuthorizeAttribute( Expression<System.Action> expression )
{
var method = MethodOf( expression );
const bool includeInherited = false;
return method.GetCustomAttributes( typeof( AuthorizeAttribute ), includeInherited ).Any();
}
好的,那就是方法。 現在,如果要對類或字段應用屬性檢查(我將保留屬性,因為它們實際上是方法),我們需要對MemberInfo
進行檢查,該成員是Type
, FieldInfo
和MethodInfo
的繼承根。 這就像將“屬性”搜索提取到一個單獨的方法中並為它提供合適的帶有漂亮名稱的適配器方法一樣簡單:
public static bool MethodHasAuthorizeAttribute( Expression<System.Action> expression )
{
MemberInfo member = MethodOf( expression );
return MemberHasAuthorizeAttribute( member );
}
public static bool TypeHasAuthorizeAttribute( Type t)
{
return MemberHasAuthorizeAttribute( t );
}
private static bool MemberHasAuthorizeAttribute( MemberInfo member )
{
const bool includeInherited = false;
return member.GetCustomAttributes( typeof( AuthorizeAttribute ), includeInherited ).Any();
}
我將保留字段的實現作為練習,您可以采用與MethodOf相同的技巧。
與當前的.NET / C#版本(4.6.1,C#6)相比,有一個比上面其他解決方案更簡單的解決方案:
如果您只有一個使用該名稱的方法:
var method = typeof(TestClass).GetMethods()
.SingleOrDefault(x => x.Name == nameof(TestClass.TestMethod));
var attribute = method?.GetCustomAttributes(typeof(MethodAttribute), true)
.Single() as MethodAttribute;
現在檢查是否在方法上設置了屬性:
bool isDefined = attribute != null;
而且,如果您想訪問屬性的屬性,可以這樣簡單地完成:
var someInfo = attribute.SomeMethodInfo
如果有多個同名方法,則可以繼續使用method.GetParameters()
並檢查參數,而不是.GetMethods().Single...
如果您知道您的方法沒有參數,則此檢查很容易:
var method = typeof(TestClass).GetMethods()
.SingleOrDefault(
x => x.Name == nameof(TestClass.TestMethod)
&& x.GetParameters().Length == 0
);
如果不是這樣,它將變得更加復雜(檢查參數等),並且其他解決方案將更易於使用且更可靠。
因此:如果您沒有方法的重載,或者只想從具有指定數量參數的方法中讀取屬性,請使用此方法。 否則,請使用此處其他答案提供的MethodOf
。
我做這樣的事情:
public static bool MethodHasAuthorizeAttribute(this Delegate pMethod, string pRoleAccess)
{
var mi = pMethod.GetMethodInfo();
const bool includeInherited = false;
var atr = mi.GetCustomAttributes(typeof(AuthorizeAttribute), includeInherited)
.Select(t => (AuthorizeAttribute)t)
.Where(t => pRoleAccess.Length>0?t.Roles == pRoleAccess:true);
if (pRoleAccess == String.Empty)
{
return !atr.Any();
}
else
{
return atr.Any();
}
}
public static bool MethodHasAllowAnonymousAttribute(this Delegate pMethod)
{
var mi = pMethod.GetMethodInfo();
const bool includeInherited = false;
var atr = mi.GetCustomAttributes(typeof(AllowAnonymousAttribute), includeInherited);
return atr.Any();
}
如下調用
Func<string,System.Web.Mvc.ActionResult> func = controller.Login;
bool atrAuthorize = func.MethodHasAuthorizeAttribute(String.Empty);
找到一些示例,在其中我找到了應用了指定屬性的類中的方法。
private static void GetMethodInfo(object className)
{
var methods = className.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
foreach(var m in methods)
{
var parameters = m.GetParameters();
var att = m.GetCustomAttributes(typeof (CustomAttribute), true);
}
}
傳遞的參數是類的實例。 您可以修改代碼以適合您的要求,這應該很容易。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.