优化ETL过滤模块
大石头 编写于 2017-08-29 17:11:46
X
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using NewLife.Reflection;

namespace NewLife.Remoting
{
    /// <summary>Api动作</summary>
    public class ApiAction
    {
        /// <summary>动作名称</summary>
        public String Name { get; set; }

        /// <summary>动作所在类型</summary>
        public Type Type { get; set; }

        /// <summary>方法</summary>
        public MethodInfo Method { get; set; }

        /// <summary>控制器对象</summary>
        /// <remarks>如果指定控制器对象,则每次调用前不再实例化对象</remarks>
        public Object Controller { get; set; }

        /// <summary>动作过滤器</summary>
        public IActionFilter[] ActionFilters { get; }

        /// <summary>异常过滤器</summary>
        public IExceptionFilter[] ExceptionFilters { get; }

        /// <summary>实例化</summary>
        public ApiAction(MethodInfo method, Type type)
        {
            if (type == null) type = method.DeclaringType;
            if (type != null)
            {
                var typeName = type.Name.TrimEnd("Controller");
                var att = type.GetCustomAttribute<ApiAttribute>(true);
                if (att != null) typeName = att.Name;

                var miName = method.Name;
                att = method.GetCustomAttribute<ApiAttribute>();
                if (att != null) miName = att.Name;

                if (typeName.IsNullOrEmpty())
                    Name = miName;
                else
                    Name = "{0}/{1}".F(typeName, miName);
            }
            // 必须同时记录类型和方法,因为有些方法位于继承的不同层次,那样会导致实例化的对象不一致
            Type = type;
            Method = method;

            ActionFilters = GetAllFilters(method);
            ExceptionFilters = GetAllExceptionFilters(method);
        }

        private IActionFilter[] GetAllFilters(MethodInfo method)
        {
            if (method == null) throw new ArgumentNullException(nameof(method));

            var fs = new List<IActionFilter>();
            var atts = method.GetCustomAttributes<ActionFilterAttribute>(true);
            if (atts != null) fs.AddRange(atts);
            atts = method.DeclaringType.GetCustomAttributes<ActionFilterAttribute>(true);
            if (atts != null) fs.AddRange(atts);

            fs.AddRange(GlobalFilters.ActionFilters);

            // 排序
            var arr = fs.OrderBy(e => (e as FilterAttribute)?.Order ?? 0).ToArray();

            return arr;
        }

        private IExceptionFilter[] GetAllExceptionFilters(MethodInfo method)
        {
            if (method == null) throw new ArgumentNullException(nameof(method));

            var fs = new List<IExceptionFilter>();
            var atts = method.GetCustomAttributes<HandleErrorAttribute>(true);
            if (atts != null) fs.AddRange(atts);
            atts = method.DeclaringType.GetCustomAttributes<HandleErrorAttribute>(true);
            if (atts != null) fs.AddRange(atts);

            fs.AddRange(GlobalFilters.ExceptionFilters);

            // 排序
            var arr = fs.OrderBy(e => (e as FilterAttribute)?.Order ?? 0).ToArray();

            return arr;
        }

        /// <summary>已重载。</summary>
        /// <returns></returns>
        public override String ToString()
        {
            //return "{0}\t{1}".F(Method.GetDisplayName() ?? Name, Method);

            var type = Method.ReturnType;
            var rtype = type.Name;
            if (type.As<Task>())
            {
                if (type.IsGenericType)
                    rtype = "Void";
                else
                {
                    type = type.GetGenericArguments()[0];
                    rtype = type.Name;
                }
            }

            var sb = new StringBuilder();
            sb.AppendFormat("{0} {1}", rtype, Name);
            sb.Append("(");

            var pis = Method.GetParameters();
            for (var i = 0; i < pis.Length; i++)
            {
                if (i > 0) sb.Append(", ");
                sb.AppendFormat("{0} {1}", pis[i].ParameterType.Name, pis[i].Name);
            }

            sb.Append(")");

            return sb.ToString();
        }
    }
}