仿 MVC 三大特性



泪湿孤枕 提交于 2020-10-29 12:28:01

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