2012-01-11 34 views
22

Tôi có một lớp dụLàm thế nào để kiểm tra xem phương pháp có một thuộc tính

public class MyClass{ 

    ActionResult Method1(){ 
     .... 
    } 

    [Authorize] 
    ActionResult Method2(){ 
     .... 
    } 

    [Authorize]  
    ActionResult Method3(int value){ 
     .... 
    } 

} 

Bây giờ những gì tôi muốn là viết một hàm trả về đúng/sai có thể được thực hiện như thế này

var controller = new MyClass(); 

Assert.IsFalse(MethodHasAuthorizeAttribute(controller.Method1)); 
Assert.IsTrue(MethodHasAuthorizeAttribute(controller.Method2)); 
Assert.IsTrue(MethodHasAuthorizeAttribute(controller.Method3)); 

tôi đến điểm mà

public bool MethodHasAuthorizeAttribute(Func<int, ActionResult> function) 
{ 
    return function.Method.GetCustomAttributes(typeof(AuthorizeAttribute), false).Length > 0; 
} 

sẽ hoạt động đối với Method3. Bây giờ làm thế nào tôi có thể làm điều đó chung chung trong một cách mà nó sẽ mất chuỗi và các lớp học như các tham số là tốt?

+0

Bạn có muốn kiểm tra xem lớp, phương pháp hoặc thuộc tính có Thuộc tính như vậy trong một phương pháp chung không? –

+0

Có phải bạn chỉ muốn biết liệu một phương pháp có một loại thuộc tính nào đó được áp dụng trên nó không? – Rajesh

+0

Tôi muốn kiểm tra xem phương pháp có một tập hợp thuộc tính cụ thể nhưng tôi không muốn chuyển một tên phương thức như một chuỗi. – 4rchie

Trả lời

20

Vấn đề với mã của bạn là chữ ký của public bool MethodHasAuthorizeAttribute(Func<int, ActionResult> function). MethodHasAuthorizeAttribute chỉ có thể được sử dụng với các đối số khớp với chữ ký của đại biểu bạn đã chỉ định. Trong trường hợp này, phương thức trả lại số ActionResult với thông số loại int.

Khi bạn gọi phương thức này như MethodHasAuthorizeAttribute(controller.Method3), Trình biên dịch sẽ thực hiện chuyển đổi nhóm phương pháp. Điều này có thể không phải lúc nào cũng mong muốn và có thể mang lại kết quả không mong muốn (Chuyển đổi nhóm phương pháp không phải lúc nào cũng thẳng thắn). Nếu bạn cố gắng gọi MethodHasAuthorizeAttribute(controller.Method1) bạn sẽ nhận được một lỗi trình biên dịch vì không có chuyển đổi.

Một giải pháp tổng quát hơn có thể được xây dựng bằng cây biểu thức và mẹo "MethodOf" nổi tiếng. Nó sử dụng trình biên dịch tạo ra cây biểu thức để tìm ra mục tiêu gọi:

public static MethodInfo MethodOf(Expression<System.Action> expression) 
{ 
    MethodCallExpression body = (MethodCallExpression)expression.Body; 
    return body.Method; 
} 

Bạn có thể sử dụng nó như thế này, nhưng nó cũng có thể được sử dụng với phương pháp nào:

MethodInfo method = MethodOf(() => controller.Method3(default(int))); 

Với điều đó ra khỏi con đường, chúng tôi có thể xây dựng triển khai chung:

public static bool MethodHasAuthorizeAttribute(Expression<System.Action> expression) 
{ 
    var method = MethodOf(expression); 

    const bool includeInherited = false; 
    return method.GetCustomAttributes(typeof(AuthorizeAttribute), includeInherited).Any(); 
} 

Được rồi, đó là phương pháp. Bây giờ, nếu bạn muốn áp dụng các thuộc tính kiểm tra trên các lớp hoặc các lĩnh vực để (tôi sẽ phụ thuộc tài sản vì chúng thực sự là phương pháp), chúng ta cần thực hiện kiểm tra của chúng tôi trên MemberInfo, là gốc thừa kế cho Type, FieldInfoMethodInfo. Đây dễ dàng như chiết xuất tìm kiếm thuộc tính thành một phương pháp riêng biệt và cung cấp phương pháp chuyển đổi thích hợp với những cái tên đẹp:

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

Tôi sẽ để lại việc thực hiện cho các lĩnh vực như một bài tập, bạn có thể sử dụng các thủ thuật tương tự như MethodOf.

+0

OP cũng muốn các lớp học. – Tigran

+0

bây giờ tôi có thể thực hiện MethodHasAuthorizeAttribute (() => Controller.AjaxDashboardNodes (mặc định (TreeViewItem))) Tôi nghĩ rằng tôi có thể sống với những ký tự phụ :) – 4rchie

+0

Tôi đã tạo ra một câu hỏi mới trong phản hồi này, hỏi làm thế nào để khái quát hóa giải pháp: http://stackoverflow.com/questions/41493289/how-to-assert-that-a-method-has-a-specified-attribute –

0

Tìm một số mẫu nơi tôi tìm thấy các phương thức trong lớp có thuộc tính được chỉ định được áp dụng.

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

Thông số được chuyển là một thể hiện của một lớp. Bạn có thể sửa đổi mã cho phù hợp với yêu cầu của bạn mà nên được khá dễ dàng.

1

tôi làm điều gì đó như thế:

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

Gọi nó sau

Func<string,System.Web.Mvc.ActionResult> func = controller.Login; 
bool atrAuthorize = func.MethodHasAuthorizeAttribute(String.Empty); 
4

Có một giải pháp Sẵn dễ dàng hơn so với những người khác trên với hiện tại NET C phiên bản/# (4.6.1 , C# 6):

Nếu bạn chỉ có một phương thức với tên đó:

var method = typeof(TestClass).GetMethods() 
    .SingleOrDefault(x => x.Name == nameof(TestClass.TestMethod)); 

var attribute = method?.GetCustomAttributes(typeof(MethodAttribute), true) 
    .Single() as MethodAttribute; 

Bây giờ để kiểm tra xem bạn có thuộc tính thiết lập trên phương pháp:

bool isDefined = attribute != null; 

Và nếu bạn muốn truy cập các tính chất của thuộc tính, bạn có thể làm điều này dễ dàng như vậy:

var someInfo = attribute.SomeMethodInfo 

Nếu có nhiều phương thức có cùng tên, bạn có thể tiếp tục và sử dụng method.GetParameters() và kiểm tra các tham số, thay vì .GetMethods().Single...

Nếu bạn biết rằng phương pháp của bạn không có tham số, kiểm tra này rất dễ dàng:

var method = typeof(TestClass).GetMethods() 
    .SingleOrDefault(
     x => x.Name == nameof(TestClass.TestMethod) 
     && x.GetParameters().Length == 0 
); 

Nếu không, điều này sẽ phức tạp hơn (kiểm tra thông số, v.v ...) và các giải pháp khác dễ sử dụng hơn.

Vì vậy: Sử dụng tính năng này nếu bạn không có quá tải cho một phương pháp hoặc chỉ muốn đọc các thuộc tính từ một phương pháp có số lượng thông số được chỉ định. Khác, sử dụng số MethodOf do các câu trả lời khác cung cấp tại đây.

Các vấn đề liên quan