void ImplementEvents() { foreach (EventInfo e in ReflectionHelper.GetFlattenEvents(_definition.TypeInterface)) { ProxyOptions optEvent = _definition.GetEventOptions(e); DefineEventSupport(e, optEvent); } }
void ImplementRemainingMethods() { // For each methods in definition.TypeInterface... foreach (MethodInfo m in ReflectionHelper.GetFlattenMethods(_definition.TypeInterface)) { if (!_processedMethods.Contains(m)) { ProxyOptions generationOptions = _definition.GetMethodOptions(m); GenerateInterceptor(m, generationOptions); } } }
public ProxyOptions GetEventOptions( EventInfo e ) { ProxyOptions opt = new ProxyOptions(); opt.CatchExceptions = _errorCatch == CatchExceptionGeneration.Always || (_errorCatch == CatchExceptionGeneration.HonorIgnoreExceptionAttribute && !e.IsDefined( typeof( IgnoreExceptionAttribute ), false )); if( _isDynamicService ) { bool stopAllowed = e.IsDefined( typeof( IgnoreServiceStoppedAttribute ), false ); opt.RuntimeCheckStatus = stopAllowed ? ProxyOptions.CheckStatus.NotDisabled : ProxyOptions.CheckStatus.Running; } else opt.RuntimeCheckStatus = ProxyOptions.CheckStatus.None; return opt; }
void ImplementProperties() { foreach (PropertyInfo p in ReflectionHelper.GetFlattenProperties(_definition.TypeInterface)) { MethodInfo mGet = p.GetGetMethod(true); if (mGet != null) { ProxyOptions optGet = _definition.GetPropertyMethodOptions(p, mGet); GenerateInterceptor(mGet, optGet); } MethodInfo mSet = p.GetSetMethod(true); if (mSet != null) { ProxyOptions optSet = _definition.GetPropertyMethodOptions(p, mSet); GenerateInterceptor(mSet, optSet); } } }
public ProxyOptions GetPropertyMethodOptions(PropertyInfo p, MethodInfo m) { ProxyOptions opt = new ProxyOptions(); opt.CatchExceptions = _errorCatch == CatchExceptionGeneration.Always || (_errorCatch == CatchExceptionGeneration.HonorIgnoreExceptionAttribute && !(p.IsDefined(typeof(IgnoreExceptionAttribute), false) || m.IsDefined(typeof(IgnoreExceptionAttribute), false))); if (_isDynamicService) { bool stopAllowed = p.IsDefined(typeof(IgnoreServiceStoppedAttribute), false) || m.IsDefined(typeof(IgnoreServiceStoppedAttribute), false); opt.RuntimeCheckStatus = stopAllowed ? ProxyOptions.CheckStatus.NotDisabled : ProxyOptions.CheckStatus.Running; } else { opt.RuntimeCheckStatus = ProxyOptions.CheckStatus.None; } return(opt); }
/// <summary> /// Generates the exact signature and the code that relays the call /// to the _impl corresponding method. /// </summary> void GenerateInterceptor(MethodInfo m, ProxyOptions generationOptions) { // Registers the method. Debug.Assert(m != null && !_processedMethods.Contains(m)); _processedMethods.Add(m); Type[] parameters; MethodBuilder mB = CreateInterfaceMethodBuilder(_typeBuilder, m, out parameters); SetDebuggerStepThroughAttribute(mB); int metaRef = RegisterRef(_mRefs, m); #region Body generation { ILGenerator g = mB.GetILGenerator(); LocalBuilder logOption = g.DeclareLocal(typeof(ServiceLogMethodOptions)); LocalBuilder logger = g.DeclareLocal(typeof(LogMethodEntry)); // The retValue local is used only if we must intercept // the return value (of course, if there is a return value). LocalBuilder retValue = null; if (m.ReturnType != typeof(void)) { retValue = g.DeclareLocal(m.ReturnType); } g.Emit(OpCodes.Ldarg_0); g.LdInt32(metaRef); g.Emit(OpCodes.Ldloca_S, logger); string getLoggerName; switch (generationOptions.RuntimeCheckStatus) { case ProxyOptions.CheckStatus.None: getLoggerName = "GetLoggerForAnyCall"; break; case ProxyOptions.CheckStatus.NotDisabled: getLoggerName = "GetLoggerForNotDisabledCall"; break; default: getLoggerName = "GetLoggerForRunningCall"; break; //ProxyOptions.CheckStatus.Running } g.EmitCall(OpCodes.Call, _definition.ProxyBase.GetMethod(getLoggerName, BindingFlags.NonPublic | BindingFlags.Instance), null); g.StLoc(logOption); if (parameters.Length > 0) { Label skipLogParam = g.DefineLabel(); g.LdLoc(logOption); g.LdInt32((int)ServiceLogMethodOptions.LogParameters); g.Emit(OpCodes.And); g.Emit(OpCodes.Brfalse, skipLogParam); LocalBuilder paramsArray = g.DeclareLocal(typeof(object[])); g.CreateObjectArrayFromInstanceParameters(paramsArray, parameters); g.LdLoc(logger); g.LdLoc(paramsArray); g.Emit(OpCodes.Stfld, typeof(LogMethodEntry).GetField("_parameters", BindingFlags.Instance | BindingFlags.NonPublic)); g.MarkLabel(skipLogParam); } LocalBuilder exception = null; if (generationOptions.CatchExceptions) { exception = g.DeclareLocal(typeof(Exception)); g.BeginExceptionBlock(); } // Pushes the _impl field on the stack. g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, _implField); // Pushes all the parameters on the stack. g.RepushActualParameters(false, parameters.Length); g.EmitCall(OpCodes.Callvirt, m, null); // if( (o & LogMethodOptions.Leave) != 0 ) g.LdLoc(logOption); g.LdInt32((int)ServiceLogMethodOptions.Leave); g.Emit(OpCodes.And); Label skipLogPostCall = g.DefineLabel(); g.Emit(OpCodes.Brfalse, skipLogPostCall); // { if (retValue == null) { g.Emit(OpCodes.Ldarg_0); g.LdLoc(logger); g.EmitCall(OpCodes.Call, _definition.ProxyBase.GetMethod("LogEndCall", BindingFlags.NonPublic | BindingFlags.Instance), null); } else { Label skipLogWithValue = g.DefineLabel(); g.LdLoc(logOption); g.LdInt32((int)ServiceLogMethodOptions.LogReturnValue); g.Emit(OpCodes.And); g.Emit(OpCodes.Brfalse, skipLogWithValue); // Save retValue. g.StLoc(retValue); g.Emit(OpCodes.Ldarg_0); g.LdLoc(logger); g.LdLoc(retValue); if (m.ReturnType.IsGenericParameter || m.ReturnType.IsValueType) { g.Emit(OpCodes.Box, m.ReturnType); } g.EmitCall(OpCodes.Call, _definition.ProxyBase.GetMethod("LogEndCallWithValue", BindingFlags.NonPublic | BindingFlags.Instance), null); // Repush retValue and go to end. g.LdLoc(retValue); g.Emit(OpCodes.Br_S, skipLogPostCall); // Just call LogEndCall without return value management (stack is okay). g.MarkLabel(skipLogWithValue); g.Emit(OpCodes.Ldarg_0); g.LdLoc(logger); g.EmitCall(OpCodes.Call, _definition.ProxyBase.GetMethod("LogEndCall", BindingFlags.NonPublic | BindingFlags.Instance), null); } // } g.MarkLabel(skipLogPostCall); if (generationOptions.CatchExceptions) { Label end = g.DefineLabel(); g.Emit(OpCodes.Br_S, end); g.BeginCatchBlock(typeof(Exception)); g.StLoc(exception); // if( (o & LogMethodOptions.LogError) != 0 ) g.LdLoc(logOption); g.LdInt32((int)ServiceLogMethodOptions.LogError); g.Emit(OpCodes.And); Label skipExceptionCall = g.DefineLabel(); g.Emit(OpCodes.Brfalse, skipExceptionCall); g.Emit(OpCodes.Ldarg_0); g.LdInt32(metaRef); g.LdLoc(exception); g.LdLoc(logger); g.EmitCall(OpCodes.Call, _definition.ProxyBase.GetMethod("OnCallException", BindingFlags.NonPublic | BindingFlags.Instance), null); g.MarkLabel(skipExceptionCall); g.Emit(OpCodes.Rethrow); g.EndExceptionBlock(); g.MarkLabel(end); } g.Emit(OpCodes.Ret); } #endregion }
void DefineEventSupport(EventInfo e, ProxyOptions generationOptions) { // Defines the hook field: Delegate _dXXX; FieldBuilder dField = _typeBuilder.DefineField("_d" + e.Name, typeof(Delegate), FieldAttributes.Private); // Defines the event field: <EventHandler> _hookXXX; FieldBuilder hField = _typeBuilder.DefineField("_hook" + e.Name, e.EventHandlerType, FieldAttributes.Private); int eventMetaRef = RegisterRef(_eRefs, e); // Implements our hook method. MethodBuilder mHookB; { MethodInfo mCall = e.EventHandlerType.GetMethod("Invoke"); Type[] parameters = ReflectionHelper.CreateParametersType(mCall.GetParameters()); mHookB = _typeBuilder.DefineMethod("_realService_" + e.Name, MethodAttributes.Private, CallingConventions.HasThis, typeof(void), parameters); { SetDebuggerStepThroughAttribute(mHookB); ILGenerator g = mHookB.GetILGenerator(); LocalBuilder logOptions = g.DeclareLocal(typeof(ServiceLogEventOptions)); LocalBuilder logger = g.DeclareLocal(typeof(LogEventEntry)); g.Emit(OpCodes.Ldarg_0); g.LdInt32(eventMetaRef); g.Emit(OpCodes.Ldloca_S, logger); g.Emit(OpCodes.Ldloca_S, logOptions); string getLoggerName; switch (generationOptions.RuntimeCheckStatus) { case ProxyOptions.CheckStatus.None: getLoggerName = "GetLoggerEventForAnyCall"; break; case ProxyOptions.CheckStatus.NotDisabled: getLoggerName = "GetLoggerEventForNotDisabledCall"; break; default: getLoggerName = "GetLoggerEventForRunningCall"; break; //ProxyOptions.CheckStatus.Running } g.EmitCall(OpCodes.Call, _definition.ProxyBase.GetMethod(getLoggerName, BindingFlags.NonPublic | BindingFlags.Instance), null); Label doRaise = g.DefineLabel(); g.Emit(OpCodes.Brtrue_S, doRaise); g.Emit(OpCodes.Ret); g.MarkLabel(doRaise); LocalBuilder client = g.DeclareLocal(typeof(Delegate)); LocalBuilder exception = generationOptions.CatchExceptions ? g.DeclareLocal(typeof(Exception)) : null; LocalBuilder list = g.DeclareLocal(typeof(Delegate[])); LocalBuilder listLength = g.DeclareLocal(typeof(int)); LocalBuilder index = g.DeclareLocal(typeof(int)); // Maps actual parameters. for (int i = 0; i < parameters.Length; ++i) { if (parameters[i].IsAssignableFrom(_definition.TypeInterface)) { g.LdArg(i + 1); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, _implField); Label notTheSender = g.DefineLabel(); g.Emit(OpCodes.Bne_Un_S, notTheSender); g.Emit(OpCodes.Ldarg_0); g.StArg(i + 1); g.MarkLabel(notTheSender); } } // Should we log parameters? if (parameters.Length > 0) { Label skipLogParam = g.DefineLabel(); g.LdLoc(logOptions); g.LdInt32((int)ServiceLogEventOptions.LogParameters); g.Emit(OpCodes.And); g.Emit(OpCodes.Brfalse, skipLogParam); LocalBuilder paramsArray = g.DeclareLocal(typeof(object[])); g.CreateObjectArrayFromInstanceParameters(paramsArray, parameters); g.LdLoc(logger); g.LdLoc(paramsArray); g.Emit(OpCodes.Stfld, typeof(LogEventEntry).GetField("_parameters", BindingFlags.Instance | BindingFlags.NonPublic)); g.MarkLabel(skipLogParam); } // Gets all the delegate to call in list. g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, dField); g.EmitCall(OpCodes.Callvirt, _delegateGetInvocationList, null); g.StLoc(list); // listLength = list.Length; g.LdLoc(list); g.Emit(OpCodes.Ldlen); g.Emit(OpCodes.Conv_I4); g.StLoc(listLength); // index = 0; g.Emit(OpCodes.Ldc_I4_0); g.StLoc(index); Label beginOfLoop = g.DefineLabel(); Label endOfLoop = g.DefineLabel(); g.Emit(OpCodes.Br_S, endOfLoop); g.MarkLabel(beginOfLoop); // client = list[index]; g.LdLoc(list); g.LdLoc(index); g.Emit(OpCodes.Ldelem_Ref); g.StLoc(client); if (generationOptions.CatchExceptions) { g.BeginExceptionBlock(); } g.LdLoc(client); g.Emit(OpCodes.Castclass, e.EventHandlerType); g.RepushActualParameters(false, parameters.Length); g.EmitCall(OpCodes.Callvirt, mCall, null); if (generationOptions.CatchExceptions) { Label bottomOfLoop = g.DefineLabel(); g.Emit(OpCodes.Leave_S, bottomOfLoop); g.BeginCatchBlock(typeof(Exception)); g.StLoc(exception); g.Emit(OpCodes.Ldarg_0); g.LdInt32(eventMetaRef); g.LdLoc(client); g.EmitCall(OpCodes.Callvirt, _delegateGetMethod, null); g.LdLoc(exception); g.Emit(OpCodes.Ldloca_S, logger); g.EmitCall(OpCodes.Call, _definition.ProxyBase.GetMethod("OnEventHandlingException", BindingFlags.NonPublic | BindingFlags.Instance), null); Label continueDispatch = g.DefineLabel(); g.Emit(OpCodes.Brtrue_S, continueDispatch); g.Emit(OpCodes.Rethrow); g.MarkLabel(continueDispatch); g.Emit(OpCodes.Leave_S, bottomOfLoop); g.EndExceptionBlock(); g.MarkLabel(bottomOfLoop); } // ++index; g.LdLoc(index); g.Emit(OpCodes.Ldc_I4_1); g.Emit(OpCodes.Add); g.StLoc(index); // Checks whether we must continue the loop. g.MarkLabel(endOfLoop); g.LdLoc(index); g.LdLoc(listLength); g.Emit(OpCodes.Blt_S, beginOfLoop); // if( (o & LogMethodOptions.Leave) != 0 ) // { g.LdLoc(logOptions); g.LdInt32((int)ServiceLogEventOptions.EndRaise); g.Emit(OpCodes.And); Label skipLogPostCall = g.DefineLabel(); g.Emit(OpCodes.Brfalse, skipLogPostCall); g.Emit(OpCodes.Ldarg_0); g.LdLoc(logger); g.EmitCall(OpCodes.Call, _definition.ProxyBase.GetMethod("LogEndRaise", BindingFlags.NonPublic | BindingFlags.Instance), null); g.MarkLabel(skipLogPostCall); // } g.Emit(OpCodes.Ret); } } // Defines the event property itself: <EventHandler> XXX; EventBuilder eB = _typeBuilder.DefineEvent(e.Name, e.Attributes, e.EventHandlerType); // Implements the add_ MethodInfo mAdd = e.GetAddMethod(true); if (mAdd != null) { // Registers the method to skip its processing. _processedMethods.Add(mAdd); Type[] parameters = ReflectionHelper.CreateParametersType(mAdd.GetParameters()); MethodBuilder mAddB = _typeBuilder.DefineMethod(mAdd.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, CallingConventions.HasThis, mAdd.ReturnType, parameters); { SetDebuggerStepThroughAttribute(mAddB); ILGenerator g = mAddB.GetILGenerator(); Label dFieldOK = g.DefineLabel(); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, dField); g.Emit(OpCodes.Brtrue_S, dFieldOK); Label hFieldOK = g.DefineLabel(); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, hField); g.Emit(OpCodes.Brtrue_S, hFieldOK); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldftn, mHookB); g.Emit(OpCodes.Newobj, e.EventHandlerType.GetConstructor(new Type[] { typeof(Object), typeof(IntPtr) })); g.Emit(OpCodes.Stfld, hField); g.MarkLabel(hFieldOK); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, _implField); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, hField); g.Emit(OpCodes.Callvirt, mAdd); g.MarkLabel(dFieldOK); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, dField); g.Emit(OpCodes.Ldarg_1); g.Emit(OpCodes.Call, _delegateCombine); g.Emit(OpCodes.Stfld, dField); g.Emit(OpCodes.Ret); } eB.SetAddOnMethod(mAddB); } // Implements the remove_ MethodInfo mRemove = e.GetRemoveMethod(true); if (mRemove != null) { // Registers the method to skip its processing. _processedMethods.Add(mRemove); Type[] parameters = ReflectionHelper.CreateParametersType(mRemove.GetParameters()); MethodBuilder mRemoveB = _typeBuilder.DefineMethod(mRemove.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, CallingConventions.HasThis, mRemove.ReturnType, parameters); { SetDebuggerStepThroughAttribute(mRemoveB); ILGenerator g = mRemoveB.GetILGenerator(); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, dField); g.Emit(OpCodes.Ldarg_1); g.Emit(OpCodes.Call, _delegateRemove); g.Emit(OpCodes.Stfld, dField); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, dField); Label end = g.DefineLabel(); g.Emit(OpCodes.Brtrue_S, end); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, _implField); g.Emit(OpCodes.Ldarg_0); g.Emit(OpCodes.Ldfld, hField); g.Emit(OpCodes.Callvirt, mRemove); g.MarkLabel(end); g.Emit(OpCodes.Ret); } eB.SetRemoveOnMethod(mRemoveB); } }