Prevent Autofac from aggressively injecting properties? - c#

I have a simple class:
public class MyWidget
{
private string _something;
public MyWidget(string name)
{
}
public string Something
{
get { return _something; }
set { _something = value; }
}
}
that I register with Autofac:
var builder = new ContainerBuilder();
builder.RegisterType<MyWidget>();
var container = builder.Build();
If I resolve a factory and create an instance of MyWidget:
var myWidgetFactory = Container.Resolve<Func<string, MyWidget>>();
var myWidget = myWidgetFactory("test");
The property 'Something' is assigned the value "test", even though it has nothing to do with the constructor parameter. Why does Autofac think it should set the first property it comes to? How do I prevent this? I'm using Autofac v4.0.0.

Related

autofac AutoActivate instance how to control order?

public class TestOrderIndex1
{
public TestOrderIndex1()
{
Console.WriteLine("TestOrderIndex1");
}
}
public class TestOrderIndex2
{
public TestOrderIndex2()
{
Console.WriteLine("TestOrderIndex2");
}
}
public class TestOrderIndex3
{
public TestOrderIndex3()
{
Console.WriteLine("TestOrderIndex3");
}
}
var builder = new ContainerBuilder();
builder.RegisterType<TestOrderIndex1>().SingleInstance().AutoActivate();
builder.RegisterType<TestOrderIndex2>().SingleInstance().AutoActivate();
builder.RegisterType<TestOrderIndex3>().SingleInstance().AutoActivate();
var container = builder.Build();
// the order of instance autoactivate
// It looks like it is registered first and instantiated last
TestOrderIndex3
TestOrderIndex2
TestOrderIndex1
how to change the order to registered first and instantiated first ?

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 update registered instances in Autofac container in runtime

I want to replace existing registered instances in Autofac with new ones in ASP.NET MVC application in runtime. Registrations are keyed as I work with collections of instances of different subtype, though it seems to be irrelevant to my issue.
Initial registration on application startup
foreach (var instance in instances)
{
builder.RegisterInstance(instance).Keyed<IInstance>(InstanceType.A);
}
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
Further on, in a controller method I do the following: dispose old instances, obtain new ones, create a new builder, reregister existing components and also register new instances, then update Autofac's ComponentContext
//...dispose old instances, obtain new instances
var builder = new ContainerBuilder();
foreach (var c in _componentContext.ComponentRegistry.Registrations)
{
builder.RegisterComponent(c);
}
foreach (var instance in newInstances)
{
builder.RegisterInstance(instance).Keyed<IInstance>(InstanceType.A);
}
builder.Update(_componentContext.ComponentRegistry);
Next time I enter the controller method, in controller constructor the old instances are resolved as IIndex<InstanceType, IInstance[]>, not the new ones. What am I doing wrong?
Your code doesn't work because componentContext is the context for the current scope and not the global scope. You can look at this .NetFiddle to show some code illustrating the problem : https://dotnetfiddle.net/GNvOL4
If you really want to replace instance it will be simpler to use a provider :
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterInstance(new FooProvider(new Foo("a")))
.As<FooProvider>();
builder.Register(c => c.Resolve<FooProvider>().Value)
.ExternallyOwned()
.Keyed<Foo>(1);
IContainer container = builder.Build();
using (ILifetimeScope scope = container.BeginLifetimeScope())
{
Do(scope);
}
using (ILifetimeScope scope = container.BeginLifetimeScope())
{
IComponentContext context = scope.Resolve<IComponentContext>();
container.Resolve<FooProvider>().Value = new Foo("b");
Do(scope);
}
using (ILifetimeScope scope = container.BeginLifetimeScope())
{
Do(scope);
}
}
static void Do(ILifetimeScope scope)
{
IIndex<Int32, Foo> index = scope.Resolve<IIndex<Int32, Foo>>();
Foo foo = index[1];
Console.WriteLine(foo.Value);
}
}
public class FooProvider
{
public FooProvider(Foo value)
{
this._value = value;
}
private volatile Foo _value;
public Foo Value
{
get
{
return this._value;
}
}
public void ChangeValue(Foo value)
{
if(value == null)
{
throw new ArgumentNullException("value");
}
if(value == this._value)
{
return;
}
Foo oldValue = this._value;
this._value = value;
oldValue.Dispose();
}
public void Dispose()
{
this._value.Dispose();
}
}
public class Foo : IDisposable
{
public Foo(String value)
{
this._value = value;
}
private readonly String _value;
public String Value
{
get
{
return this._value;
}
}
public void Dispose()
{
// do things
}
}

