diff --git a/AutoDI.AspNetCore/WebHostBuilderMixins.cs b/AutoDI.AspNetCore/WebHostBuilderMixins.cs
index 0ce7f8d..b273324 100644
--- a/AutoDI.AspNetCore/WebHostBuilderMixins.cs
+++ b/AutoDI.AspNetCore/WebHostBuilderMixins.cs
@@ -1,6 +1,6 @@
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
-[assembly:AutoDI.Settings(AutoInit = false)]
+[assembly:AutoDI.Settings(InitMode = AutoDI.InitMode.None)]
namespace AutoDI.AspNetCore
{
public static class WebHostBuilderMixins
diff --git a/AutoDI.Build.Tests/ManualInjectionOfContainer.cs b/AutoDI.Build.Tests/ManualInjectionOfContainer.cs
index 9ddafcd..a6737b2 100644
--- a/AutoDI.Build.Tests/ManualInjectionOfContainer.cs
+++ b/AutoDI.Build.Tests/ManualInjectionOfContainer.cs
@@ -48,7 +48,7 @@ public void CanManuallyInjectTheGeneratedContainer()
//
//
//
-//
+//
namespace ManualInjectionNamespace
{
using AutoDI;
diff --git a/AutoDI.Build.Tests/ModuleLoadInjectionTests.cs b/AutoDI.Build.Tests/ModuleLoadInjectionTests.cs
new file mode 100644
index 0000000..a57bf48
--- /dev/null
+++ b/AutoDI.Build.Tests/ModuleLoadInjectionTests.cs
@@ -0,0 +1,80 @@
+using AutoDI.AssemblyGenerator;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using ModuleLoadInjectionNamespace;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace AutoDI.Build.Tests
+{
+ [TestClass]
+ public class ModuleLoadInjectionTests
+ {
+ private static Assembly _testAssembly;
+
+ [ClassInitialize]
+ public static async Task Initialize(TestContext context)
+ {
+ var gen = new Generator();
+
+ _testAssembly = (await gen.Execute()).SingleAssembly();
+ }
+
+ [ClassCleanup]
+ public static void Cleanup()
+ {
+ DI.Dispose(_testAssembly);
+ }
+
+ [TestMethod]
+ public void InitThrowsIfModuleLoadAssembly()
+ {
+ try
+ {
+ DI.Init(_testAssembly);
+ }
+ catch (TargetInvocationException e)
+ when (e.InnerException is AlreadyInitializedException)
+ {
+ return;
+ }
+ Assert.Fail($"Excepted {nameof(AlreadyInitializedException)}");
+ }
+
+ [TestMethod]
+ public void TryInitReturnsFalseOnFirstInvocation()
+ {
+ Assert.IsFalse(DI.TryInit(_testAssembly));
+ }
+
+ [TestMethod]
+ public void LibraryDependenciesAreInjected()
+ {
+ dynamic sut = _testAssembly.CreateInstance();
+ Assert.IsTrue(((object)sut.Service).Is());
+ }
+ }
+}
+
+//
+//
+//
+//
+namespace ModuleLoadInjectionNamespace
+{
+ using AutoDI;
+
+ public class ModuleLoadingLibrary
+ {
+ public IService Service { get; }
+
+ public ModuleLoadingLibrary([Dependency] IService service = null)
+ {
+ Service = service;
+ }
+ }
+
+ public interface IService { }
+
+ public class Service : IService { }
+}
+//
diff --git a/AutoDI.Build.Tests/SettingsTests.cs b/AutoDI.Build.Tests/SettingsTests.cs
index d3c74bf..2b833ee 100644
--- a/AutoDI.Build.Tests/SettingsTests.cs
+++ b/AutoDI.Build.Tests/SettingsTests.cs
@@ -20,5 +20,13 @@ public void DebugCodeGenerationDefaultsOff()
Assert.AreEqual((int)CodeLanguage.None, (int)settings.DebugCodeGeneration);
}
+
+ [TestMethod]
+ public void InitModeDefaultsEntryPoint()
+ {
+ var settings = new Settings();
+
+ Assert.AreEqual((int)InitMode.EntryPoint, (int)settings.InitMode);
+ }
}
}
diff --git a/AutoDI.Build/AutoDI.Build.csproj b/AutoDI.Build/AutoDI.Build.csproj
index 5218cba..f6e3f08 100644
--- a/AutoDI.Build/AutoDI.Build.csproj
+++ b/AutoDI.Build/AutoDI.Build.csproj
@@ -28,6 +28,7 @@
+
diff --git a/AutoDI.Build/ProcessAssemblyTask.InjectContainer.cs b/AutoDI.Build/ProcessAssemblyTask.InjectContainer.cs
index c701c29..760a958 100644
--- a/AutoDI.Build/ProcessAssemblyTask.InjectContainer.cs
+++ b/AutoDI.Build/ProcessAssemblyTask.InjectContainer.cs
@@ -1,4 +1,5 @@
-using Mono.Cecil;
+using System.Linq;
+using Mono.Cecil;
using Mono.Cecil.Cil;
namespace AutoDI.Build
@@ -20,5 +21,47 @@ private void InjectInitCall(MethodReference initMethod)
Logger.Debug($"No entry point in {ModuleDefinition.FileName}. Skipping container injection.", DebugLogLevel.Default);
}
}
+
+ private void InjectModuleCctorInitCall(MethodReference initMethod)
+ {
+ var moduleClass = ModuleDefinition.Types.FirstOrDefault(t => t.Name == "");
+ if (moduleClass == null)
+ {
+ Logger.Debug($"No module class in {ModuleDefinition.FileName}. Skipping container injection.", DebugLogLevel.Default);
+ return;
+ }
+
+ var cctor = FindOrCreateCctor(moduleClass);
+ if (cctor != null)
+ {
+ Logger.Debug("Injecting AutoDI .cctor init call", DebugLogLevel.Verbose);
+
+ var injector = new Injector(cctor);
+ injector.Insert(OpCodes.Ldnull);
+ injector.Insert(OpCodes.Call, initMethod);
+ }
+ else
+ {
+ Logger.Debug($"Couldn't find or create .cctor in {ModuleDefinition.FileName}. Skipping container injection.", DebugLogLevel.Default);
+ }
+
+ }
+
+ private MethodDefinition FindOrCreateCctor(TypeDefinition moduleClass)
+ {
+ var cctor = moduleClass.Methods.FirstOrDefault(m => m.Name == ".cctor");
+ if (cctor == null)
+ {
+ var attributes = MethodAttributes.Private
+ | MethodAttributes.HideBySig
+ | MethodAttributes.Static
+ | MethodAttributes.SpecialName
+ | MethodAttributes.RTSpecialName;
+ cctor = new MethodDefinition(".cctor", attributes, ModuleDefinition.ImportReference(typeof(void)));
+ moduleClass.Methods.Add(cctor);
+ cctor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
+ }
+ return cctor;
+ }
}
}
\ No newline at end of file
diff --git a/AutoDI.Build/ProcessAssemblyTask.cs b/AutoDI.Build/ProcessAssemblyTask.cs
index ff6d051..2277bb0 100644
--- a/AutoDI.Build/ProcessAssemblyTask.cs
+++ b/AutoDI.Build/ProcessAssemblyTask.cs
@@ -60,9 +60,20 @@ protected override bool WeaveAssembly()
ModuleDefinition.Types.Add(GenerateAutoDIClass(mapping, settings, gen, out MethodDefinition initMethod));
- if (settings.AutoInit)
+ switch (settings.InitMode)
{
- InjectInitCall(initMethod);
+ case InitMode.None:
+ Logger.Debug("Skipping injections of Init method", DebugLogLevel.Verbose);
+ break;
+ case InitMode.EntryPoint:
+ InjectInitCall(initMethod);
+ break;
+ case InitMode.ModuleLoad:
+ InjectModuleCctorInitCall(initMethod);
+ break;
+ default:
+ Logger.Warning($"Unsupported InitMode: {settings.InitMode}");
+ break;
}
}
else
diff --git a/AutoDI.Build/Settings.cs b/AutoDI.Build/Settings.cs
index e13e8ee..9418ad1 100644
--- a/AutoDI.Build/Settings.cs
+++ b/AutoDI.Build/Settings.cs
@@ -21,8 +21,8 @@ public static Settings Load(ModuleDefinition module)
{
switch (property.Name)
{
- case nameof(SettingsAttribute.AutoInit):
- settings.AutoInit = (bool)property.Argument.Value;
+ case nameof(SettingsAttribute.InitMode):
+ settings.InitMode = (InitMode)property.Argument.Value;
break;
case nameof(SettingsAttribute.Behavior):
settings.Behavior = (Behaviors)property.Argument.Value;
@@ -209,12 +209,12 @@ IList GetConstructorParameterNames()
public Behaviors Behavior { get; set; } = Behaviors.Default;
///
- /// Automatically initialize AutoDI in assembly entry point (if available)
+ /// Specifies if and when AutoDI initializes during assembly loading.
///
- public bool AutoInit { get; set; } = true;
+ public InitMode InitMode { get; set; } = InitMode.EntryPoint;
///
- /// Generate registration calls no the container. Setting to false will negate AutoInit.
+ /// Generate registration calls no the container. Setting to false will negate InitMode.
///
public bool GenerateRegistrations { get; set; } = true;
@@ -236,7 +236,7 @@ public override string ToString()
sb.AppendLine("AutoDI Settings:");
sb.AppendLine($" Behavior(s): {Behavior}");
- sb.AppendLine($" AutoInit: {AutoInit}");
+ sb.AppendLine($" InitMode: {InitMode}");
sb.AppendLine($" GenerateRegistrations: {GenerateRegistrations}");
sb.AppendLine($" DebugLogLevel: {DebugLogLevel}");
sb.AppendLine($" DebugExceptions: {DebugExceptions}");
diff --git a/AutoDI/InitMode.cs b/AutoDI/InitMode.cs
new file mode 100644
index 0000000..e7d0b0e
--- /dev/null
+++ b/AutoDI/InitMode.cs
@@ -0,0 +1,23 @@
+namespace AutoDI
+{
+ ///
+ /// Controls when AutoDI is initialized
+ ///
+ public enum InitMode
+ {
+ ///
+ /// The container must be initialized manually.
+ ///
+ None,
+ ///
+ /// The container will be initialized on your program's entry point.
+ /// Recommended for executable programs.
+ ///
+ EntryPoint,
+ ///
+ /// The container will be initialized on assembly module load.
+ /// Recommended for libraries.
+ ///
+ ModuleLoad
+ }
+}
diff --git a/AutoDI/SettingsAttribute.cs b/AutoDI/SettingsAttribute.cs
index 3d41dc7..48792e1 100644
--- a/AutoDI/SettingsAttribute.cs
+++ b/AutoDI/SettingsAttribute.cs
@@ -6,7 +6,7 @@ namespace AutoDI
public class SettingsAttribute : Attribute
{
public Behaviors Behavior { get; set; }
- public bool AutoInit { get; set; }
+ public InitMode InitMode { get; set; }
public bool GenerateRegistrations { get; set; }
public bool DebugExceptions { get; set; }
public DebugLogLevel DebugLogLevel { get; set; }