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

namespace NewLife.Remoting
{
    /// <summary>Api处理器</summary>
    public interface IApiHandler
    {
        /// <summary>执行</summary>
        /// <param name="session"></param>
        /// <param name="action"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        Object Execute(IApiSession session, String action, IDictionary<String, Object> args);
    }

    class ApiHandler : IApiHandler
    {
        /// <summary>Api接口主机</summary>
        public IApiHost Host { get; set; }

        /// <summary>执行</summary>
        /// <param name="session"></param>
        /// <param name="action"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public Object Execute(IApiSession session, String action, IDictionary<String, Object> args)
        {
            var api = session.FindAction(action);
            if (api == null) throw new ApiException(404, "无法找到名为[{0}]的服务!".F(action));

            // 全局共用控制器,或者每次创建对象实例
            var controller = session.CreateController(api);
            if (controller == null) throw new ApiException(403, "无法创建名为[{0}]的服务!".F(api.Name));

            if (controller is IApi) (controller as IApi).Session = session;

            // 服务端需要检查登录授权
            var svrHost = Host as ApiServer;
            if (svrHost != null && !svrHost.Anonymous)
            {
                if (controller.GetType().GetCustomAttribute<AllowAnonymousAttribute>() == null &&
                    api.Method.GetCustomAttribute<AllowAnonymousAttribute>() == null)
                {
                    if (session.UserSession == null || !session.UserSession.Logined) throw new ApiException(401, "未登录!");
                }
            }

            // 服务设置优先于全局主机
            var svr = session.GetService<IApiServer>();
            var enc = svr?.Encoder ?? Host.Encoder;

            // 全局过滤器、控制器特性、Action特性
            var fs = api.ActionFilters;
            // 控制器实现了过滤器接口
            if (controller is IActionFilter)
            {
                var list = fs.ToList();
                list.Add(controller as IActionFilter);
                fs = list.ToArray();
            }

            // 不允许参数字典为空
            if (args == null)
                args = new NullableDictionary<String, Object>(StringComparer.OrdinalIgnoreCase);
            else
                args = args.ToNullable(StringComparer.OrdinalIgnoreCase);

            // 准备好参数
            var ps = GetParams(api.Method, args, enc);

            // 上下文
            var ctx = new ControllerContext
            {
                Controller = controller,
                Action = api,
                Session = session,
                Parameters = args
            };

            Object rs = null;
            ExceptionContext etx = null;
            try
            {
                // 当前上下文
                var actx = new ActionExecutingContext(ctx) { ActionParameters = ps };
                ControllerContext.Current = actx;

                // 执行动作前的过滤器
                OnExecuting(actx, fs);
                rs = actx.Result;

                // 执行动作
                if (rs == null) rs = controller.InvokeWithParams(api.Method, ps as IDictionary);
            }
            catch (ThreadAbortException) { throw; }
            catch (Exception ex)
            {
                // 过滤得到内层异常
                ex = ex.GetTrue();

                var efs = api.ExceptionFilters;
                // 控制器实现了异常过滤器接口
                if (controller is IExceptionFilter)
                {
                    var list = efs.ToList();
                    list.Add(controller as IExceptionFilter);
                    efs = list.ToArray();
                }

                // 执行异常过滤器
                etx = OnException(ctx, ex, efs, rs);

                Host.WriteLog("执行{0}出错!{1}", action, ex.Message);

                // 如果异常没有被拦截,继续向外抛出
                if (!etx.ExceptionHandled) throw;

                return rs = etx.Result;
            }
            finally
            {
                // 执行动作后的过滤器
                rs = OnExecuted(ctx, etx, fs, rs);
                ControllerContext.Current = null;
            }

            return rs;
        }

        protected virtual void OnExecuting(ActionExecutingContext ctx, IActionFilter[] fs)
        {
            foreach (var filter in fs)
            {
                filter.OnActionExecuting(ctx);
            }
        }

        protected virtual Object OnExecuted(ControllerContext ctx, ExceptionContext etx, IActionFilter[] fs, Object rs)
        {
            if (fs.Length == 0) return rs;

            // 倒序
            fs = fs.Reverse().ToArray();

            var atx = new ActionExecutedContext(etx ?? ctx) { Result = rs };
            foreach (var filter in fs)
            {
                filter.OnActionExecuted(atx);
            }
            return atx.Result;
        }

        protected virtual ExceptionContext OnException(ControllerContext ctx, Exception ex, IExceptionFilter[] fs, Object rs)
        {
            //if (fs.Length == 0) return null;

            var etx = new ExceptionContext(ctx) { Exception = ex, Result = rs };

            foreach (var filter in fs)
            {
                filter.OnException(etx);
            }

            return etx;
        }

        private IDictionary<String, Object> GetParams(MethodInfo method, IDictionary<String, Object> args, IEncoder encoder)
        {
            // 该方法没有参数,无视外部传入参数
            var pis = method.GetParameters();
            if (pis == null || pis.Length < 1) return null;

            var ps = new Dictionary<String, Object>();
            foreach (var pi in pis)
            {
                var name = pi.Name;

                Object v = null;
                if (args != null && args.ContainsKey(name)) v = args[name];

                // 基本类型
                if (pi.ParameterType.GetTypeCode() != TypeCode.Object)
                {
                    ps[name] = v.ChangeType(pi.ParameterType);
                }
                // 复杂对象填充,各个参数填充到一个模型参数里面去
                else
                {
                    // 特殊处理字节数组
                    if (pi.ParameterType == typeof(Byte[]))
                        ps[name] = Convert.FromBase64String(v + "");
                    else
                    {
                        if (v == null) v = args;
                        //if (v is IDictionary<String, Object>)
                        ps[name] = encoder.Convert(v, pi.ParameterType);
                    }
                }
            }

            return ps;
        }
    }
}