1.先做个小例子
特性,只能通过反射实现
我们自定义一个特性
public class CustomAttribute : Attribute { public int Id; public string Name; public string Reamrk; public string Desc; public CustomAttribute() : this(0, "") { }//如果没传参,使用this给默认值 public CustomAttribute(int _id, string _name) { this.Id = _id; this.Name = _name; } public void Show() { Console.WriteLine($"{Id}_{Name}_{Reamrk}_{Desc}"); } }
写一个类并注册特性
[Custom(123,"kxy",Desc ="是个帅哥",Reamrk ="学员")] public class Student { [Custom(124, "wzz", Desc = "是个丑逼", Reamrk = "学员")] public void Study() { Console.WriteLine($"正在学习"); } }
实现特性调用,只能通过反射,没办法和MVC那样直接调用接口特性就会执行(因为MVC已经封装好了调用的反射机制)
class Program { static void Main(string[] args) { Student student = new Student(); Type type = student.GetType(); // 判断该类是否注册了CustomAttribute if (type.IsDefined(typeof(CustomAttribute), true)) { var attribute = type.GetCustomAttribute<CustomAttribute>(); attribute.Show(); } MethodInfo method = type.GetMethod("Study"); // 判断该方法是否注册了CustomAttribute if (method.IsDefined(typeof(CustomAttribute), true)) { var attribute = method.GetCustomAttribute<CustomAttribute>(); attribute.Show(); } // 执行了特性之后执行方法 student.Study(); Console.ReadLine(); } }
结果:
由上可知,执行步骤先是执行类注册、在是方法注册的特性,然后再是执行我们需要的方法
这个思路和MVC 提供的特性是一致的
2.MVC特性思路
先定义三大特性
namespace Study.CustomMVCAttribute.CustomMVCAttribute { /// <summary> /// 基类不做操作 /// 所有Filter只打印,不实现功能 /// </summary> public class FilterAttribute : Attribute { } /// <summary> /// 权限Filter /// </summary> public class AuthorizeAttribute : FilterAttribute { public void OnAuthorization() { Console.WriteLine("OnAuthorization"); } } /// <summary> /// 动作Filter /// </summary> public class ActionFilterAttribute : FilterAttribute { public void OnActionExecuting() { Console.WriteLine("OnActionExecuting"); } public void OnActionExecuted() { Console.WriteLine("OnActionExecuted"); } // OnResultExecuting 和 OnResultExecuted 先不管 } /// <summary> /// 捕捉异常Filter /// </summary> public class HandleErrorAttribute : FilterAttribute { public void OnException() { Console.WriteLine("OnException"); } } }
定义 ControllerActionInvoker
using System; using System.Linq; using System.Reflection; namespace Study.CustomMVCAttribute.CustomMVCAttribute { public class ControllerActionInvoker { /// <summary> /// 实例化 /// </summary> /// <param name="instance">调用的实例</param> /// <param name="action">方法名</param> /// <param name="parameters">参数</param> public static void InvokeAction(object instance, string action, object[] parameters = null) { Type type = instance.GetType(); MethodInfo method = type.GetMethod(action); if (method.IsDefined(typeof(FilterAttribute), true)) { var filterList = method.GetCustomAttributes<FilterAttribute>(); try { // 授权 AuthorizeAttribute authorize = (AuthorizeAttribute)filterList.FirstOrDefault(v => v is AuthorizeAttribute); if (authorize != null) { authorize.OnAuthorization(); } // 方法执行前 var actionList = filterList.Where(v => v is ActionFilterAttribute); foreach (var item in actionList) { ((ActionFilterAttribute)item).OnActionExecuting(); } // 这里执行方法 method.Invoke(instance, parameters); // 方法执行后 foreach (var item in actionList) { ((ActionFilterAttribute)item).OnActionExecuted(); } } catch (Exception ex) { // 异常捕捉,包括整个动作 HandleErrorAttribute handleError = (HandleErrorAttribute)filterList.FirstOrDefault(v => v is HandleErrorAttribute); if (handleError != null) { handleError.OnException(); } } } } } }
注册
namespace Study.CustomMVCAttribute { public class Student { [Authorize] [ActionFilter] [HandleError] public void Study() { Console.WriteLine($"正在学习"); } } }
调用
Student student = new Student(); ControllerActionInvoker.InvokeAction(student, "Study");