InjectionMap

InjectionMap is a very small and lightweight IoC/DI container for .NET.
InjectionMap allows loose coupling betweeen interfaces and implementations. InjectionMap uses a fluent syntax to map and configure components to the key types.
  • InjectionMap uses type mapping to reference the key/reference and the implementation.
  • Instances are resolved using reflection or can be provided through a callback whitch allows you to create the instance in the mapping.
  • It suports a fluent syntax to help keep the code simple, small and clean.
  • Constructors can be marked with attributes.
  • Parameters for constructors can be injected or passed when mapping.
  • InjectionMap is very simple and straightforward.

How to use InjectionMap

The best way to configure the mappings is to implement IMapInitializer and initialialize the mappings once per AppDomain. The best place to call the static InjectionMapper.Initialize method is in the application startup. In ASP.NET applications that would be the Global.asax file and in WPF applications in App.xaml.cs the Startup method. Mappings can also be configured through an instance of InjectionMapper.
Mappings can be resolved with an instance of InjectionResolver.


  • Register mappings with IMapInitializer
  • Register mappings with InjectionMapper
  • Register mappings in the Application Config File
  • Mapping with extensions
  • Resolve objects with InjectionResolver
  • Mapping to custom constructor


Install InjectionMap

InjectionMap can be installed from NuGet from the package manager console:
PM > Install-Package InjectionMap

Examples

The source code containes several UnitTests that show how InjectionMap is used.


How to use InjectionMap

IMapInitializer

The best practice is to create all mappings in one place and only once per AppDomain. The best place to do this is the application startup. In an ASP.NET application it would be the Global.asax file and in a WPF application it would be the App.xaml.cs Startup.

Implementation

To achieve this, you have to create a class that implements IMapInitializer. IMapInitializer only provides one Method that has to be implemented:
void InitializeMap(IMappingProvider container)

The IMappingProvider object containes two methods to register mappings:
Map<TSvc>()
Map<TSvc,TImpl>()

And one method to clean existing mappings:
Clean<T>()

Example

This example demonstrates the simples form of mapping. An interface and a class with a default constructor that implements the interface. The mapping doesn't need any special cases.

interface IMapInitializerTest
{
}

class InjectionMappingTestMock : IMapInitializerTest
{
}

class InjectionMapperMock : IMapInitializer
{
    public void InitializeMap(IMappingProvider container)
    {
  // create mapping
        container.Map<IMapInitializerTest, InjectionMappingTestMock>();
    }
}

Initialization

In the application startup you only call InjectionMap.InitializeMap(...) with the Assembly that contains IMapInitializer implementations.

InjectionMap.InitializeMap(Assembly assembly)
All classes that implement IMapInitializer will automaticaly get created and called after InjectionMap.InitializeMap() gets executed.

Resolving values

Resolving values can be done with InjectionResolver.
using (var resolver = new InjectionResolver())
{
    // resolve the mapping
    var map = resolver.Resolve<IMapInitializerTest>();
}


InjectionMapper

The InjectionMapper class can be used to register mappings without a IMapInitializer implementation.

Default mapping

using (var mapper = new InjectionMapper())
{
    // create mapping
    mapper.Map<IMapInitializerTest, InjectionMappingTestMock>();
}

Mapping with generic extensions

Alternatively with IMappingExpression<TSvc>.For<TImpl>();
using (var mapper = new InjectionMapper())
{
    // create mapping
    mapper.Map<IMapInitializerTest>.For<InjectionMappingTestMock>();
}

Mapping with expression extensions

Alternatively with IMappingExpression<TSvc>.For<TImpl>();
using (var mapper = new InjectionMapper())
{
    // create mapping
    mapper.Map<IMapInitializerTest>.For(() => new InjectionMappingTestMock());
}

InjectionResolver

The InjectionResolver class can be used to resolve mappings.
using (var resolver = new InjectionResolver())
{
    // resolve multiple mappings of IMapInitializerTest
    var map1 = resolver.ResolveMultiple<IMapInitializerTest>();
 // resolve single mapping of IMapInitializerTest
    var map1 = resolver.Resolve<IMapInitializerTest>();
}

Resolving the constructor

InjectionMap uses the following Order to resolve the correct constructor.
1. Find the contructor marked with the InjectionConstructorAttribute
2. Try to resolve the constructor that matches the passed arguments
3. Try to resolve the default constructor
4. Try to resolve any constructor using the passed arguments and by resolving mappings

InjectionConstructor

In classes with multiple constructor, the contructor that has to be used can be marked with the InjectionConsturctoAttribute.
The parameters can be passt as arguments or can be resolved from mappings.

public class ConstructorInjectionMock : IConstructorInjectionMock
{
    public ConstructorInjectionMock()
    {
    }

    [InjectionConstructor]
    public ConstructorInjectionMock(IConstructorParameter parameter)
    {
    }
}

Passing Arguments to the mapping

Parameters that have to be used can be passed as Arguments to the mapping.
public class ConstructorInjectionMock : IConstructorInjectionMock
{
    public ConstructorInjectionMock(int parameter)
    {
    }
}

Add the argument
var mapper = new InjectionMapper();
mapper.Map<IConstructorInjectionMock, ConstructorInjectionMock>().WithArgument(() => 5);
Optionaly the argument can be passed to a named parameter
var mapper = new InjectionMapper();
mapper.Map<IConstructorInjectionMock, ConstructorInjectionMock>().WithArgument("parameter", () => 5);

Resolve Arguments from mappings

If parameters are mapped objects, they will automatically be resolved
public class ConstructorParameter : IConstructorParameter
{
}

public class ConstructorInjectionMock : IConstructorInjectionMock
{
    public ConstructorInjectionMock(IConstructorParameter parameter)
    {
    }
}

var mapper = new InjectionMapper();
mapper.Map<IConstructorParameter, ConstructorParameter>();
mapper.Map<IConstructorInjectionMock, ConstructorInjectionMock>();

var resolver = new InjectionResolver();
var obj = resolver.Resolve<IConstructorInjectionMock>();

The parameter IConstructorParameter will automaticaly be resolved and passed to the constructor.

Resolve Arguments to unmapped type

Optionaly the argument can be injected into the constructor without first having to map the type that has to be resolved.
public class ConstructorParameter : IConstructorParameter
{
}

public class ConstructorInjectionMock
{
    public ConstructorInjectionMock(IConstructorParameter parameter)
    {
    }
}

var mapper = new InjectionMapper();
mapper.Map<IConstructorParameter, ConstructorParameter>();

var resolver = new InjectionResolver();
var obj = resolver.Resolve<ConstructorInjectionMock>();

Create a map of IConstructorParameter and pass the type ConstructorInjectionMock to the resolver. ConstructorInjectionMock will be resolved and the IConstructorParameter will be injected into the contructor, even though ConstructorInjectionMock is not mapped.

No comments: