Providing Autofac with pre-resolved dependencies - c#

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);
}
}
}

Related

Autofac can't resolve dependency

I can't resolve registered type IQMService.
Error:No accessible constructors were found for the type '__ASP.FastObjectFactory_app_web_gmbeg5il'.
Below is the code invoke Resolve:
public IQMService qMService;
public QMModule QMModule;
public PageBase() {
qMService = AutofacDependency.Resolve<IQMService>();
QMModule = new QMModule(qMService);
}
Definition of model:
public interface IQMService{
somefunction()
}
public class QMService : IQMService{
public QMService()
{
someprocess();
}
}
Previously working code of AutofacDependency() defined:
static AutofacDependency()
{
Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies ();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes (assemblys);
builder.RegisterModule (new ConfigurationSettingsReader ("autofac"));
container = builder.Build();
}
After I upgrade .net from 4.0 to 4.8, and update autofac from 3.5.2 to 6.4.0, ConfigurationSettingsReader no longer exist, so I have to update the config file and change the code to below, not work,
static AutofacDependency()
{
Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies ();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes (assemblys);
//builder.RegisterModule (new ConfigurationSettingsReader ("autofac"));
ConfigurationBuilder cfgbuilder = new ConfigurationBuilder();
cfgbuilder.AddXmlFile("autofac.config");
var module = new ConfigurationModule(cfgbuilder.Build());
builder.RegisterModule(module);
container = builder.Build();
}
I also test this way
static AutofacDependency()
{
Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies ();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes (assemblys);
builder.RegisterType<Strix.QM.Service.QMService>().As<Strix.QM.Service.IQMService>().InstancePerLifetimeScope();
container = builder.Build();
}
But I always get the error No accessible constructors were found even though I can it's defined. Thank you if any help, and if any necessary information missing please comment I will append it.
The short version here is that this...
Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies ();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes (assemblys);
...is really not something you should ever do. This literally registers every type in the entire running system, including everything in every .NET base library, into dependency injection. Be way, way more selective than that when registering. I'd bet if you remove that and only register the stuff you need, then DI won't try to resolve the odd .NET stuff that doesn't have accessible constructors.

How to run non-static code that uses dependency injection in .net core

I created a new console app in VS2017 and I am trying to run this code to demonstrate I can encrypt and decrypt strings in .NET Core. I have tried calling RunSample from the Program.cs Main but it wants it to be a static method. If I make RunSample static then I'm getting a null reference exception when trying to set the var protectedpayload.
using System;
using Microsoft.AspNetCore.DataProtection;
public class MyClass
{
private readonly IDataProtector _protector;
public MyClass(IDataProtectionProvider provider)
{
_protector = provider.CreateProtector("Contoso.MyClass.v1");
}
public void RunSample()
{
Console.WriteLine("Enter input:");
string input = Console.ReadLine();
var protectedPayLoad = _protector.Protect(input);
Console.WriteLine($"Protect returned: {protectedPayLoad}");
var unprotectedPayLoad = _protector.Unprotect(protectedPayLoad);
Console.WriteLine($"Unprotect returned: {unprotectedPayLoad}");
}
}
How can I run it?
UPDATE:
Trying to run it from Program.cs, I have the following but .MyClass has a "cannot resolve" syntax error / red underline on it.
using System;
namespace encrypttest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
new Program().MyClass.RunSample();
}
}
}
UPDATE 2:
I created my app by going to new project, .NET Core and then Console App (.NET Core):
UPDATE 3:
I've changed my code as suggested but have the following error:
UPDATE 4:
I've removed the using as suggested, but now I get:
you need DI your IDataProtector in Program.cs
class Program
{
static void Main(string[] args)
{
ServiceCollection services = new ServiceCollection();
services.AddScoped<IDataProtector>();
services.AddScoped<MyClass>();
using (var serviceProvider = services.BuildServiceProvider())
{
var service = serviceProvider.GetService<MyClass>();
service.RunSample();
}
}
}
update - 1:
Install from NuGet
Install-Package Microsoft.Extensions.DependencyInjection
update - 2:
remove using like this
var serviceProvider = services.BuildServiceProvider()
var service = serviceProvider.GetService<MyClass>();
service.RunSample();
update - 3:
My code is DI example...
you need change like this
ServiceCollection services = new ServiceCollection();
services.AddDataProtection();
services.AddScoped<MyClass>();
var serviceProvider = services.BuildServiceProvider();
var service = serviceProvider.GetService<MyClass>();
service.RunSample();
Install from NuGet
Install-Package Microsoft.AspNetCore.DataProtection
The complaint about making RunSamples static is because you're not newing up the class that defines it. If it's not an instance, then the method must be static to access it. However, since the class (and method) has a dependency that needs to be satisfied, you cannot make it static. Simply, you need to use dependency injection to create an instance of your class with its dependency satisfied in order to call the RunSamples method.
To use dependency injection in a console app, it's as simple as adding the Microsoft.Extensions.DependencyInjection NuGet package, and then:
var services = new ServiceCollection()
.BuildServiceProvider();
However, that's not very useful as you haven't registered anything, so just do all that before calling BuildServiceProvider:
var serviceProvider = new ServiceCollection()
.AddDataProtection()
.AddScoped<MyClass>()
.BuildServiceProvider();
Since you want to utilize data protection, you'll obviously need the Microsoft.AspNetCore.DataProtection NuGet as well.
Then, when you want an instance of MyClass:
using (var scope = serviceProvider.CreateScope())
{
var myClass = scope.GetRequiredService<MyClass>();
myClass.RunSamples();
}
I guess this is what you are missing (from this link: https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/using-data-protection?view=aspnetcore-2.1)
public static void Main(string[] args)
{
// add data protection services
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection();
var services = serviceCollection.BuildServiceProvider();
// create an instance of MyClass using the service provider
var instance = ActivatorUtilities.CreateInstance<MyClass>(services);
instance.RunSample();
}
You have to initiate an instance of IDataProtectionProvider by calling ActivatorUtilities.CreateInstance

configure Unity to resolve a constructor parameter and interface

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).

Unity Config error in console application

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,

Problem with Registering Mock objects with Unity

I have a named registration like this:
Unity.Container.RegisterType<IScheduler, DailyScheduler>("Daily");
This is how I resolve interfaces at runtime:
var Scheduler = Unity.Container.Resolve<IScheduler>("Daily");
I override this registration in my Test class like this:
var schedulerMock = new Mock<IScheduler>();
schedulerMock.SetupSet(s => s.IntervalString = It.IsAny<string>());
Unity.Container.RegisterInstance("Daily", schedulerMock.Object);
The problem is that the code is always resolving IScheduler to a DailyScheduler type not the mock object resulting in the VerifyAll method to fail. Am I missing something?
Are you using Unity 2.0? It works for me, at least using an instance of the container. I just tried it in LINQPad:
void Main()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IScheduler, DailyScheduler>("Daily");
var schedulerMock = new Mock<IScheduler>();
schedulerMock.Setup(x => x.Name).Returns("Mock!");
container.RegisterInstance("Daily", schedulerMock.Object);
IScheduler s = container.Resolve<IScheduler>("Daily");
Console.WriteLine(s.Name); // Prints "Mock!"
}
public interface IScheduler
{
string Name { get; }
}
public class DailyScheduler: IScheduler
{
public string Name { get { return "Daily!"; } }
}
Assuming Unity.Container is a Singleton, is it possible that code is changing the registration after the test setup calls RegisterInstance?

Categories