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 里面添加我们自己的过滤器实现:

实现的代码如下:

///


/// 自定义执行前过滤器
///
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("=====================================================================\r\n");
    }
}

/// <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 interface IServiceTest
{
    string[] 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;
    }
}

最后一步,在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();
		}
	}
}

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

9ed177d11e174aacaf2f57abe9f5a5fe-image.png

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

public static TInterface GenerateProxy(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 : 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 出现,异常过滤器当然也会失效。

011320d38d20452f90e7015adbe44e4c-image.png

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

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

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

通过 RealProxy 来实现动态代理。
为了不与 EMIT 的实现方式混淆我们新建一个 Solution,此时我们依旧需要我么的 ServiceTest,我们先看一下这里的实现:

d3315fc74e6448cfb494d5a7ae089403-image.png

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

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

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

运行代码我们就可以发现 Proxy 中的 Invoke try catch 就能帮我们处理异常了。