Exemple #1
0
    private MethodDefinition GenerateDisposeMethod(FieldDefinition globalServiceProvider)
    {
        var disposeMethod = new MethodDefinition(nameof(DI.Dispose),
                                                 MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static,
                                                 ModuleDefinition.ImportReference(typeof(void)));

        VariableDefinition disposable = new VariableDefinition(ModuleDefinition.Get <IDisposable>());

        disposeMethod.Body.Variables.Add(disposable);

        ILProcessor processor    = disposeMethod.Body.GetILProcessor();
        Instruction afterDispose = Instruction.Create(OpCodes.Nop);

        processor.Emit(OpCodes.Ldsfld, globalServiceProvider);
        processor.Emit(OpCodes.Isinst, ModuleDefinition.Get <IDisposable>());
        processor.Emit(OpCodes.Dup);
        processor.Emit(OpCodes.Stloc_0); //disposable
        processor.Emit(OpCodes.Brfalse_S, afterDispose);
        processor.Emit(OpCodes.Ldloc_0); //disposable
        processor.Emit(OpCodes.Callvirt, ModuleDefinition.GetMethod <IDisposable>(nameof(IDisposable.Dispose)));

        processor.Append(afterDispose);

        processor.Emit(OpCodes.Ldsfld, globalServiceProvider);
        processor.Emit(OpCodes.Call, Import.GlobalDI_Unregister);
        processor.Emit(OpCodes.Pop);

        processor.Emit(OpCodes.Ldnull);
        processor.Emit(OpCodes.Stsfld, globalServiceProvider);

        processor.Emit(OpCodes.Ret);
        return(disposeMethod);
    }
Exemple #2
0
    //TODO: out parameters... yuck
    private TypeDefinition GenerateAutoDIClass(Mapping mapping, Settings settings,
                                               out MethodDefinition initMethod)
    {
        var containerType = new TypeDefinition(DI.Namespace, DI.TypeName,
                                               TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed
                                               | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit)
        {
            BaseType = ModuleDefinition.Get <object>()
        };

        FieldDefinition globalServiceProvider =
            ModuleDefinition.CreateStaticReadonlyField(DI.GlobalServiceProviderName, false, Import.IServiceProvider);

        containerType.Fields.Add(globalServiceProvider);

        MethodDefinition configureMethod = GenerateAddServicesMethod(mapping, settings, containerType);

        containerType.Methods.Add(configureMethod);

        initMethod = GenerateInitMethod(configureMethod, globalServiceProvider);
        containerType.Methods.Add(initMethod);

        MethodDefinition disposeMethod = GenerateDisposeMethod(globalServiceProvider);

        containerType.Methods.Add(disposeMethod);

        return(containerType);
    }
Exemple #3
0
        public static FieldDefinition CreateReadonlyField <T>(this ModuleDefinition moduleDefinition, string name, bool @public)
        {
            if (moduleDefinition == null)
            {
                throw new ArgumentNullException(nameof(moduleDefinition));
            }
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            return(moduleDefinition.CreateReadonlyField(name, @public, moduleDefinition.Get <T>()));
        }
