Пример #1
0
 void ImplementEvents()
 {
     foreach (EventInfo e in ReflectionHelper.GetFlattenEvents(_definition.TypeInterface))
     {
         ProxyOptions optEvent = _definition.GetEventOptions(e);
         DefineEventSupport(e, optEvent);
     }
 }
Пример #2
0
 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);
         }
     }
 }
Пример #3
0
        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;
        }
Пример #4
0
 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);
         }
     }
 }
Пример #5
0
        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);
        }
Пример #6
0
            /// <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
            }
Пример #7
0
            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);
                }
            }