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

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

二、方法过滤的实现方式

  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("=====================================================================\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 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 = ; 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[])); ilOfCtorDefault.Emit(OpCodes.Ldarg_0);
ilOfCtorDefault.Emit(OpCodes.Newobj, typeofTImplement.GetConstructor(new Type[]));
ilOfCtorDefault.Emit(OpCodes.Stfld, fieldInstance); ilOfCtorDefault.Emit(OpCodes.Ret);
#endregion #region 实现接口方法
var methodsOfInterface = interfaceType.GetMethods();
var length = methodsOfInterface.Length;
for (var i = ; 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[]));
ilOfMethod.Emit(OpCodes.Stloc_1);
ilOfMethod.Emit(OpCodes.Newobj, typeof(List<ExecutedFilterAttribute>).GetConstructor(new Type[]));
ilOfMethod.Emit(OpCodes.Stloc_2);
ilOfMethod.Emit(OpCodes.Newobj, typeof(List<ErrorFilterAttribute>).GetConstructor(new Type[]));
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 = ; 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 = ;
for (int p = ; 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 = ; p < methodParamsTypes.Length; p++)
{
ilOfMethod.Emit(OpCodes.Ldarg, (p + ));
} 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[]);
EmitGenerator<TImplement>.InitFilters(instanceMethod, list, list2, list3);
MethodParameters[] array2 = null;
try
{
array2 = EmitGenerator<TImplement>.GetMethodParmaters(instanceMethod, new object[]);
for (int i = ; i < list.Count; i++)
{
list[i].Execute(array2);
}
array = ((ServiceTest)_instance).GetValues();
}
catch (Exception ex)
{
if (list3.Count == )
{
throw;
}
for (int j = ; j < list3.Count; j++)
{
list3[j].Execute(array2, ex);
}
}
finally
{
for (int k = ; 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

C# 使用代理实现方法过滤的更多相关文章

  1. 动态代理AOP实现方法过滤

    上一节实现了动态代理,接下来 有时候,我不需要在每一个方法都要记录日志,做权限验证 等等. 所有就有了这样的需求.AOP实现特定方法过滤,有选择性的来对方法实现AOP 拦截.就是本节标题所示. 举个例 ...

  2. iOS里面消除使用代理调用方法时间警告问题

    iOS里面有三种调用函数的方式: 直接调用方法   [对象名 方法]; performselector:    [对象名 perform方法]; NSInvocation     调用 在使用代理调用 ...

  3. struts2中的方法过滤拦截器

    方法过滤拦截器是只过滤指定的方法,如果使用针对action 的普通的过滤器则会过滤该action内部 所有方法.如果在一个action中同时有多个作为业务逻辑控制的方法存在 的话则会过滤所有的业务逻辑 ...

  4. .Net下HTTP访问穿越多层代理的方法以及代理服务器的验证 转载

    https://blog.williamgates.net/2006/07/aspdotnet-through-multi-proxy/ 首先,通过普通的匿名透明代理的方法,是直接使用Socket发送 ...

  5. java-mybaits-00203-DAO-mapper代理开发方法,多参数【推荐】

    程序员只需要mapper接口(相当 于dao接口) 不需要写具体实现类,mapper已经代理完成,mybatis才有的 一.mapper代理开发方法(建议使用)          程序员在编写mapp ...

  6. 五种WordPress防止垃圾评论方法-过滤垃圾评论提高WP运行效率

    WordPress貌似和垃圾评论是一对“孪生兄弟”,无论在国内还是国外的空间主机上搭建的Wordpress博客,无论Wordpress有多少流量多么低的权重,垃圾评论都会自动找上门来,假如有好几天没有 ...

  7. vue中代理实现方法

    vue中代理实现方法如下: const path = require('path'); function resolve(dir) { return path.join(__dirname, dir) ...

  8. 原生js事件委托(事件代理)方法扩展

    原生js事件委托(事件代理)方法扩展: 通过Node底层原型扩展委托方法 /** * 事件委托方法 * @param eventName {string}:事件名称,如'click' * @param ...

  9. [转] Ubuntu的apt-get 设置代理的方法

    点击阅读原文 新立得软件管理器这种图形化的代理设置很明了,这里介绍下终端命令行的网络代理设置,这样大家就可以通过代理进行apt-get了. 方法一: 如果只是想临时使用http代理,可以在使用apt- ...

随机推荐

  1. css笔记 - column分栏

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. Tkinter 之文件管理器

    一.效果图 二.功能描述 1.打开文件菜单中的打开按钮,可以选择目录. 2.可以查看各种类型的图片. 3.可以编辑文本. 4.显示行号功能,可改变目录显示的宽度. 三.使用的标签 1.Menu 2.F ...

  3. 【CSP模拟赛】Freda的迷宫(桥)

    题目描述 Freda是一个迷宫爱好者,她利用业余时间建造了许多迷宫.每个迷宫都是由若干房间和走廊构成的,每条走廊都连接着两个不同的房间,两个房间之间最多只有一条走廊直接相连,走廊都是双向通过.  黄昏 ...

  4. NIO 选择器 Selector

    选择器提供选择执行已经就绪的任务的能力,这使得多元 I/O 成为可能.就像在第一章中描述的那样,就绪选择和多元执行使得单线程能够有效率地同时管理多个 I/O 通道(Channels).C/C++代码的 ...

  5. 剑指offer:和为S的两个数字

    题目描述: 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 输出描述: 对应每个测试案例,输出两个数,小的先输出. 思 ...

  6. vue 创建监听,和销毁监听(addEventListener, removeEventListener)

    最近在做一个有关监听scroll的功能, 发现我添加监听之后一直不起作用: 1 2 mounted() {     window.addEventListener("scroll" ...

  7. 企业架构 Red Hat Drools KIE Project 三大核心产品

    美团放弃Drools自研规则引擎: https://blog.csdn.net/qq_18603599/article/details/80767912 Drools rule engine虽然好,但 ...

  8. thinkphp5---join联合查询

    使用thinkphp3.2进行联合查询,join联合查询: $list = M('document as d') ->join('tp_admin_column as c on d.cid = ...

  9. (5)Flask项目会员登录页

    一.添加登录和登出的路由 修改app/home/views.py内容,增加登录("/login/")和登出("/logout/")的路由: # coding:u ...

  10. SpringCloud中遇到的问题总结

    1.如果数据库URL字符串中不加serverTimezone=GMT%2B8且数据库未设置时区,会报如下错误 Caused by: com.mysql.cj.exceptions.InvalidCon ...