C# 使用代理实现方法过滤
一、为什么要进行方法过滤
一些情况下我们需要再方法调用前记录方法的调用时间和使用的参数,再调用后需要记录方法的结束时间和返回结果,当方法出现异常的时候,需要记录异常的堆栈和原因,这些都是与业务无关的代码,我们不应该将这些重复的且与业务无关的逻辑引入到业务方法里面,此时我们便需要使用过滤来解决这些问题。
二、方法过滤的实现方式
- 静态代理实现
什么时静态代理?
静态代理,又叫编译时代理,就是在编译的时候,已经存在代理类,运行时直接调用的方式。说的通俗一点,就是自己手动写代码实现代理类的方式。
当我们需要再方法前后和有异常的时候记录log我们最常想用的方式就如同下图中左图的实现方式,我们再业务逻辑类里面有个test方法,我们直接再方法前后记录log,再catch到异常的时候也记录log,此时这些无关代码就会引入到我们的业务逻辑里面,如果我们采用右图的方式我们就可以将这些代码从业务代码中移除,首先我们创建业务代理类,然后再业务代理类中同样定义方法test,再这个方法体中我们调用业务类中的test方法,再调用前后和捕捉到异常的时候打印需要的log。这个时候我们就可以保持业务代码的清新。
对于此我们也有更优雅的实现方法,比如说业务类中定义Test方法为虚方法,然后让业务代理类继承与业务类,并重写Test方法,在方法中我们调用父类的Test方法,并在方法中记录需要的log。
当我们只有一个或几个方法的是时候这样做时没有任何问题的,但是当我们一个类里面的方法有成百上千,我们这样做依然会显得代码多余,此时我们有以下方式解决这些问题。
l 第一个当然就是把记录log的语句提炼成不同的方法,比如说提炼为BeforeInvoke,AfterInvoke, HandleError这三个方法,然后在不同的方法里面调用就可以了。
l 还有比上一种方式实现更优雅的方式,就是在代理类中只定义一个Invoke方法,方法的参数是我们需要调用的方法名和参数列表,然后再Invoke方法里面我们利用反射技术调用业务类中对应的方法。此时我们代理类中的方法就十分清爽了
当做完以上的工作,我们就已经用静态代理的方式实现了方法的过滤,然后我们再思考一个问题,如果我们的方法更多而且分布在不同的类里面,又或者我们需要给系统进行进行重构,系统中方法数不胜数,如果采用静态的方式,需要做很多重复的工作,还有我们要追求系统的可扩展性,希望以后添加新的业务逻辑类,不要再新加业务代理类,这个时候我们就希望我们的业务代理是再运行时才开始创建,而不是再编译时,这个时候我们就可以采用动态代理了。
- 动态代理方式
动态代理,又成为运行时代理。在程序运行的过程中,调用了生成代理类的代码,将自动生成业务类的代理类。不需要我们手共编写,极高的提高了工作效率。
动态代理的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. 动态构建代理方法
在第三步中又做了以下几件事情:
- 如果业务方法中存在执行前过滤器,调用执行前过滤器的Execute方法
- 执行业务方法
- 如果业务方法中存在执行后过滤器,调用执行前过滤器的Execute方法
- 如果业务方法中存在异常过滤器,添加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# 使用代理实现方法过滤的更多相关文章
- 动态代理AOP实现方法过滤
上一节实现了动态代理,接下来 有时候,我不需要在每一个方法都要记录日志,做权限验证 等等. 所有就有了这样的需求.AOP实现特定方法过滤,有选择性的来对方法实现AOP 拦截.就是本节标题所示. 举个例 ...
- iOS里面消除使用代理调用方法时间警告问题
iOS里面有三种调用函数的方式: 直接调用方法 [对象名 方法]; performselector: [对象名 perform方法]; NSInvocation 调用 在使用代理调用 ...
- struts2中的方法过滤拦截器
方法过滤拦截器是只过滤指定的方法,如果使用针对action 的普通的过滤器则会过滤该action内部 所有方法.如果在一个action中同时有多个作为业务逻辑控制的方法存在 的话则会过滤所有的业务逻辑 ...
- .Net下HTTP访问穿越多层代理的方法以及代理服务器的验证 转载
https://blog.williamgates.net/2006/07/aspdotnet-through-multi-proxy/ 首先,通过普通的匿名透明代理的方法,是直接使用Socket发送 ...
- java-mybaits-00203-DAO-mapper代理开发方法,多参数【推荐】
程序员只需要mapper接口(相当 于dao接口) 不需要写具体实现类,mapper已经代理完成,mybatis才有的 一.mapper代理开发方法(建议使用) 程序员在编写mapp ...
- 五种WordPress防止垃圾评论方法-过滤垃圾评论提高WP运行效率
WordPress貌似和垃圾评论是一对“孪生兄弟”,无论在国内还是国外的空间主机上搭建的Wordpress博客,无论Wordpress有多少流量多么低的权重,垃圾评论都会自动找上门来,假如有好几天没有 ...
- vue中代理实现方法
vue中代理实现方法如下: const path = require('path'); function resolve(dir) { return path.join(__dirname, dir) ...
- 原生js事件委托(事件代理)方法扩展
原生js事件委托(事件代理)方法扩展: 通过Node底层原型扩展委托方法 /** * 事件委托方法 * @param eventName {string}:事件名称,如'click' * @param ...
- [转] Ubuntu的apt-get 设置代理的方法
点击阅读原文 新立得软件管理器这种图形化的代理设置很明了,这里介绍下终端命令行的网络代理设置,这样大家就可以通过代理进行apt-get了. 方法一: 如果只是想临时使用http代理,可以在使用apt- ...
随机推荐
- IT 常用单词表
程序员英语单词册 前言 程序员必备的600个英语词汇(1) 程序员必备的600个英语词汇(2) 程序员必备的600个英语词汇(3) 程序员必备的600个英语词汇(4) 程序员不 ...
- 刷题记录:[CISCN2019 东北赛区 Day2 Web3]Point System
目录 刷题记录:[CISCN2019 东北赛区 Day2 Web3]Point System 知识点 1.padding-oracle attack 2.cbc字节翻转攻击 3.FFMpeg文件读取漏 ...
- ArgumentException: The Assembly Mono.WebBrowser is referenced by System.Windows.Forms ('Assets/Plugins/System.Windows.Forms.dll'). But the dll is not allowed to be included or could not be found.
最近有个项目要用到System.Windows.Forms.dll,在Unity编辑器里用着还好好的,但是一导出就给我报错,让我十分不爽. 于是请教百度,搜出了五花八门的答案,没一个能解决我的问题的, ...
- Alpha总体规划 & 任务分解
目录 Alpha阶段项目目标 任务拆解和优先级 总体规划 Alpha-1任务分配 Alpha-2任务分配 Alpha阶段项目目标 初步实现北航社团小程序: 北航社团小程序基础功能(优先级中的高两级,即 ...
- Python绘制3D图形
来自:https://www.jb51.net/article/139349.htm 3D图形在数据分析.数据建模.图形和图像处理等领域中都有着广泛的应用,下面将给大家介绍一下如何使用python进行 ...
- 正则表达式在线分析 regex online analyzer
https://regexper.com/#%2F%5B0-9%5D%5Cs%5B0-9%5D%2F https://regexper.com/ http://regexone.com/lesson/ ...
- 详解intent和intentfilter
1.Intent对象简介 Intent中文意思指"意图",按照Android的设计理念,Android使用Intent来封装程序的"调用意图",不管启动Acti ...
- 廖雪峰Git教程3
转自:https://www.liaoxuefeng.com/wiki/896043488029600 [标签管理] 发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签 ...
- Shell流程控制语句case
case语法格式: case 变量或表达式 in 变量或表达式1) 命令1 ;; 变量或表达式2) 命令2 ;; ...... *) 默认命令 esac case语句流程控制图: 实例: [root ...
- vue 框架安装系列问题
npm install --global vue-cli 错误提示:vue-cli-service' 不是内部或外部命令,也不是可运行的程序或批处理文件解决:如果是npm安装的 执行 npm -g b ...