Exemple #4
0
    private MethodDefinition GenerateAddServicesMethod(Mapping mapping, Settings settings, TypeDefinition containerType)
    {
        var method = new MethodDefinition(nameof(DI.AddServices),
                                          MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static,
                                          ModuleDefinition.ImportReference(typeof(void)));

        var serviceCollection = new ParameterDefinition("collection", ParameterAttributes.None, ModuleDefinition.Get <IServiceCollection>());

        method.Parameters.Add(serviceCollection);

        ILProcessor processor = method.Body.GetILProcessor();

        VariableDefinition exceptionList = null;
        VariableDefinition exception     = null;
        TypeDefinition     listType      = null;

        if (settings.DebugExceptions)
        {
            var genericType = ModuleDefinition.ImportReference(Import.List_Type.MakeGenericInstanceType(Import.System_Exception));
            listType      = genericType.Resolve();
            exceptionList = new VariableDefinition(genericType);
            exception     = new VariableDefinition(Import.System_Exception);

            method.Body.Variables.Add(exceptionList);
            method.Body.Variables.Add(exception);

            MethodReference listCtor = ModuleDefinition.ImportReference(Import.List_Type.GetConstructors().Single(c => c.IsPublic && c.Parameters.Count == 0));
            listCtor = listCtor.MakeGenericDeclaringType(Import.System_Exception);

            processor.Emit(OpCodes.Newobj, listCtor);
            processor.Emit(OpCodes.Stloc, exceptionList);
        }

        MethodDefinition funcCtor = ModuleDefinition.ResolveCoreConstructor(typeof(Func <,>));

        if (mapping != null)
        {
            int factoryIndex = 0;
            foreach (TypeMap map in mapping)
            {
                try
                {
                    Logger.Debug($"Processing map for {map.TargetType.FullName}", DebugLogLevel.Verbose);

                    MethodDefinition factoryMethod = GenerateFactoryMethod(map.TargetType, factoryIndex);
                    if (factoryMethod == null)
                    {
                        Logger.Debug($"No acceptable constructor for '{map.TargetType.FullName}', skipping map",
                                     DebugLogLevel.Verbose);
                        continue;
                    }
                    containerType.Methods.Add(factoryMethod);
                    factoryIndex++;

                    foreach (TypeLifetime typeLifetime in map.Lifetimes)
                    {
                        var tryStart = Instruction.Create(OpCodes.Ldarg_0); //collection parameter
                        processor.Append(tryStart);

                        processor.Emit(OpCodes.Ldnull);
                        processor.Emit(OpCodes.Ldftn, factoryMethod);
                        processor.Emit(OpCodes.Newobj,
                                       ModuleDefinition.ImportReference(
                                           funcCtor.MakeGenericDeclaringType(Import.IServiceProvider,
                                                                             map.TargetType)));

                        processor.Emit(OpCodes.Ldc_I4, typeLifetime.Keys.Count);
                        processor.Emit(OpCodes.Newarr, Import.System_Type);

                        int arrayIndex = 0;
                        foreach (TypeDefinition key in typeLifetime.Keys)
                        {
                            TypeReference importedKey = ModuleDefinition.ImportReference(key);
                            Logger.Debug(
                                $"Mapping {importedKey.FullName} => {map.TargetType.FullName} ({typeLifetime.Lifetime})",
                                DebugLogLevel.Default);
                            processor.Emit(OpCodes.Dup);
                            processor.Emit(OpCodes.Ldc_I4, arrayIndex++);
                            processor.Emit(OpCodes.Ldtoken, importedKey);
                            processor.Emit(OpCodes.Call, Import.Type_GetTypeFromHandle);
                            processor.Emit(OpCodes.Stelem_Ref);
                        }

                        processor.Emit(OpCodes.Ldc_I4, (int)typeLifetime.Lifetime);

                        var genericAddMethod =
                            new GenericInstanceMethod(Import.ServiceCollectionMixins_AddAutoDIService);
                        genericAddMethod.GenericArguments.Add(ModuleDefinition.ImportReference(map.TargetType));
                        processor.Emit(OpCodes.Call, genericAddMethod);
                        processor.Emit(OpCodes.Pop);

                        if (settings.DebugExceptions)
                        {
                            Instruction afterCatch = Instruction.Create(OpCodes.Nop);
                            processor.Emit(OpCodes.Leave_S, afterCatch);

                            Instruction handlerStart = Instruction.Create(OpCodes.Stloc, exception);
                            processor.Append(handlerStart);
                            processor.Emit(OpCodes.Ldloc, exceptionList);
                            processor.Emit(OpCodes.Ldstr, $"Error adding type '{map.TargetType.FullName}' with key(s) '{string.Join(",", typeLifetime.Keys.Select(x => x.FullName))}'");
                            processor.Emit(OpCodes.Ldloc, exception);

                            processor.Emit(OpCodes.Newobj, Import.AutoDIException_Ctor);
                            var listAdd = ModuleDefinition.ImportReference(Import.List_Type.GetMethods().Single(m => m.Name == "Add" && m.IsPublic && m.Parameters.Count == 1));
                            listAdd = listAdd.MakeGenericDeclaringType(Import.System_Exception);

                            processor.Emit(OpCodes.Callvirt, listAdd);

                            Instruction handlerEnd = Instruction.Create(OpCodes.Leave_S, afterCatch);
                            processor.Append(handlerEnd);

                            var exceptionHandler =
                                new ExceptionHandler(ExceptionHandlerType.Catch)
                            {
                                CatchType    = Import.System_Exception,
                                TryStart     = tryStart,
                                TryEnd       = handlerStart,
                                HandlerStart = handlerStart,
                                HandlerEnd   = afterCatch,
                            };

                            method.Body.ExceptionHandlers.Add(exceptionHandler);

                            processor.Append(afterCatch);
                        }
                    }
                }
                catch (MultipleConstructorException e)
                {
                    Logger.Error($"Failed to create map for {map}\r\n{e}");
                }
                catch (Exception e)
                {
                    Logger.Warning($"Failed to create map for {map}\r\n{e}");
                }
            }
        }

        Instruction @return = Instruction.Create(OpCodes.Ret);

        if (settings.DebugExceptions)
        {
            Instruction loadList = Instruction.Create(OpCodes.Ldloc, exceptionList);
            processor.Append(loadList);

            var listCount = ModuleDefinition.ImportReference(listType.GetMethods().Single(m => m.IsPublic && m.Name == "get_Count"));
            listCount = listCount.MakeGenericDeclaringType(Import.System_Exception);
            processor.Emit(OpCodes.Callvirt, listCount);
            processor.Emit(OpCodes.Ldc_I4_0);
            processor.Emit(OpCodes.Cgt);
            processor.Emit(OpCodes.Brfalse_S, @return);

            processor.Emit(OpCodes.Ldstr, $"Error in {DI.TypeName}.{nameof(DI.AddServices)}() generated method");
            processor.Emit(OpCodes.Ldloc, exceptionList);

            processor.Emit(OpCodes.Newobj, Import.System_AggregateException_Ctor);
            processor.Emit(OpCodes.Throw);
        }

        processor.Append(@return);

        return(method);
    }
