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))
});
}
}
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.
@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';
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.
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With