How can I register class as singleton depending on optional argument in Autofac?

Let me explain my question using code, so I have a class:
public class ComplexEntity
{
private readonly ISomeDependency _someDependency;
private readonly int _optionalArg;
public ComplexEntity(ISomeDependency someDependency, int optionalArg)
{
_someDependency = someDependency;
_optionalArg = optionalArg;
}
}
and module:
public class FooModule : Module
{
protected override void OnMap(ContainerBuilder builder)
{
builder.RegisterType<ConcreteDependency>().As<ISomeDependency>().SingleInstance();
builder.RegisterType<ComplexEntity>().AsSelf();//SingleInstance fails my test below.
}
}
so my question is - how can I resolve ComplexEntity using optional argument (of type int - actually it doesn't matter what type is) and according to that optional argument it will return me same entity (if was already requested with) or create a new one - just take a look at the following test:
int optionalArgument = 10;
int anotherOptionalArgument = 11;
//I expect ResolveOptional returns same references for the same optional argument,
//thus instance1 should be equals instance2, but not equals instance3
var instance1 = _container.ResolveOptional<ComplexEntity>(
new TypedParameter(optionalArgument.GetType(), optionalArgument));
var instance2 = _container.ResolveOptional<ComplexEntity>(
new TypedParameter(optionalArgument.GetType(), optionalArgument));
var instance3 = _container.ResolveOptional<ComplexEntity>(
new TypedParameter(anotherOptionalArgument.GetType(), anotherOptionalArgument));
bool ref12Equals = object.ReferenceEquals(instance1, instance2); //should be true
bool ref13Equals = object.ReferenceEquals(instance1, instance3); //should be false
bool ref23Equals = object.ReferenceEquals(instance2, instance3); //should be false
In autofac scope can either be singleton or factory (transient), not both. If you need more complex lifetime management, I belive you need to take responsibility for that and manage that yourself. If I understood you properly, you need a scope manager that either produces new instance or returns singleton. If you still want to use DI, you can put it in container, like this:
private const int FactoryMode = 11;
private const int SingletonMode = 10;
public static void Main()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<ComplexTypeScope>().SingleInstance();
containerBuilder.Register((c, p) => c.Resolve<ComplexTypeScope>().Get(p.TypedAs<int>()));
var container = containerBuilder.Build();
ComplexType instance1 = container.Resolve<ComplexType>(new TypedParameter(typeof(int), SingletonMode));
ComplexType instance2 = container.Resolve<ComplexType>(new TypedParameter(typeof(int), SingletonMode));
ComplexType instance3 = container.Resolve<ComplexType>(new TypedParameter(typeof(int), FactoryMode));
Debug.Assert(ReferenceEquals(instance1, instance2));
Debug.Assert(!ReferenceEquals(instance1, instance3));
}
class ComplexType
{
}
class ComplexTypeScope
{
private readonly Lazy<ComplexType> complexTypeSingleTon;
public ComplexTypeScope()
{
complexTypeSingleTon = new Lazy<ComplexType>(() => new ComplexType());
}
public ComplexType Get(int parameter)
{
return parameter == FactoryMode ? new ComplexType() : complexTypeSingleTon.Value;
}
}
of course with such an approach container does not manage lifetime of the components, like automatic disposal.

Categories

Resources