Exemple #5
0
    private MethodDefinition GenerateInitMethod(MethodDefinition configureMethod, FieldDefinition globalServiceProvider)
    {
        var initMethod = new MethodDefinition(nameof(DI.Init),
                                              MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static,
                                              ModuleDefinition.ImportReference(typeof(void)));
        var configureAction = new ParameterDefinition("configure", ParameterAttributes.None, ModuleDefinition.Get <Action <IApplicationBuilder> >());

        initMethod.Parameters.Add(configureAction);

        var applicationBuilder = new VariableDefinition(ModuleDefinition.Get <IApplicationBuilder>());

        initMethod.Body.Variables.Add(applicationBuilder);
        ILProcessor initProcessor = initMethod.Body.GetILProcessor();

        Instruction createApplicationbuilder = Instruction.Create(OpCodes.Newobj, ModuleDefinition.GetDefaultConstructor <ApplicationBuilder>());

        initProcessor.Emit(OpCodes.Ldsfld, globalServiceProvider);
        initProcessor.Emit(OpCodes.Brfalse_S, createApplicationbuilder);
        //Compare
        initProcessor.Emit(OpCodes.Newobj, ModuleDefinition.GetConstructor <AlreadyInitializedException>());
        initProcessor.Emit(OpCodes.Throw);

        initProcessor.Append(createApplicationbuilder);
        initProcessor.Emit(OpCodes.Stloc_0);

        initProcessor.Emit(OpCodes.Ldloc_0); //applicationBuilder
        initProcessor.Emit(OpCodes.Ldnull);
        initProcessor.Emit(OpCodes.Ldftn, configureMethod);
        initProcessor.Emit(OpCodes.Newobj, ModuleDefinition.GetConstructor <Action <IServiceCollection> >());
        initProcessor.Emit(OpCodes.Callvirt, ModuleDefinition.GetMethod <IApplicationBuilder>(nameof(IApplicationBuilder.ConfigureServices)));
        initProcessor.Emit(OpCodes.Pop);

        MethodDefinition setupMethod = SetupMethod.Find(ModuleDefinition, Logger);

        if (setupMethod != null)
        {
            Logger.Debug($"Found setup method '{setupMethod.FullName}'", DebugLogLevel.Default);
            initProcessor.Emit(OpCodes.Ldloc_0); //applicationBuilder
            initProcessor.Emit(OpCodes.Call, setupMethod);
            initProcessor.Emit(OpCodes.Nop);
        }
        else
        {
            Logger.Debug("No setup method found", DebugLogLevel.Default);
        }

        Instruction loadForBuild = Instruction.Create(OpCodes.Ldloc_0);

        initProcessor.Emit(OpCodes.Ldarg_0);
        initProcessor.Emit(OpCodes.Brfalse_S, loadForBuild);
        initProcessor.Emit(OpCodes.Ldarg_0);
        initProcessor.Emit(OpCodes.Ldloc_0);
        initProcessor.Emit(OpCodes.Callvirt, ModuleDefinition.GetMethod <Action <IApplicationBuilder> >(nameof(Action <IApplicationBuilder> .Invoke)));


        initProcessor.Append(loadForBuild);
        var buildMethod = ModuleDefinition.GetMethod <IApplicationBuilder>(nameof(IApplicationBuilder.Build));

        buildMethod.ReturnType = Import.IServiceProvider; //Must update the return type to handle .net core apps
        initProcessor.Emit(OpCodes.Callvirt, buildMethod);
        initProcessor.Emit(OpCodes.Stsfld, globalServiceProvider);

        initProcessor.Emit(OpCodes.Ldsfld, globalServiceProvider);
        initProcessor.Emit(OpCodes.Call, Import.GlobalDI_Register);


        initProcessor.Emit(OpCodes.Ret);

        return(initMethod);
    }
