zoukankan      html  css  js  c++  java
  • C# 使用代理实现方法过滤

    一、为什么要进行方法过滤

    一些情况下我们需要再方法调用前记录方法的调用时间和使用的参数,再调用后需要记录方法的结束时间和返回结果,当方法出现异常的时候,需要记录异常的堆栈和原因,这些都是与业务无关的代码,我们不应该将这些重复的且与业务无关的逻辑引入到业务方法里面,此时我们便需要使用过滤来解决这些问题。

    二、方法过滤的实现方式

    1. 静态代理实现

    什么时静态代理?

    静态代理,又叫编译时代理,就是在编译的时候,已经存在代理类,运行时直接调用的方式。说的通俗一点,就是自己手动写代码实现代理类的方式。

    当我们需要再方法前后和有异常的时候记录log我们最常想用的方式就如同下图中左图的实现方式,我们再业务逻辑类里面有个test方法,我们直接再方法前后记录log,再catch到异常的时候也记录log,此时这些无关代码就会引入到我们的业务逻辑里面,如果我们采用右图的方式我们就可以将这些代码从业务代码中移除,首先我们创建业务代理类,然后再业务代理类中同样定义方法test,再这个方法体中我们调用业务类中的test方法,再调用前后和捕捉到异常的时候打印需要的log。这个时候我们就可以保持业务代码的清新。

    对于此我们也有更优雅的实现方法,比如说业务类中定义Test方法为虚方法,然后让业务代理类继承与业务类,并重写Test方法,在方法中我们调用父类的Test方法,并在方法中记录需要的log。

    当我们只有一个或几个方法的是时候这样做时没有任何问题的,但是当我们一个类里面的方法有成百上千,我们这样做依然会显得代码多余,此时我们有以下方式解决这些问题。

    l  第一个当然就是把记录log的语句提炼成不同的方法,比如说提炼为BeforeInvoke,AfterInvoke, HandleError这三个方法,然后在不同的方法里面调用就可以了。

    l  还有比上一种方式实现更优雅的方式,就是在代理类中只定义一个Invoke方法,方法的参数是我们需要调用的方法名和参数列表,然后再Invoke方法里面我们利用反射技术调用业务类中对应的方法。此时我们代理类中的方法就十分清爽了

    当做完以上的工作,我们就已经用静态代理的方式实现了方法的过滤,然后我们再思考一个问题,如果我们的方法更多而且分布在不同的类里面,又或者我们需要给系统进行进行重构,系统中方法数不胜数,如果采用静态的方式,需要做很多重复的工作,还有我们要追求系统的可扩展性,希望以后添加新的业务逻辑类,不要再新加业务代理类,这个时候我们就希望我们的业务代理是再运行时才开始创建,而不是再编译时,这个时候我们就可以采用动态代理了。

    1. 动态代理方式

    动态代理,又成为运行时代理。在程序运行的过程中,调用了生成代理类的代码,将自动生成业务类的代理类。不需要我们手共编写,极高的提高了工作效率。

    动态代理的EMIT 实现方式。

    我们先不要看原理,先看一下我们实现的效果:

    首先我们在vs里面有一个Service项目,在这个项目中我们使用refit来实现调用http的接口,我们需要对每一个服务的调用记录时间,预测性能,由于refit在http response的status code不是200的时候统一返回ApiException这个时候我们就需要对这个exception进行处理。

    我们添加一个新的项目Filter,在这个类里面我们,定义了三个不同的Attribute,如下图所示:其中方法异常,执行前和执行后过滤器基类都继承与方法过滤器基类。

    然后我们在service类project里面添加我们自己的过滤器实现:

    实现的代码如下:

    /// <summary>
        /// 自定义执行前过滤器
        /// </summary>
        public class CustomExecutingFilterAttribute : ExecutingFilterAttribute
        {
            public string Name { get; set; }
    
            public override void Execute(MethodParameters[] parameters)
            {
                Console.WriteLine("=====================================================================");
                if (parameters != null)
                    Console.WriteLine($"执行前过滤器:{nameof(CustomExecutingFilterAttribute)}, Data:{this.Name}, Param:{string.Join(", ", parameters?.Select(p => p.ToString()))}");
                else
                    Console.WriteLine($"执行前过滤器:{nameof(CustomExecutingFilterAttribute)}, Data:{this.Name}");
            }
        }
    
        /// <summary>
        /// 自定义执行后过滤器
        /// </summary>
        public class CustomExecutedFilterAttribute : ExecutedFilterAttribute
        {
            public override void Execute<TReturn>(MethodParameters[] parameters, TReturn returned)
            {
                if (parameters != null)
                    Console.WriteLine($"执行后过滤器:{nameof(CustomExecutedFilterAttribute)},Param:{string.Join(", ", parameters?.Select(p => p.ToString()))}, Return:{returned}");
                else
                    Console.WriteLine($"执行后过滤器:{nameof(CustomExecutedFilterAttribute)},Return:{returned}");
                Console.WriteLine("=====================================================================
    ");
            }
        }
    
        /// <summary>
        /// 自定义错误过滤器
        /// </summary>
        public class CustomErrorFilterAttribute : ErrorFilterAttribute
        {
            public override void Execute(MethodParameters[] parameters, Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                if (parameters != null)
                    Console.WriteLine($"异常过滤器:{nameof(CustomErrorFilterAttribute)}, Param:{string.Join(", ", parameters?.Select(p => p.ToString()))},Exception:{ex}");
                else
                    Console.WriteLine($"异常过滤器:{nameof(CustomErrorFilterAttribute)}, Exception:{ex}");
                Console.ResetColor();
            }
        }

    我们添加ServiceTest类并继承于IServiceTest接口,然后我们在Service的GetValues方法上添加我们定义好的过滤器,代码如下:

        public class ServiceTest : IServiceTest
        {
            IService serviceUrl = RestService.For<IService>("http://localhost:5001/Api");
            
            [CustomErrorFilter]
            [CustomExecutingFilter]
            [CustomExecutedFilter]
            public string[] GetValues()
            {
                var value = serviceUrl.GetValue().Result;
                return value;
            }
        }
        public interface IServiceTest
        {
            string[] GetValues();
        }

    最后一步,在Test project中我们在main方法里面生成代理,并调用代理方法GetValues,代码和运行效果如下:

    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                //实例化接口实现类
                var serviceTest = new ServiceTest();
                IServiceTest serviceProxy = EmitGenerator<IServiceTest>.GenerateProxy<ServiceTest>(serviceTest);
                serviceProxy.GetValues();
                Console.ReadKey();
            }
        }
    }

    此时我们在控制台中看到我们实现的过滤器已经有了效果。

     

     现在我们就来看一下为什么我们写的Attribute可以在这个方法上生效,我们在main方法里面看到我们调用了EmitGenerator里面的GenerateProxy方法来创建代理,然后利用这个代理调用我们的方法就可以实现过滤,这个才是重中之重,下面看一下我们GenerateProxy方法的实现:

            public static TInterface GenerateProxy<TImplement>(TImplement implement) where TImplement : class, TInterface
            {
                if (implement == null)
                    throw new ArgumentNullException(nameof(implement));
                var interfaceType = typeof(TInterface);
                if (!interfaceType.IsInterface)
                    throw new ArgumentException("传入的TInterface参数不是interface");
                var interfaceTypeName = interfaceType.Name;
                var nameOfAssembly = $"Filter.{interfaceTypeName}ProxyAssembly";
                var nameofModule = $"Filter.{interfaceTypeName}ProxyModule";
                var nameOfType = $"Filter.{interfaceTypeName}Proxy";
                var typeofTImplement = typeof(TImplement);
                if (!typeofTImplement.IsClass)
                    throw new ArgumentException("传入的TImplement参数不是class");
                //动态程序集
                var assemblyName = new AssemblyName(nameOfAssembly);
                var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
                //动态模型
                var moduleBuilder = assembly.DefineDynamicModule(nameofModule, $"{nameOfAssembly}.dll");
                //动态类型
                var typeBuilder = moduleBuilder.DefineType(nameOfType, TypeAttributes.Public, null, new Type[] { interfaceType });
                var genericTypeParamBuilds = typeBuilder.DefineGenericParameters("TImplement");
    
    
                //定义泛型约束
                for (var i = 0; i < genericTypeParamBuilds.Length; i++)
                {
                    var genTypeParamBuilder = genericTypeParamBuilds[i];
                    genTypeParamBuilder.SetGenericParameterAttributes(GenericParameterAttributes.ReferenceTypeConstraint);
                    genTypeParamBuilder.SetInterfaceConstraints(interfaceType);
                }
    
    
                //定义变量
                var fieldInstance = typeBuilder.DefineField("_instance", interfaceType, FieldAttributes.Private);
                //定义构造方法
                #region 无参构造方法
                var ctorDefault = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
                var ilOfCtorDefault = ctorDefault.GetILGenerator();
    
                ilOfCtorDefault.Emit(OpCodes.Ldarg_0);
                ilOfCtorDefault.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[0]));
    
                ilOfCtorDefault.Emit(OpCodes.Ldarg_0);
                ilOfCtorDefault.Emit(OpCodes.Newobj, typeofTImplement.GetConstructor(new Type[0]));
                ilOfCtorDefault.Emit(OpCodes.Stfld, fieldInstance);
    
                ilOfCtorDefault.Emit(OpCodes.Ret);
                #endregion
    
                #region 实现接口方法
                var methodsOfInterface = interfaceType.GetMethods();
                var length = methodsOfInterface.Length;
                for (var i = 0; i < length; i++)
                {
                    var method = methodsOfInterface[i];
                    var methodReturnType = method.ReturnType;
                    var hasReturnValue = methodReturnType != typeof(void);
                    var methodParamsTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
                    var methodBuilder = typeBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard, methodReturnType, methodParamsTypes);
                    if (method.IsGenericMethod)
                    {
                        methodBuilder.DefineGenericParameters(method.GetGenericArguments().Select(p => p.Name).ToArray());
                    }
                    var ilOfMethod = methodBuilder.GetILGenerator();
                    #region 方法内容
                    ilOfMethod.Emit(OpCodes.Nop);
                    //定义局部变量
                    LocalBuilder resultLocal;
                    if (hasReturnValue)
                    {
                        resultLocal = ilOfMethod.DeclareLocal(methodReturnType);
                        if (methodReturnType.IsValueType)
                        {
                            ilOfMethod.Emit(OpCodes.Ldc_I4_0);
                            ilOfMethod.Emit(OpCodes.Stloc_0);
                        }
                        else
                        {
                            ilOfMethod.Emit(OpCodes.Ldnull);
                            ilOfMethod.Emit(OpCodes.Stloc_0);
                        }
                    }
                    else
                    {
                        resultLocal = ilOfMethod.DeclareLocal(typeof(int));
                    }
    
                    ilOfMethod.DeclareLocal(typeof(List<ExecutingFilterAttribute>));
                    ilOfMethod.DeclareLocal(typeof(List<ExecutedFilterAttribute>));
                    ilOfMethod.DeclareLocal(typeof(List<ErrorFilterAttribute>));
    
                    ilOfMethod.Emit(OpCodes.Newobj, typeof(List<ExecutingFilterAttribute>).GetConstructor(new Type[0]));
                    ilOfMethod.Emit(OpCodes.Stloc_1);
                    ilOfMethod.Emit(OpCodes.Newobj, typeof(List<ExecutedFilterAttribute>).GetConstructor(new Type[0]));
                    ilOfMethod.Emit(OpCodes.Stloc_2);
                    ilOfMethod.Emit(OpCodes.Newobj, typeof(List<ErrorFilterAttribute>).GetConstructor(new Type[0]));
                    ilOfMethod.Emit(OpCodes.Stloc_3);
    
                    var getTypeFromHandleMI = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static);
    
                    //获取method
                    ilOfMethod.Emit(OpCodes.Ldtoken, typeofTImplement);
                    ilOfMethod.Emit(OpCodes.Call, getTypeFromHandleMI);
    
                    ilOfMethod.Emit(OpCodes.Ldstr, method.Name);
                    ilOfMethod.Emit(OpCodes.Ldc_I4, methodParamsTypes.Length);
                    ilOfMethod.Emit(OpCodes.Newarr, typeof(Type));
                    for (var p = 0; p < methodParamsTypes.Length; p++)
                    {
                        ilOfMethod.Emit(OpCodes.Dup);
                        ilOfMethod.Emit(OpCodes.Ldc_I4, p);
                        ilOfMethod.Emit(OpCodes.Ldtoken, methodParamsTypes[p]);
                        ilOfMethod.Emit(OpCodes.Call, getTypeFromHandleMI);
                        ilOfMethod.Emit(OpCodes.Stelem_Ref);
                    }
    
    
                    ilOfMethod.Emit(OpCodes.Call, typeof(EmitGenerator<>).GetMethod("GetInstanceMethod", BindingFlags.Public | BindingFlags.Static));
                    var methodInfoLocal = ilOfMethod.DeclareLocal(typeof(MethodInfo));
                    ilOfMethod.Emit(OpCodes.Stloc_S, methodInfoLocal);
    
                    ilOfMethod.Emit(OpCodes.Ldloc_S, methodInfoLocal);
                    ilOfMethod.Emit(OpCodes.Ldloc_1);
                    ilOfMethod.Emit(OpCodes.Ldloc_2);
                    ilOfMethod.Emit(OpCodes.Ldloc_3);
    
                    ilOfMethod.Emit(OpCodes.Call, typeof(EmitGenerator<>).GetMethod("InitFilters", BindingFlags.Public | BindingFlags.Static));
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Ldnull);
                    var methodParametersLocal = ilOfMethod.DeclareLocal(typeof(MethodParameters[]));
                    ilOfMethod.Emit(OpCodes.Stloc_S, methodParametersLocal);
    
                    //添加try代码块
                    ilOfMethod.BeginExceptionBlock();
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, methodInfoLocal);
                    ilOfMethod.Emit(OpCodes.Ldc_I4, methodParamsTypes.Length);
    
                    ilOfMethod.Emit(OpCodes.Newarr, typeof(object));
                    int p1 = 1;
                    for (int p = 0; p < methodParamsTypes.Length; p++, p1++)
                    {
                        var item = methodParamsTypes[p];
                        ilOfMethod.Emit(OpCodes.Dup);
                        ilOfMethod.Emit(OpCodes.Ldc_I4, p);
                        ilOfMethod.Emit(OpCodes.Ldarg, (p1));
                        if (item.IsValueType)
                        {
                            ilOfMethod.Emit(OpCodes.Box, item);  //值类型装箱
                        }
                        ilOfMethod.Emit(OpCodes.Stelem_Ref);
                    }
                    ilOfMethod.Emit(OpCodes.Call, typeof(EmitGenerator<>).GetMethod("GetMethodParmaters", BindingFlags.Public | BindingFlags.Static));
                    ilOfMethod.Emit(OpCodes.Stloc_S, methodParametersLocal);
                    //执行前 for 循环,调用执行前过滤器的Execute方法
                    var iLocal = ilOfMethod.DeclareLocal(typeof(int));  //变量i
                    var conditionLable = ilOfMethod.DefineLabel();      //条件
                    var trueLable = ilOfMethod.DefineLabel();           //true
                    ilOfMethod.Emit(OpCodes.Ldc_I4_0);
                    ilOfMethod.Emit(OpCodes.Stloc_S, iLocal);           //V6
                    ilOfMethod.Emit(OpCodes.Br_S, conditionLable);
                    ilOfMethod.MarkLabel(trueLable);
                    //循环体
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Ldloc_1);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, iLocal);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(List<ExecutingFilterAttribute>).GetMethod("get_Item"));
                    ilOfMethod.Emit(OpCodes.Ldloc_S, methodParametersLocal);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(ExecutingFilterAttribute).GetMethod("Execute"));
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Nop);
                    //i++
                    ilOfMethod.Emit(OpCodes.Ldloc_S, iLocal);
                    ilOfMethod.Emit(OpCodes.Ldc_I4_1);
                    ilOfMethod.Emit(OpCodes.Add);
                    ilOfMethod.Emit(OpCodes.Stloc_S, iLocal);
                    //condition
                    ilOfMethod.MarkLabel(conditionLable);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, iLocal);
                    ilOfMethod.Emit(OpCodes.Ldloc_1);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(List<ExecutingFilterAttribute>).GetMethod("get_Count"));
                    ilOfMethod.Emit(OpCodes.Clt);
                    var v7Local = ilOfMethod.DeclareLocal(typeof(bool));
                    ilOfMethod.Emit(OpCodes.Stloc_S, v7Local);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v7Local);
                    ilOfMethod.Emit(OpCodes.Brtrue_S, trueLable);
                    //执行前 for循环结束
    
                    //执行 调用业务类中对应的方法
                    ilOfMethod.Emit(OpCodes.Ldarg_0);
                    ilOfMethod.Emit(OpCodes.Ldfld, fieldInstance);
                    for (var p = 0; p < methodParamsTypes.Length; p++)
                    {
                        ilOfMethod.Emit(OpCodes.Ldarg, (p + 1));
                    }
    
    
                    MethodInfo m;
                    if (method.IsGenericMethod)
                    {
                        m = typeofTImplement.GetMethods().FirstOrDefault(p => p.Name == method.Name && p.GetParameters().Length == methodParamsTypes.Length);
                    }
                    else
                    {
                        m = typeofTImplement.GetMethod(method.Name, methodParamsTypes);
                    }
                    ilOfMethod.Emit(OpCodes.Callvirt, m);
                    if (hasReturnValue)
                        ilOfMethod.Emit(OpCodes.Stloc_0);
                    else
                        ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Nop);
    
                    //Catch到异常时候执行异常过滤器中的execute方法
                    ilOfMethod.BeginCatchBlock(typeof(Exception));
                    var exLocal = ilOfMethod.DeclareLocal(typeof(Exception));
                    ilOfMethod.Emit(OpCodes.Stloc_S, exLocal);
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Ldloc_3);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(List<ErrorFilterAttribute>).GetMethod("get_Count"));
                    ilOfMethod.Emit(OpCodes.Ldc_I4_0);
                    ilOfMethod.Emit(OpCodes.Ceq);
                    var v9Local = ilOfMethod.DeclareLocal(typeof(bool));
                    ilOfMethod.Emit(OpCodes.Stloc_S, v9Local);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v9Local);
    
                    var tLable = ilOfMethod.DefineLabel();
                    var fLable = ilOfMethod.DefineLabel();
                    ilOfMethod.Emit(OpCodes.Brfalse_S, fLable);         //如果false跳转
                    ilOfMethod.Emit(OpCodes.Rethrow);
                    ilOfMethod.MarkLabel(fLable);                       //false
                    //异常 for循环
                    var conditionLable2 = ilOfMethod.DefineLabel();     //条件
                    var trueLable2 = ilOfMethod.DefineLabel();          //true
                    ilOfMethod.Emit(OpCodes.Ldc_I4_0);
                    var v10Local = ilOfMethod.DeclareLocal(typeof(int));
                    ilOfMethod.Emit(OpCodes.Stloc_S, v10Local);
                    ilOfMethod.Emit(OpCodes.Br_S, conditionLable2);
                    ilOfMethod.MarkLabel(trueLable2);
                    //循环体
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Ldloc_3);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v10Local);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(List<ErrorFilterAttribute>).GetMethod("get_Item"));
                    ilOfMethod.Emit(OpCodes.Ldloc_S, methodParametersLocal);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, exLocal);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(ErrorFilterAttribute).GetMethod("Execute"));
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Nop);
                    //i++
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v10Local);
                    ilOfMethod.Emit(OpCodes.Ldc_I4_1);
                    ilOfMethod.Emit(OpCodes.Add);
                    ilOfMethod.Emit(OpCodes.Stloc_S, v10Local);
                    //condition
                    ilOfMethod.MarkLabel(conditionLable2);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v10Local);
                    ilOfMethod.Emit(OpCodes.Ldloc_3);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(List<ErrorFilterAttribute>).GetMethod("get_Count"));
                    ilOfMethod.Emit(OpCodes.Clt);
                    var v11Local = ilOfMethod.DeclareLocal(typeof(bool));
                    ilOfMethod.Emit(OpCodes.Stloc_S, v11Local);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v11Local);
                    ilOfMethod.Emit(OpCodes.Brtrue_S, trueLable2);
                    ilOfMethod.Emit(OpCodes.Nop);
                    //异常 for循环结束
    
                    //finally
                    ilOfMethod.BeginFinallyBlock();
                    ilOfMethod.Emit(OpCodes.Nop);
                    //执行结束 for循环 调用执行后过滤器的Execute方法
                    var conditionLable3 = ilOfMethod.DefineLabel();      //条件
                    var trueLable3 = ilOfMethod.DefineLabel();           //true
                    ilOfMethod.Emit(OpCodes.Ldc_I4_0);
                    var v12Local = ilOfMethod.DeclareLocal(typeof(int));
                    ilOfMethod.Emit(OpCodes.Stloc_S, v12Local);
                    ilOfMethod.Emit(OpCodes.Br_S, conditionLable3);
                    ilOfMethod.MarkLabel(trueLable3);
                    //循环体
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Ldloc_2);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v12Local);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(List<ExecutedFilterAttribute>).GetMethod("get_Item"));
                    ilOfMethod.Emit(OpCodes.Ldloc_S, methodParametersLocal);
                    if (hasReturnValue)
                    {
                        ilOfMethod.Emit(OpCodes.Ldloc_0);
                        ilOfMethod.Emit(OpCodes.Callvirt, typeof(ExecutedFilterAttribute).GetMethod("Execute").MakeGenericMethod(methodReturnType));
                    }
                    else
                    {
                        ilOfMethod.Emit(OpCodes.Ldc_I4_0);
                        ilOfMethod.Emit(OpCodes.Callvirt, typeof(ExecutedFilterAttribute).GetMethod("Execute").MakeGenericMethod(typeof(int)));
                    }
    
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.Emit(OpCodes.Nop);
                    //i++
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v12Local);
                    ilOfMethod.Emit(OpCodes.Ldc_I4_1);
                    ilOfMethod.Emit(OpCodes.Add);
                    ilOfMethod.Emit(OpCodes.Stloc_S, v12Local);
                    //condition
                    ilOfMethod.MarkLabel(conditionLable3);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v12Local);
                    ilOfMethod.Emit(OpCodes.Ldloc_2);
                    ilOfMethod.Emit(OpCodes.Callvirt, typeof(List<ExecutedFilterAttribute>).GetMethod("get_Count"));
                    ilOfMethod.Emit(OpCodes.Clt);
                    var v13Local = ilOfMethod.DeclareLocal(typeof(bool));
                    ilOfMethod.Emit(OpCodes.Stloc_S, v13Local);
                    ilOfMethod.Emit(OpCodes.Ldloc_S, v13Local);
                    ilOfMethod.Emit(OpCodes.Brtrue, trueLable3);
                    //执行结束 for循环结束
    
                    ilOfMethod.Emit(OpCodes.Nop);
                    ilOfMethod.EndExceptionBlock();
    
                    if (hasReturnValue)
                    {
                        ilOfMethod.Emit(OpCodes.Ldloc_0);
                        ilOfMethod.Emit(OpCodes.Stloc, resultLocal);
    
                        var returnLable = ilOfMethod.DefineLabel();
                        ilOfMethod.Emit(OpCodes.Br_S, returnLable);
    
                        ilOfMethod.MarkLabel(returnLable);
                        ilOfMethod.Emit(OpCodes.Ldloc_S, resultLocal);
                    }
    
                    //结束
                    ilOfMethod.Emit(OpCodes.Ret);
                    #endregion
                }
    
                #endregion
                var type = typeBuilder.CreateType();
                assembly.Save($"{nameOfAssembly}.dll"); 
                type = type.MakeGenericType(typeofTImplement);
                return (TInterface)Activator.CreateInstance(type);
            }

    在GenerateProxy 这个超长的代码中的实现遵循以下步骤:

    1. 动态构建程序集

    2. 动态构建模型

    3. 动态构建代理方法

    在第三步中又做了以下几件事情:

    1. 如果业务方法中存在执行前过滤器,调用执行前过滤器的Execute方法
    2. 执行业务方法
    3. 如果业务方法中存在执行后过滤器,调用执行前过滤器的Execute方法
    4. 如果业务方法中存在异常过滤器,添加Try catch代码块,catch到异常执行异常过滤器中的Execute方法。

    我们通过ILSpy反编译动态生成的dll来看一下,dll中的代码是什么样子的。

    public class IServiceTestProxy<TImplement> : IServiceTest where TImplement : class, IServiceTest
    {
        private IServiceTest _instance;
    
        public IServiceTestProxy()
        {
            //Error decoding local variables: Signature type sequence must have at least one element.
            _instance = new ServiceTest();
        }
    
        public override string[] GetValues()
        {
            string[] array = null;
            List<ExecutingFilterAttribute> list = new List<ExecutingFilterAttribute>();
            List<ExecutedFilterAttribute> list2 = new List<ExecutedFilterAttribute>();
            List<ErrorFilterAttribute> list3 = new List<ErrorFilterAttribute>();
            MethodInfo instanceMethod = EmitGenerator<TImplement>.GetInstanceMethod(typeof(ServiceTest), "GetValues", new Type[0]);
            EmitGenerator<TImplement>.InitFilters(instanceMethod, list, list2, list3);
            MethodParameters[] array2 = null;
            try
            {
                array2 = EmitGenerator<TImplement>.GetMethodParmaters(instanceMethod, new object[0]);
                for (int i = 0; i < list.Count; i++)
                {
                    list[i].Execute(array2);
                }
                array = ((ServiceTest)_instance).GetValues();
            }
            catch (Exception ex)
            {
                if (list3.Count == 0)
                {
                    throw;
                }
                for (int j = 0; j < list3.Count; j++)
                {
                    list3[j].Execute(array2, ex);
                }
            }
            finally
            {
                for (int k = 0; k < list2.Count; k++)
                {
                    list2[k].Execute(array2, array);
                }
            }
            return array;
        }
    }

    从反编译处理的代码中我们可以看到,这跟我们静态代理中添加的代码并无太大区别,都是在方法执行前后和catch异常后进行了记录处理。

    从现在看起来我们这个动态代理已经时完美的了吗?我建议大家可以做一个测试,如果你添加了带有泛型参数的方法,会出现什么情况?我们会发现我们的动态代理将会生成代理类失败,但是好在我们在这里依然可以通过反射添加泛型参数,这里大家可以思考一下具体如何实现。

    还存在另外一个问题,正常来讲Refit调用接口都是异步的,我们也应该使用异步来调用Refit的方法,这样才不会时我们的UI卡顿,可是我们在ServiceTest的GetValues方法里面采用的时同步调用,如果我们改成异步的会出现什么结果呢?

    我们动手来实践一下:

    首先我们将代码更改成异步调用(async,await关键字实现异步调用)然后我们再运行代码会发现,我们的方法执行前和执行后过滤器都没有问题,但是我们的异常处理过滤器却没有生效,导致我们的异常直接抛出到了我们的调用者里面。

    我们看一下为什么会出现这种情况,首先我们用ILSpy反编译我们的动态程序集,我们发现我们的代理方法并没有自动生成async和await调用,此时当我们调用完ServiceTest中的getValue方法后就已经退出了代理方法。此时方法运行并没有Exception出现,异常过滤器当然也会失效。

    那么async和await到底是什么呢,我们反编译一下我们的Service.dll代码版本选择C# 4.0,这个版本的代码还没有async和await的实现。这个时候我们的代码如下图所示:

    很显然,这里的stateMachine(状态机)就是我们需要的东西,遗憾的时我们的EMIT框架暂时没有提供状态机的实现,那么我们怎么解决这个问题呢?

     接下来为大家介绍另外一种实现动态代理的方法:

    通过RealProxy 来实现动态代理。

    为了不与EMIT的实现方式混淆我们新建一个Solution,此时我们依旧需要我么的ServiceTest,我们先看一下这里的实现:

    我们的serviceTest类必须继承MarshalByRefObject类,然后定义一个新的类Proxy继承与RealProxy类,RealProxy类中的Invoke 必须重写,然后我们定义了awaitTask方法用来等待task完成

    下面是我们Main方法里面调用的实现:

    我们只需要构建一个Proxy,然后直接调用即可。

    运行代码我们就可以发现Proxy中的Invoke try catch就能帮我们处理异常了。这里的代码相对来说比较简单,我就不在做赘述,最后给大家留两个问题思考,上面我们再静态代理的时候也介绍了使用反射技术来调用业务方法,为什么那个不能称为动态代理,而Proxy中也是使用反射,确是动态代理呢?我们能不能通过反射自己实现动态代理呢?

    以上完整代码可以从以下获得:

    https://gitee.com/KingDamonZhen/Filter.git

    https://gitee.com/KingDamonZhen/WindowsFormsRefitTests.git

  • 相关阅读:
    Mysql常用sql语句(18)- union 全连接
    Mysql常用sql语句(17)- left / right join 外连接
    Mysql常用sql语句(16)- inner join 内连接
    Mysql常用sql语句(15)- cross join 交叉连接
    Mysql常用sql语句(14)- 多表查询
    PAT甲级专题|链表
    编程范式|程序世界里的编程范式,探索语言本质
    PAT甲级专题|树的遍历
    Java学习路线|转至CodeSheep
    SQL必知必会|SQL基础篇
  • 原文地址:https://www.cnblogs.com/ZhangDamon/p/11965907.html
Copyright © 2011-2022 走看看