Autofac - resolving less specific covariant implementations - c#

I am using Autofac. Let's say I have an covariant interface
interface IOptionFactory<out T> where T : IOption
and specific implementations
class Option1Factory : IOptionFactory<Option1>
class Option2Factory : IOptionFactory<Option2>
I register them as
container.RegisterType<Option1Factory>.As<IOptionFactory<Option1>>();
container.RegisterType<Option2Factory>.As<IOptionFactory<Option2>>();
Is there a way, how to resolve all implementations of IOptionFactory? Because this is covariant, this should be legal in C# (am I right?). Something like:
var factories = container.Resolve<IEnumerable<IOptionFactory<IOption>>>();

The best solution is to wrap your code in a Reporting class with a private IEnumerable property of IOptionFactory<IOption>.
private class Reporting
{
private IEnumerable<IOptionFactory<IOption>> _allOptionsFactories;
public Reporting(IEnumerable<IOptionFactory<IOption>> allOptionsFactories)
{
if (allOptionsFactories == null)
{
throw new ArgumentNullException("Parameter:" + nameof(allOptionsFactories));
}
this._allOptionsFactories = allOptionsFactories;
}
public void Report()
{
foreach (var optionsFactories in _allOptionsFactories)
{
Console.WriteLine(optionsFactories.GetType());
}
}
}
And then you can register and use them with:
[TestMethod]
public void PassingParametersToRegister_NamedParameter()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<IOption1Factory1<SomeOption>>().As<IOptionFactory<IOption>>();
builder.RegisterType<IOption1Factory2<SomeOption>>().As<IOptionFactory<IOption>>();
builder.RegisterType<Reporting>();
using (var container = builder.Build())
{
container.Resolve<Reporting>().Report();
}
//OUTPUT:
//Enumerations + IOption1Factory1`1[Enumerations + SomeOption]
//Enumerations + IOption1Factory2`1[Enumerations + SomeOption]
}
Here is the entire code in my github

Related

How to resolve an interface and use it in the class using Autofac

I'm trying to resolve an interface that I registered in Autofac but it seems to be not working. There is
nullreferenceexception.
Class where I register the inferface :
public void RegisterAutofac(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
(...)
builder.RegisterType<ApiFileTester>().As<IApiFlTester>().InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
Then I want to use it in a class :
public class ApiFileSendingController : ApiClientBase
{
private readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester) : base(dto)
{
_tester = tester;
}
public void Send(List<AftInvFileDTO> filesToSendRetry = null)
{
_apiFileTester.RegisterTestingMethods();
}
}
Then in some other class:
DTO dto = new DTO(); //some configuration here
ApiFileSendingController sender = new ApiFileSendingController(dto, null);
sender.Send();
There is a problem here because my interface is null. I've tried to pass it like this:
ApiFileSendingController sender = new ApiFileSendingController(dto,
null);
but it's null and it's completely reasonable (I am passing the null).
IS it possible to configure optional parameter or something? I'd like to have this interface resolved automatically by autofac, not manually.
I don't seem to have a problem resolving your class. Technically it's impossible to really answer your question since the code won't even compile and it appears you have a ton of missing autofac registrations.
Working Example.
// #nuget: Autofac
using System;
using Autofac;
public class Program
{
private static IContainer _container;
public static void Main()
{
RegisterAutofac();
using (var httpRequestScope = _container.BeginLifetimeScope("AutofacWebRequest"))
{
var apiController = httpRequestScope.Resolve<ApiFileSendingController>();
Console.WriteLine(apiController._apiFileTester);
}
}
public static void RegisterAutofac()
{
var builder = new ContainerBuilder();
//builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<ApiFileTester>().As<IApiFlTester>().InstancePerLifetimeScope();
builder.RegisterType<ApiFileSendingController>().AsSelf();
builder.RegisterType<DTO>().AsSelf();
_container = builder.Build();
}
public class ApiFileSendingController : ApiClientBase
{
public readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester): base (dto)
{
_apiFileTester = tester;
}
}
public interface IApiFlTester { }
public class ApiFileTester : IApiFlTester { }
public class ApiClientBase
{
public ApiClientBase(DTO dto)
{
}
}
public class DTO { }
}
You have misconception at Autofac DI, most of the DI frameworks are good at creating instances for you, via constructor injection and property injection you will get the instance with their dependencies automatically wired up.
Your constructor contains DTO instance which you will provide during runtime, Autofac will not resolve that since you had not declare it to the DI container during ConfigureServices cycle.
You might need to giving up using Autofac in this case to get the freedom of creating controller instance at your own code, you will need to get the concrete class instance from Reflection instead. The abstraction / implementation isolation is still there via this approach.
public class ApiFileSendingController : ApiClientBase
{
private readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester) : base(dto)
{
if (tester is null)
_tester = GetApiTesterViaReflection();
else
_tester = tester;
}
public ApiFileSendingController(DTO dto) : base(dto)
{
_apiFileTester = GetApiTesterViaReflection();
}
public void Send(List<AftInvFileDTO> filesToSendRetry = null)
{
_apiFileTester.RegisterTestingMethods();
}
private IApiFlTester GetApiTesterViaReflection()
{
Type type = typeof(IApiFlTester).Assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IApiFlTester))).FirstOrDefault();
return Activator.CreateInstance(type) as IApiFlTester;
}
}

Supply typed parameter to nested dependencies in Autofac

