Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have only some constructor parameters injected with Autofac combined with using an InjectionModule

Summary:

How to combine an injection module with regular contain.Resolve() calls in registration?

~ Update (5 hours later and after feedback)~ :

The use of RegisterType<> as opposed to Register() does not solve the actual complexity level I have in production code, I have updated the demo code on BitBucket to include a generic ISecond, with examples of: IMagic and CreateMagic (interface, class respectively).

The HG repo code has been updated, as has the PasteBin link below.

Details:

There is a class with 2 dependencies

public SomeClassWithILogDependency(ILog log, ISecond<T> second)

'ILog' has an InjectionModule defined for it such as, just like in the documentation

( LogforIntegration ) see bottom of post

If the class has only 1 dependency then this line of Autofac registration works in the simplest scenario:

builder.RegisterType<SomeClassWithILogDependency>()
.As<IUseILog>()
.PropertiesAutowired();

BUT

I need to call container.Resolve<ISecond<T>>() in the registration for more parameters on the class, but something like this does not work:

builder.Register(
    c => new SomeClassWithILogDependency(
        c.Resolve<ILog>(), c.Resolve<ISecond<T>>()))
    .As<IUseILog>()
    .PropertiesAutowired(); //with or without this

The c.Resolve<ILog>() is the issue as "that service has not been registered."

I also tried

SomeClassWithILogDependency(c.ResolveOptional<ILog>() //without luck...

Any ideas as to what I have missed, or completely different strategy? I hope the solution is not to have more InjectionModules...

Full code posted on PasteBin.com as a single file

Or entire solution from bitbucket.org

hg clone https://[email protected]/NickJosevski/autofaclog4netdemo

Injection Module Code (to make this post complete):

public class LogInjectionModule : Module
{
    protected override void AttachToComponentRegistration(
        IComponentRegistry registry, IComponentRegistration registration)
    {
        registration.Preparing += OnComponentPreparing;
    }

    private static void OnComponentPreparing(object sender, PreparingEventArgs e)
    {
        var t = e.Component.Activator.LimitType;

        e.Parameters = e.Parameters.Union(new[]
            {
                new ResolvedParameter(
                (p, i) => p.ParameterType == typeof (ILog),
                (p, i) => LogManager.GetLogger(t))
            });
    }
}
like image 936
Nick Josevski Avatar asked May 31 '11 06:05

Nick Josevski


People also ask

What does @inject do with constructor?

Injectable constructors are annotated with @Inject and accept zero or more dependencies as arguments. @Inject can apply to at most one constructor per class. @Inject is optional for public, no-argument constructors when no other constructors are present. This enables injectors to invoke default constructors.

What is@ inject in Angular?

@Inject() is a manual mechanism for letting Angular know that a parameter must be injected. It can be used like so: import { Component, Inject } from '@angular/core'; import { ChatWidget } from '../components/chat-widget'; ​

Which choice is benefit for using dependency injection?

Advantages. A basic benefit of dependency injection is decreased coupling between classes and their dependencies. By removing a client's knowledge of how its dependencies are implemented, programs become more reusable, testable and maintainable.


1 Answers

Thanks to bentayloruk's suggestion, the solution was in fact using:

WithParameter(/* ... */)

So the registration code now looks like this:

builder.RegisterType<SomeClassWithILogDependency<IMagic>>()
.As<IUseILog>()
.WithParameter(
    (pi, c) => pi.ParameterType == (typeof(ISecond<>)),
    (pi, c) => c.ResolveNamed<ISecond<IMagic>>("second")
    );

The sample application has been updated, but not the pastebin entry.

More Info:

This being a simplified example of my production code, was resolved slightly more easily than my real code, the solution there involved one more specific step of using the concrete type for the ParameterType check, example in this 'domain'

pi.ParameterType == (typeof(CreateMagic))

The reason being for this is my production SomeClassWithILogDependency did not have its generic parameter wrapped with an interface, but I chose to make the sample application showing the issue operate slightly different but yielding the same issue.

//demo:
class SomeClassWithILogDependency<TTypeOfISecond> : IUseILog
{
    public SomeClassWithILogDependency(ILog log, ISecond<TTypeOfISecond> second)
}
//-------------- vs --------------
//production:
public class RealClass<TOne, TTwo>, IRealClass<TOne, TTwo>
{
    public RealClass(ILog log, TOne t1, TTwo t2)
}
like image 142
Nick Josevski Avatar answered Nov 06 '22 13:11

Nick Josevski