-
Notifications
You must be signed in to change notification settings - Fork 17
Configuration Legacy
For the latest infomration see here
- Generate Debuggable Code
- Generate Registrations
- Included Assemblies
- Custom Mapping
- Object Lifetime
- Behaviors
- Auto Initialization
- Debug Log Level
- Debug Exceptions
- Constructor Selection
- Property Injection
Be sure to do a full rebuild of your project after modifying FodyWeavers.xml
Run time configuration ([SetupMethodAttribute]
)
The following configurations are all specified within the AutoDI node in the FodyWeavers.xml file. All of the node names and attributes are case insensitive. These configurations are processed in order, so if there are rules that match the same type, the last one wins.
Default: None
<AutoDI DebugCodeGeneration="CSharp"/>
Valid values: None
, CSharp
[assembly:AutoDI.Settings(DebugCodeGeneration = CodeLanguage.CSharp)]
AutoDI can generate debuggable code to allow you to see the dependency parameters get resolved. This feature is off by default. It will also generate reference code for the initialization code. The code that it generates should be considered reference code. This code was not compiled to produce the final output, rather it is a reflection of the IL that was generated in the final output.
Default: True
<AutoDI GenerateRegistrations="false" />
[assembly:AutoDI.Settings(GenerateRegistrations = false)]
When this is true, AutoDI will construct a mapping of all types and build up all of the dependency registrations. These registrations are added at run time when AutoDI is initialized.
Default: none
<AutoDI>
<Assembly Name="MyCompany.*" />
</AutoDI>
AutoDI will always scan the assembly being processed by the Fody weaver (ie. the assembly with the AutoDI.Fody nuget package installed) when building up the list of types to register. If there are additional dependent assemblies that AutoDI should also include you can specify them with an <assembly />
node inside of the AutoDI node. The Name
attribute is a regular expression that is used to match on the assembly's full name.
Default: none
<AutoDI>
<Map From=".I*" To=".*" Lifetime="Singleton" />
<Map From="regex:Interfaces\.I(.*)" To="regex:Services\.$1" Force="False" />
</AutoDI>
If you need to configure a specific mapping between types you can specify it with a <map />
node specifying the From
and To
types. Both of these attributes may contain a wildcard (*). In the first example <Map From=".I*" To=".*" />
maps all types that start with an 'I' to their corresponding type without the 'I' prefix. Note that the .
in this example are being used to match a namespace delimiter and are not regular expressions. A wildcard in the To
attribute will be replaced with the matched wildcard value in the From
attribute.
The From
and To
attributes can also contain regular expressions to allow for more complex matching scenarios. For these prefix the value with "regex:" (as seen above). The pattern in the To
attribute may contain regex groups that were matched in the From
attribute. This allows for some more complex mappings to be declared.
Map
nodes may also specify a Lifetime
attribute for all of the mappings that are generated from it. This lifetime may be overridden by Type
nodes (see below for valid values). Mapping that do not have an explicit mapping will use LazySingleton
.
AutoDI will also verify that the target type (specified in the To
attribute) can be cast to the service type (specified in the From
attribute). If the service type is not in the target type's hierarchy it will ignore the mapping. You can disable this check by setting the Force
attribute to true (default is false).
When matching on nested types you may use either '/' or '+' to denote a nested class.
<Map From="Container+*" To="Container/*" />
Note: In v3.0.0 all From and To attribute values were treated as regex (without the "regex:" prefix)
Default: none
<AutoDI>
<Type Name="Namespace\..+Service" Lifetime="Transient" />
</AutoDI>
Unless otherwise specified, the generated registrations by AutoDI have a lifetime of LazySingleton (see below). You can change the lifetime used for generated registration with a <type />
node. The Name
attribute is processed as a regular expression. All generated registrations whose target type's full name matches this pattern will use the specified lifetime.
AutoDI supports the following lifetimes:
- LazySingleton (Default) - A singleton instance. The object is not created until the first time it is requested.
- Singleton - A singleton instance. The object is created when AutoDI is instantiated.
- Scoped - A unique lazy singleton instances is created in each service scope.
- WeakSingleton - A single instance is created and returned. The container holds a weak reference to the instance and will return the same instance as long as it is alive; otherwise a new instance is created. In version 3.0.0 this was named WeakTransient (#61)
- Transient - A new instance is created for each request.
- None - Used to un-register a type that may have been previously registered.
You can also remove types that were previously mapped by simply setting the Lifetime
attribute to None.
The following removes all types within the Exclude namespace.
<AutoDI>
<type name="Exclude\..*" lifetime="None" />
</AutoDI>
Default: Behaviors.Default
<AutoDI Behavior="SingleInterfaceImplementation,IncludeClasses,IncludeBaseClasses,IncludeDependentAutoDIAssemblies" />
[assembly:AutoDI.Settings(Behavior = Behaviors.SingleInterfaceImplementation | Behaviors.IncludeClasses)]
Having to declare every registration with regex would be incredibly time consuming. To support many of the common scenarios AutoDI has several built in behaviors. Often it is simplest to let the behaviors do most of the mapping, and then fine tune the results with the <map />
or <type />
nodes. You can specify any number of behaviors as a comma separated list.
- None - All behaviors are turned off.
- Default - All behaviors are turned on.
-
SingleInterfaceImplementation - All classes that are the sole implementation of an interface are automatically registered with the interface as the service type. Mappings created by this behavior have a default lifetime of
LazySingleton
.
public interface IService { ... }
public class Service : IService { ... }
All dependencies of IService
will be automatically resolved with a Service
instance.
-
IncludeClasses - All classes are automatically registered with their own class type as the service type. This allows for dependencies to be requested by their concrete type. Abstract classes are ignored. Mappings created by this behavior have a default lifetime of
Transient
. -
IncludeBaseClasses - All classes are automatically registered with their base classes as the service types as long as they are the sole derived classes, and the class is not abstract. Mappings created by this behavior have a default lifetime of
Transient
. - IncludeDependentAutoDIAssemblies - By default only the main assembly is scanned when selecting types to register. Enabling this behavior will also scan any referenced assembly that references AutoDI. This can be useful for automatically picking up all of the assemblies that are also using AutoDI.
Default: True
<AutoDI AutoInit="False" />
[assembly:AutoDI.Settings(AutoInit = false)]
Be default AutoDI will attempt to locate the assemblies entry point method (the main method) and inject a call to its initialize method there. You can disable this behavior by setting AutoInit="False"
.
Disabling this behavior will require you to manually invoke AutoDI.DI.Init(...)
to initialize the AutoDI framework.
For Xamarin.Android projects you will need to manually inject the container since the assemblies do not contain a single entry point.
Default: DebugLogLevel.Default
<AutoDI DebugLogLevel="Verbose" />
[assembly:AutoDI.Settings(DebugLogLevel = DebugLogLevel.Verbose)]
In the Build section of the Output window you can see the registrations that AutoDI is generating along with some basic output. If you are running into issues or simply want to see more details you can adjust the logging. The valid values are None, Default, or Verbose.
This setting does not affect any warnings or errors raised by AutoDI.
Default: False
<AutoDI DebugExceptions="True" />
Introduced in version 3.2.0. Allows for debugging thrown exceptions in the generated <AutoDI>.AddServices
. The exceptions are caught, and wrapped into an AggregateException.
By default AutoDI will invoke the constructor with the most arguments. However, there may be cases where you need to explicitly specify which constructor to use. In these cases you can simply decorate the constructor with the AutoDI.DiConstructorAttribute
.
public class MyClass
{
public MyClass(string name, int id) { ... }
[AutoDI.DiConstructor]
public MyClass(IService service) { ...}
}
AutoDI can also provide property injection for dependencies. For a property to be resolved it must meet the following criteria.
- Decorated with
[AutoDI.DependencyAttribute]
- Must have a setter or be an auto-property
The property values are set inside of the constructor (just like constructor parameters). This allows the properties to have any protection level, from public to private. Properties that only specify a getter method with a body are ignored.
For something things it may be necessary to configure the AutoDI framework at run-time.
To do this simply declare a method and decorate it with the AutoDI.SetupMethodAttribute
.
[AutoDI.SetupMethod]
public static void Initialize(AutoDI.IApplicationBuilder application)
{
//Any needed run-time configuration here
}
The setup method must meet the following criteria:
- Must be static
- Must be public or internal
- Must take in a single
AutoDI.IApplicationBuilder
parameter - Must be in the main module of the assembly being processed by the Fody weaver.
You can see examples of using the run-time configuration in some of the example projects.
You can register additional services using the IApplicationBuilder.ConfigureServices
method.
[AutoDI.SetupMethod]
public static void Initialize(AutoDI.IApplicationBuilder application)
{
application.ConfigureServices(services => services.AddAutoDILazySingleton<IService, Service>());
//you can also use the standard extension methods provided by the Microsoft.Extensions.DependencyInjection.Abstractions assembly, but this will limit you to object lifetimes supported there.
}
AutoDI's container is exposed through the AutoDI.IContainer
interface. Using the IApplicationBuilder.ConfigureContainer<AutoDI.IContainer>
method. You can use this method to make container specific calls.
[AutoDI.SetupMethod]
public static void Initialize(AutoDI.IApplicationBuilder application)
{
application.ConfigureContainer<AutoDI.IContainer>(container => {
//Manipulate the container
});
}
The IContainer
also has an event TypeKeyNotFound
. If a service cannot be resolved this event is raised. You can use this event as a run-time means of logging missing dependencies or dynamic resolution of missing types.
[AutoDI.SetupMethod]
public static void Initialize(AutoDI.IApplicationBuilder application)
{
application.ConfigureContainer<AutoDI.IContainer>(container => {
container.TypeKeyNotFound += (_, e) => {
e.Instance = ResolveInstance(e.ServiceKey);
};
});
}
private static object ResolveInstance(Type serviceKey)
{
//Return appropriate instance
}
If you are using a different dependency injection framework you can make a similar call to interact directly with that framework's container. The following is an example using StructureMap as the backing dependency injection framework.
[AutoDI.SetupMethod]
public static void Initialize(AutoDI.IApplicationBuilder application)
{
//This method provided by the StructureMap.AutoDI project in the Examples.
application.UseStructureMap();
application.ConfigureContinaer<Registry>(registry =>
{
Do any SM specific registration on the registry
});
}