I was under the impression that the TypedParameter could be used to supply values during resolution in Autofac.
However, it seems that these parameters are used on the explicit type being resolved only, and does not propagate down the dependency chain.
Is there a way to accomplish this?
public interface IDepA { }
public interface IDepB { }
public interface IDepC { }
public class DepA : IDepA
{
public DepA(IDepB depB) { }
}
public class DepB : IDepB
{
public DepB(IDepC depC) { }
}
public class DepC : IDepC { }
[TestMethod]
public void AutofacResolutionTest()
{
var builder = new ContainerBuilder();
builder.RegisterType<DepA>().As<IDepA>();
builder.RegisterType<DepB>().As<IDepB>();
var container = builder.Build();
// Works
var b = container.Resolve<IDepB>(new TypedParameter(typeof(IDepC), new DepC()));
// Does not work
var a = container.Resolve<IDepA>(new TypedParameter(typeof(IDepC), new DepC()));
}
Short answer: You can't pass a parameter to something in the middle of a resolve chain.
This is an FAQ in the Autofac docs.

How to make Unity call a method after creating an object instance but before it is injected anywhere

I'm using Unity for dependency injection. I'd like to achieve something like this:
public interface MyInterface { void MyMethod(); }
When building Unity container:
myContainer.RegisterType<MyInterface, MyConcreteType>();
myContainer.AddPostConstructor(x => (x as MyInterface)?.MyMethod());
Is it possible? Is there a better/more elegant way?
Another way - register implementations via special factory and use it:
class Factory
{
IUnityContainer _container;
public Factory(IUnityContainer container)
{
_container = container;
}
public void Register<TType>() where TType : MyInterface
{
myContainer.RegisterType<MyInterface, TType>(new InjectionFactory(c =>
{
var result = c.Resolve<TType>();
result.MyMethod();
return result;
}));
}
public MyInterface Get()
{
_container.Resolve<MyInterface>();
}
}
...
public TestClass
{
Factory _factory;
public TestClass(Factory factory)
{
_factory = factory;
_factory.Register<MyConcreteType>();
}
public void TestMethod()
{
var service = _factory.Get();
}
}
So, all future implementations must be registered in the factory. But still there is no guarantee that method MyMethod will be implemented correct or implemented at all.
Maybe somethig like this:
myContainer.RegisterType<MyInterface, MyConcreteType>(new InjectionFactory(c =>
{
var result = c.Resolve<MyConcreteType>();
result.MyMethod();
return result;
}));

Castle Windsor Interceptor

I'm trying to use the code from this page, http://docs.castleproject.org/Windsor.Introduction-to-AOP-With-Castle.ashx and register an interceptor in a fluent manner.
But I get this error thrown. I've tried Castle Windsor versions from 2.5 to 3.3. So it must be something very basic in how interceptors are set up
Classes
public interface ISomething
{
Int32 Augment(Int32 input);
void DoSomething(String input);
Int32 Property { get; set; }
}
class Something : ISomething
{
public int Augment(int input) {
return input + 1;
}
public void DoSomething(string input) {
Console.WriteLine("I'm doing something: " + input);
}
public int Property { get; set; }
}
public class DumpInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation) {
Console.WriteLine("DumpInterceptorCalled on method " +
invocation.Method.Name);
invocation.Proceed();
if (invocation.Method.ReturnType == typeof(Int32)) {
invocation.ReturnValue = (Int32)invocation.ReturnValue + 1;
}
Console.WriteLine("DumpInterceptor returnvalue is " +
(invocation.ReturnValue ?? "NULL"));
}
}
Setup
Console.WriteLine("Run 2 - configuration fluent");
using (WindsorContainer container = new WindsorContainer())
{
container.Register(
Component.For<IInterceptor>()
.ImplementedBy<DumpInterceptor>()
.Named("myinterceptor"));
container.Register(
Component.For<ISomething>()
.ImplementedBy<Something>()
.Interceptors(InterceptorReference.ForKey("myinterceptor")).Anywhere);
ISomething something = container.Resolve<ISomething>(); //Offending row
something.DoSomething("");
Console.WriteLine("Augment 10 returns " + something.Augment(10));
}
Error
Type 'Castle.Proxies.ISomethingProxy' from
assembly'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null' is attempting to implement an inaccessible
interface.
The answer
So I found why this was happening. Appearantly if you create inner classes and interfaces you can register and resolve them but attaching interceptors to them won't work
Example - where the error will be triggered
class Program
{
public static void Main(String [] args)
{
var container = new WindsorContainer();
container.Register(Component.For<TestInterceptor>().Named("test"));
container.Register(Component.For<InnerInterface>().ImplementedBy<InnerClass>().Interceptors(InterceptorReference.ForKey("test")).Anywhere);
// this row below will throw the exception
var innerClassInstance = container.Resolve<InnerInterface>();
}
class InnerClass : InnerInterface { }
interface InnerInterface { }
class TestInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
throw new NotImplementedException();
}
}
}
Conclusion
So to conclude my intention was not to create inner classes in the first place but rather put together a demo to showcase Castle Windsor. But maybe this can help someone if they run into the same error as me..

Registering open generic singleton using Simple Injector

I have the below code, and would like to register a singleton for each different variant of the generic. Is this possible? Currently, the assertion fails, as the are not the same object type.
public interface IGenericClass<T>
{
string GetToString();
}
public class GenericClass<T> : IGenericClass<T>
{
public string GetToString()
{
return typeof (T).FullName;
}
}
[Test]
public void test()
{
var container = new Container();
container.RegisterOpenGeneric(
typeof(IGenericClass<>),
typeof(GenericClass<>));
var instance1 = container.GetInstance<IGenericClass<double>>();
var instance2 = container.GetInstance<IGenericClass<double>>();
//this should assert true
Assert.IsTrue(object.ReferenceEquals(instance1, instance2));
}
Just use RegisterSingleOpenGeneric:
_container.RegisterSingleOpenGeneric(
typeof(IGenericClass<>),
typeof(GenericClass<>));

Categories

Resources