I have a FaxService class that takes two constructor parameters.
public FaxService(string phone, IFaxProvider faxProvider)
How is Unity configured to send a string for the first parameter and an IFaxProvider instance for the second? I realize I can inject another service that provides the string, but I am looking for a solution where I don't have to change the FaxService constructor parameters.
This is what I have so far...
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
var phone = "214-123-4567";
container.RegisterType<IFaxProvider, EFaxProvider>();
container.RegisterType<IFaxService, FaxService>(phone);
var fax = container.Resolve<IFaxService>();
}
}
public interface IFaxService { }
public interface IFaxProvider { }
public class FaxService : IFaxService
{
public FaxService(string phone, IFaxProvider faxProvider) { }
}
public class EFaxProvider : IFaxProvider { }
but it throws...
Unity.Exceptions.ResolutionFailedException HResult=0x80131500
Message=Resolution of the dependency failed, type =
'ConsoleApp3.IFaxService', name = '(none)'. Exception occurred while:
while resolving.
var container = new UnityContainer();
var phone = "214-123-4567";
container.RegisterType<IFaxProvider, EFaxProvider>();
container.RegisterType<IFaxService, FaxService>(new InjectionConstructor(phone, typeof(IFaxProvider)));
var fax = container.Resolve<IFaxService>();
I am looking for a solution where I don't have to change the FaxService constructor parameters.
There is nothing built into Unity to do this without specifying at least the types of all constructor parameters.
var container = new UnityContainer();
var phone = "214-123-4567";
container.RegisterType<IFaxService, FaxService>(new InjectionConstructor(phone, typeof(IFaxProvider)));
container.RegisterType<IFaxProvider, EFaxProvider>();
var fax = container.Resolve<IFaxService>();
The list of parameters would need to change every time the constructor changes.
Workaround
If you don't want to change your DI registration if the constructor changes for FaxService, build an abstract factory to separate the string/primitive parameters from the services. Pass services through the constructor parameters of the factory. Pass string and primitive parameter types through the Build method parameters.
public class FaxServiceFactory
{
private readonly IFaxProvider faxProvider;
public FaxServiceFactory(IFaxProvider faxProvider)
{
this.faxProvider = faxProvider ?? throw new ArgumentNullException(nameof(faxProvider));
}
public IFaxService Create(string phone)
{
return new FaxService(phone, this.faxProvider);
}
}
And then register like:
var container = new UnityContainer();
var phone = "214-123-4567";
container.RegisterType<FaxServiceFactory>();
container.RegisterType<IFaxProvider, EFaxProvider>();
container.RegisterInstance<IFaxService>(container.Resolve<FaxServiceFactory>().Create(phone));
var fax = container.Resolve<IFaxService>();
Another possibility is to use a DI container that allows you to specify partial lists of constructor parameters (Autofac, Ninject, StructureMap, and Castle Windsor all do this out of the box).
Related
Please forgive me if I make any mistakes in asking this question as it is the first question I have asked on this site.
I am currently trying to add Autofac to an already existing project. I have been using Autofac for about 6 hours and C# for about 4 weeks, I am originally a Python developer so please forgive any C# ignorance. I currently have the following test method:`
public static void BasicTest()
{
using (var scope= Program.container.BeginLifetimeScope())
{
ITradeManager tm = scope.Resolve<ITradeManager>();
List<IGameData> gamesList = new List<IGameData>();
List<IUserData> usersList = new List<IUserData>();
IScraperManager sc = scope.Resolve<IScraperManager>(new NamedParameter("sc",(scope.Resolve<UniScraper>(new NamedParameter("games", gamesList), new NamedParameter("users", usersList)))));
IDatabaseIC db = scope.Resolve<IDatabaseIC>();
IAppCore app = scope.Resolve<IAppCore>(
new NamedParameter("tm", tm),
new NamedParameter("sc", sc),
new NamedParameter("db", db));
IUserData tradeUser = scope.Resolve<IUserData>();
app.Initialise(tradeUser, uniUser);
app.Run();
}
And have the following container setup:
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<AppCore>().As<IAppCore>();
builder.RegisterType<DatabaseInteractionControler>().As<IDatabaseIC>();
builder.RegisterType<ScraperManager>().As<IScraperManager>();
builder.RegisterType<TradeManager>().As<ITradeManager>();
builder.RegisterType<GameData>().As<IGameData>();
builder.RegisterType<UserData>().As<IUserData>();
builder.RegisterType<Scrapers.Scrapers.Uni.UniScraper>().AsSelf().As<IBaseScraper>();
builder.RegisterType<Scrapers.Scrapers.Hill.HillScraper>().AsSelf().As<IBaseScraper>();
builder.RegisterType<Scrapers.Marathon.MarathonScraper>().AsSelf().As<IBaseScraper>();
container = builder.Build();
Tests.AppTest.BasicTest();
}
My issue is that when I try to pass already resolved objects as parameters to Autofac for resolving IAppcore, it ignores the already resolved objects I'm passing as arguments, and instead of tries to resolve as if I did not pass any parameters to it at all!
Have I miss understood something or is there an obvious solution that I am too new to C# and Autofac to easily see?
If you are interested the project I originally wrote (and now converting to use Autofac) was a simple set of web scrapers that pulled in sports news from various different sites and collected them together in a handy little desktop app.
Based on this test, one guess is that the names of your named parameters ("tm", "sc", "db") don't match the actual names of those parameters in the classes' constructors. If they don't match, Autofac doesn't throw an exception. It just resolves an instance of the registered type and ignores your NamedParameter.
To clarify, if your constructor looks like this:
public SomeConstructor(SomeRequiredDependency xyz)
Then the name specified in the NamedParameter must be "xyz".
public class RequiresDependency
{
public RequiresDependency(Dependency dependency)
{
Dependency = dependency;
}
public Dependency Dependency { get; }
}
public class Dependency
{}
[TestClass]
public class AutofacTest
{
[TestMethod]
public void ResolvesWithSpecifiedParameters()
{
var builder = new ContainerBuilder();
builder.RegisterType<RequiresDependency>();
builder.RegisterType<Dependency>();
var myDependency = new Dependency();
using (var container = builder.Build())
{
var resolved =
container.Resolve<RequiresDependency>(new NamedParameter("dependency", myDependency));
Assert.AreSame(myDependency, resolved.Dependency);
}
}
[TestMethod]
public void ResolvesWithRegisteredTypeIfParameterNameDoesntMatch()
{
var builder = new ContainerBuilder();
builder.RegisterType<RequiresDependency>();
builder.RegisterType<Dependency>();
var myDependency = new Dependency();
using (var container = builder.Build())
{
var resolved =
container.Resolve<RequiresDependency>(new NamedParameter("x", myDependency));
Assert.AreNotSame(myDependency, resolved.Dependency);
}
}
}
I'm using Autofac with ASP.NET Core.
My dependency is a Reporter:
public class Reporter {
public Reporter (bool doLogging) { DoLogging = doLogging ; }
public string DoLogging { get; set; }
// other stuff
}
I need to use it like this:
public class Foo
{
public Foo(Func<bool, Reporter> reporterFactory) { _reporterFactory = reporterFactory; }
private readonly Func<bool, Reporter> _reporterFactory;
}
And I want it to resolve like this:
_reporterFactory(false) ---> equivalent to ---> new Reporter(false)
_reporterFactory(true) ---> equivalent to ---> new Reporter(true)
I want the same instance per request (i.e. Autofac's InstancePerLifetimeScope), for the same bool parameter. When I call _reporterFactory(false) multiple times, I want the same instance. And when I call _reporterFactory(true) multiple times, I want the same instance. But those two instances must be different to each other.
So I register it like this:
builder
.Register<Reporter>((c, p) => p.TypedAs<bool>() ? new Reporter(true): new Person(false))
.As<Reporter>()
.InstancePerLifetimeScope(); // gives "per HTTP request", which is what I need
However, when I resolve I get the same instances regardless of the bool argument:
var reporter = _reporterFactory(false);
var reporterWithLogging = _reporterFactory(true);
Assert.That(reporter, Is.Not.SameAs(reporterWithLogging)); // FAIL!
The documentation for "Parameterized Instantiation" says
resolve the object more than once, you will get the same object instance every time regardless of the different parameters you pass in. Just passing different parameters will not break the respect for the lifetime scope.
Which explains the behavior. So how do I register it correctly?
As mentioned in comments, you could use keyed services to achieve your goal:
builder.Register(c => new Reporter(true)).Keyed<IReporter>(true).InstancePerLifetimeScope();
builder.Register(c => new Reporter(false)).Keyed<IReporter>(false).InstancePerLifetimeScope();
The thing is, if you want to inject it to another class, you would have to inject it with IIndex<bool, IReporter>:
public class Foo
{
public Foo(IIndex<bool, IReporter> reporters)
{
var withLogging = reporters[true];
var withoutLogging = reporters[false];
}
}
IIndex is Autofac's interface, which makes your component tight coupled with the container, and this may not be desirable. To avoid this, you could additionally register the factory, like this:
builder.Register<Func<bool, IReporter>>((c,p) => withLogging => c.ResolveKeyed<IReporter>(withLogging)).InstancePerLifetimeScope();
public class Foo
{
public Foo(Func<bool, IReporter> reporters)
{
var withLogging = reporters(true);
var withoutLogging = reporters(false);
}
}
Now you have the working solution without coupling to the container itself.
Consider the interface IWorkflow, is a contract in our SDK that we define. A tenant may provide their own custom implementation of IWorkflow. So at runtime, we need dynamically load based on the tenant context:
var container = new UnityContainer();
container.RegisterTenantCustomizations();
var workflow0 = container.ResolveForTenant<IWorkflow>("tenant0");
var workflow1 = container.ResolveForTenant<IWorkflow>("tenant1");
var workflow2 = container.ResolveForTenant<IWorkflow>("tenant2");
^^^^^^^^^^^^^^^^
What would this extension method have to look like?
Does Unity IOC provide an attribute that we can use to decorate the class as to their respective tenant?
Let's say you define the definitions in the composition root as this
container.RegisterType<IWorkflow, TenantClassDefault>();
container.RegisterType<IWorkflow, TenantClass0>("tenant0");
container.RegisterType<IWorkflow, TenantClass1>("tenant1");
container.RegisterType<IWorkflow, TenantClass2>("tenant2");
Then you can extend the IUnityContainer interface and create your resolver like this
public static class IUnityContainerExt
{
public static IWorkflow ResolveForTenant(this IUnityContainer container, string name)
{
IWorkflow workflow;
try
{
workflow = container.Resolve<IWorkflow>(name);
}
catch (ResolutionFailedException e)
{
//If the resolver can't resolve the name it will throw ResolutionFailedException and you can select the default instead
workflow = container.Resolve<IWorkflow>();
}
return workflow;
}
}
Then you can use it directly on the container
var workflow0 = container.ResolveForTenant("tenant1");
You can read more about it here
Hi am working on console application which uses Dependency Injection pattern, i have created the interface like
public interface IRecurringTransactionPlanDataService : IService<RecurringTransactionPlan>
{
IQueryable<RecurringTransactionPlan> RecurringTransactionPlanData();
}
and the class implements as
public class RecurringTransactionPlanDataService : Service<RecurringTransactionPlan>, IRecurringTransactionPlanDataService
{
private readonly IRepositoryAsync<RecurringTransactionPlan> _repository;
public RecurringTransactionPlanDataService(IRepositoryAsync<RecurringTransactionPlan> repository)
: base(repository)
{
_repository = repository;
}
public IQueryable<RecurringTransactionPlan> RecurringTransactionPlanData()
{
return _repository.RecurringTransactionPlanData();
}
}
The repository:
public static class RecurringTransactionPlanRepository
{
public static IQueryable<RecurringTransactionPlan> RecurringTransactionPlanData(this IRepository<RecurringTransactionPlan> repository)
{
return repository.Queryable();
}
}
the above code all in separate projects, i am using this in MVC and also in console application, while using in MVC there is no error fetching data from db by UnityConfig.cs, but in console application we need to manually register and resolve the interfaces, i have tried this,
My Console Application:
public class RecurringTransaction
{
public readonly IRecurringTransactionPlanDataService _recurringTransactionPlanDataService;
public RecurringTransaction()
{
var container = new UnityContainer();
container.RegisterType<IRecurringTransactionPlanDataService, RecurringTransactionPlanDataService>();
_recurringTransactionPlanDataService = container.Resolve<IRecurringTransactionPlanDataService>();
}
}
public class Program
{
public static void Main(string[] args)
{
FeePaymentTracker.UnityConfig.RegisterComponents();
RecurringTransaction rt = new RecurringTransaction();
var restult = rt.GetRecurringTransactionRecords();
}
}
am getting the above error. expecting your ideas to resolve the error.
In your RecurringTransaction-method you create a new container and then you register RecurringTransactionPlanDataService in that new container. But you do not register the dependencies that the implementation RecurringTransactionPlanDataService has. That container will only have one registration.
var container = new UnityContainer();
container.RegisterType<IRecurringTransactionPlanDataService, RecurringTransactionPlanDataService>();
_recurringTransactionPlanDataService = container.Resolve<IRecurringTransactionPlanDataService>();
Since RecurringTransactionPlanDataService has a dependency to IRepositoryAsync<RecurringTransactionPlan> you need to register that as well.
Change your code to:
var container = new UnityContainer();
container.RegisterType<IRecurringTransactionPlanDataService, RecurringTransactionPlanDataService>();
container.RegisterType<IRepositoryAsync<RecurringTransactionPlan>, YourRepositoryImplementation>();
_recurringTransactionPlanDataService = container.Resolve<IRecurringTransactionPlanDataService>();
As a sidenote you may want to re-use the same container. In console-applications I usually resolve a "ProgramStarter", which then gets the correct injections. This way you only need to use the service locator anti-pattern in the root. But can use proper DI in the rest of the application.
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<ProgramStarter, ProgramStarter>();
// Pass the same container to the config.
FeePaymentTracker.UnityConfig.RegisterComponents(container);
var program = container.Resolve<ProgramStarter>();
program.Run();
}
}
public class ProgramStarter
{
IRecurringTransactionPlanDataService _dataService;
public ProgramStarter(IRecurringTransactionPlanDataService dataService)
{
_dataService = dataService;
}
public void Run()
{
// Do stuff.
}
}
in the code that you have posted you have an interface called IPaymentService and its implementation. It seems ok. But then in the screenshot you are trying to resolve a dependency called RecurringTransactionPlanDataService. Make your that you have registered this dependency. Could you add information about how you are registering the dependencies in the container?
The problem in your code is that you are trying to resolve the implementation instead of the interface. You should change the following line:
_recurringTransactionPlanDataService = container.Resolve<RecurringTransactionPlanDataService>();
with that:
_recurringTransactionPlanDataService = container.Resolve<IRecurringTransactionPlanDataService>();
Cheers,
Can anyone help?
I have a wpf app (shouldn't matter) and in the Onstart i have my bootstrap stuff.. Its like this..
// Create unity container my service and repository
container = new UnityContainer()
.RegisterType<ISecurityRepository, SecurityRepository>()
.RegisterType<ISecurityService, SecurityService>();
Basically ISecurityService expects me to pass in a ISecurityRepository, hence the above fails.
But i am little confused, do i have to create a new IsecurityRespository and then pass it in, this defeats the object doesn't it?
Is there anyway i say "pass into SecurityService the ISecurityRepository from the container", but it hasn't been built yet?
Any ideas?
You don't have to create instances first. It all just works. That's the magic of IoC Containers.
Example:
public interface ISecurityService { }
public interface ISecurityRepository { }
public class SecurityService : ISecurityService
{
public SecurityService(ISecurityRepository repository)
{
Console.WriteLine("SecurityService created");
Console.WriteLine("Repository is " + repository);
}
public override string ToString()
{
return "A SecurityService";
}
}
public class SecurityRepository : ISecurityRepository
{
public SecurityRepository()
{
Console.WriteLine("SecurityRepository created");
}
public override string ToString()
{
return "A SecurityRepository";
}
}
public class MyClassThatNeedsSecurity
{
public MyClassThatNeedsSecurity(ISecurityService security)
{
Console.WriteLine("My class has security: " + security);
}
}
class Program
{
static void Main()
{
using (IUnityContainer container = new UnityContainer())
{
container.RegisterType<ISecurityRepository, SecurityRepository>()
.RegisterType<ISecurityService, SecurityService>();
MyClassThatNeedsSecurity myClass =
container.Resolve<MyClassThatNeedsSecurity>();
}
}
}
This will print:
SecurityRepository created
SecurityService created
Repository is A SecurityRepository
My class has security: A SecurityService
You have a number of options, such as pre-creating your instances (as you showed in your follow-up post) or extending the lifetime of injected dependencies so that they're not recreated every time they're needed. But for the base case, this will work.
here is some more information. The constructor of my class is
public SecurityService(ISecurityRepository repository)
: base(repository)
{
}
After playing around a little bit, i managed to do the following but this causes me to create instances FIRST ... It seems to work.., but its an alternative.
// Create unity container my service and repository
ISecurityRepository securityRepository = new SecurityRepository();
ISecurityService securityService = new SecurityService(securityRepository);
container = new UnityContainer();
container.RegisterInstance<ISecurityRepository>(securityRepository);
container.RegisterInstance<ISecurityService>(securityService);