Exemple #6
0
 public static TypeDefinition Resolve <T>(this ModuleDefinition module)
 {
     return(module.Get <T>().Resolve());
 }
    private MethodDefinition GenerateConfigureMethod(Mapping mapping, TypeDefinition containerType)
    {
        var method = new MethodDefinition(nameof(DI.AddServices),
                                          MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static,
                                          ModuleDefinition.ImportReference(typeof(void)));

        var serviceCollection = new ParameterDefinition("collection", ParameterAttributes.None, ModuleDefinition.Get <IServiceCollection>());

        method.Parameters.Add(serviceCollection);

        ILProcessor processor = method.Body.GetILProcessor();

        MethodDefinition funcCtor = ModuleDefinition.ResolveCoreConstructor(typeof(Func <,>));

        if (mapping != null)
        {
            int factoryIndex = 0;
            foreach (TypeMap map in mapping)
            {
                try
                {
                    InternalLogDebug($"Processing map for {map.TargetType.FullName}", DebugLogLevel.Verbose);

                    MethodDefinition factoryMethod = GenerateFactoryMethod(map.TargetType, factoryIndex);
                    if (factoryMethod == null)
                    {
                        InternalLogDebug($"No acceptable constructor for '{map.TargetType.FullName}', skipping map",
                                         DebugLogLevel.Verbose);
                        continue;
                    }
                    containerType.Methods.Add(factoryMethod);
                    factoryIndex++;

                    foreach (TypeLifetime typeLifetime in map.Lifetimes)
                    {
                        processor.Emit(OpCodes.Ldarg_0); //collection parameter

                        processor.Emit(OpCodes.Ldnull);
                        processor.Emit(OpCodes.Ldftn, factoryMethod);
                        processor.Emit(OpCodes.Newobj,
                                       ModuleDefinition.ImportReference(
                                           funcCtor.MakeGenericTypeConstructor(Import.IServiceProvider,
                                                                               map.TargetType)));

                        processor.Emit(OpCodes.Ldc_I4, typeLifetime.Keys.Count);
                        processor.Emit(OpCodes.Newarr, Import.System_Type);

                        int arrayIndex = 0;

                        foreach (TypeDefinition key in typeLifetime.Keys)
                        {
                            TypeReference importedKey = ModuleDefinition.ImportReference(key);
                            InternalLogDebug(
                                $"Mapping {importedKey.FullName} => {map.TargetType.FullName} ({typeLifetime.Lifetime})",
                                DebugLogLevel.Default);
                            processor.Emit(OpCodes.Dup);
                            processor.Emit(OpCodes.Ldc_I4, arrayIndex++);
                            processor.Emit(OpCodes.Ldtoken, importedKey);
                            processor.Emit(OpCodes.Call, Import.Type_GetTypeFromHandle);
                            processor.Emit(OpCodes.Stelem_Ref);
                        }

                        processor.Emit(OpCodes.Ldc_I4, (int)typeLifetime.Lifetime);

                        var genericAddMethod =
                            new GenericInstanceMethod(Import.ServiceCollectionMixins_AddAutoDIService);
                        genericAddMethod.GenericArguments.Add(ModuleDefinition.ImportReference(map.TargetType));
                        processor.Emit(OpCodes.Call, genericAddMethod);
                        processor.Emit(OpCodes.Pop);
                    }
                }
                catch (MultipleConstructorAutoDIException e)
                {
                    LogError($"Failed to create map for {map}\r\n{e}");
                }
                catch (Exception e)
                {
                    LogWarning($"Failed to create map for {map}\r\n{e}");
                }
            }
        }

        processor.Emit(OpCodes.Ret);

        return(method);
    }