How can I use dependency injection without changing/adding constructors - c#

I have the following asp.net c# code
{
public class Test
{
ISomeService _someService;
public Test()
{
}
public void DoSomething()
{
_someService.Do();
}
}
I need to provide ISomeService to Test class, and I dont know how to do it. I am not allowed to add additional construction which would make entire problem go away, for example
public Test(ISomeService someService)
{
_someService = someService;
}
I tried using setter injection or method injection but that didnt do the trick.
Implementation of ISomeService in SomeService class also uses constructor injection, such as
public SomeService(IService1 service1, Iservice2 service2)
Not sure what to do here.
HERE IS A COMPLETE CODE
public class Startup
{
private IService _service;
public Startup()
{
}
public Startup(IService service)
{
_service = service;
}
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
var container = new UnityContainer();
container.RegisterType<IService, Service>();
config.DependencyResolver = new UnityDependencyResolver(container);
app.UseWebApi(config);
_service.DoSomething());
}
}
_service is null

I would suggest you use a factory to create your object. That would have an instance of ISomeService injected on the constructor.
Then in a CreateTest() method on your factory set the ISomeService property directly.
public class Factory
{
private readonly ISomeService someService;
public Factory(ISomeService someService)
{
this.someService = someService ?? throw new ArgumentNullException(nameof(someService));
}
public TestClass CreateTestClass()
{
var instance = new TestClass();
instance.SomeService = this.someService;
return instance;
}
}
You should note that most DI providers have built in functionality to allow factory semantics without the need to create your own factories.

What I ended up doing is this
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IService, Service>();
// create service provider
var serviceProvider = serviceCollection.BuildServiceProvider();
_service = ActivatorUtilities.CreateInstance<Service>(serviceProvider);
_service.DoSomething();
Thanks to this answer Dependency Injection with classes other than a Controller class

Related

Using Factory Pattern with ASP.NET Core Dependency Injection

I need the ASP.Net Core dependency injection to pass some parameters to the constructor of my GlobalRepository class which implements the ICardPaymentRepository interface.
The parameters are for configuration and come from the config file and the database, and I don't want my class to go and reference the database and config itself.
I think the factory pattern is the best way to do this but I can't figure out the best way to use a factory class which itself has dependencies on config and database.
My startup looks like this currently:
public class Startup
{
public IConfiguration _configuration { get; }
public IHostingEnvironment _environment { get; }
public Startup(IConfiguration configuration, IHostingEnvironment environment)
{
_configuration = configuration;
_environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IDbRepository, DbRepository>();
var connection = _configuration.GetConnectionString("DbConnection");
services.Configure<ConnectionStrings>(_configuration.GetSection("ConnectionStrings"));
services.AddDbContext<DbContext>(options => options.UseSqlServer(connection));
services.AddScoped<ICardPaymentRepository, GlobalRepository>();
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IRFDbRepository rFDbRepository)
{
...
}
}
The GlobalRepository constructor looks like this:
public GlobalRepository(string mode, string apiKey)
{
}
How do I now pass the mode from configuration and the apiKey from the DbRepository into the constructor from Startup?
Use the factory delegate overload when registering the repository
//...
string mode = "get value from config";
services.AddScoped<ICardPaymentRepository, GlobalRepository>(sp => {
IDbRepository repo = sp.GetRequiredService<IDbRepository>();
string apiKey = repo.GetApiKeyMethodHere();
return new GlobalRepository(mode, apiKey);
});
//...
Alternative using ActivatorUtilities.CreateInstance
//...
string mode = "get value from config";
services.AddScoped<ICardPaymentRepository>(sp => {
IDbRepository repo = sp.GetRequiredService<IDbRepository>();
string apiKey = repo.GetApiKeyMethodHere();
return ActivatorUtilities.CreateInstance<GlobalRepository>(sp, mode, apiKey);
});
//...
You might want to also check these links...
https://github.com/Microsoft/AspNetCoreInjection.TypedFactories
https://espressocoder.com/2018/10/08/injecting-a-factory-service-in-asp-net-core/
With regard to the last link the code is basically:
public class Factory<T> : IFactory<T>
{
private readonly Func<T> _initFunc;
public Factory(Func<T> initFunc)
{
_initFunc = initFunc;
}
public T Create()
{
return _initFunc();
}
}
public static class ServiceCollectionExtensions
{
public static void AddFactory<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
services.AddTransient<TService, TImplementation>();
services.AddSingleton<Func<TService>>(x => () => x.GetService<TService>());
services.AddSingleton<IFactory<TService>, Factory<TService>>();
}
}
I think castle windsor's typed factories dispose of all they created when they themselves are disposed (which may not be always the best idea), with these links you would probably have to consider if you are still expecting that behaviour. When I reconsidered why I wanted a factory I ended up just creating a simple factory wrapping new, such as:
public class DefaultFooFactory: IFooFactory{
public IFoo create(){return new DefaultFoo();}
}
I'll show the minimal example for the factory that resolves ITalk implementation by a string key. The solution can be easily extended to a generic factory with any key and entity type.
For the sake of example let's define the interface ITalk and two implementations Cat and Dog:
public interface ITalk
{
string Talk();
}
public class Cat : ITalk
{
public string Talk() => "Meow!";
}
public class Dog : ITalk
{
public string Talk() => "Woof!";
}
Now define the TalkFactoryOptions and TalkFactory:
public class TalkFactoryOptions
{
public IDictionary<string, Type> Types { get; } = new Dictionary<string, Type>();
public void Register<T>(string name) where T : ITalk
{
Types.Add(name, typeof(T));
}
}
public class TalkFactory
{
private readonly IServiceProvider _provider;
private readonly IDictionary<string, Type> _types;
public TalkFactory(IServiceProvider provider, IOptions<TalkFactoryOptions> options)
{
_provider = provider;
_types = options.Value.Types;
}
public ITalk Resolve(string name)
{
if (_types.TryGetValue(name, out var type))
{
return (ITalk)_provider.GetRequiredService(type);
}
throw new ArgumentOutOfRangeException(nameof(name));
}
}
Add extension method for simple implementations registration:
public static class FactoryDiExtensions
{
public static IServiceCollection RegisterTransientSpeaker<TImplementation>(this IServiceCollection services, string name)
where TImplementation : class, ITalk
{
services.TryAddTransient<TalkFactory>();
services.TryAddTransient<TImplementation>();
services.Configure<TalkFactoryOptions>(options => options.Register<TImplementation>(name));
return services;
}
}
And register the Cat and Dog implementations:
services
.RegisterTransientSpeaker<Cat>("cat")
.RegisterTransientSpeaker<Dog>("dog");
Now you can inject the TalkFactory and resolve the implementation by the name:
var speaker = _factory.Resolve("cat");
var speech = speaker.Talk();
The trick here is Configure<TOptions(). This method is additive, which means you can call it multiple times to configure the same instance of TalkFactoryOptions.
As I said this example can be converted into a generic factory and add the ability to register factory delegate instead of a concrete type. But the code will be too long for SO.
I've been running up against the same issue and solved this by registering a set of open generics for IFactory<TService>, IFactory<T, TService>, IFactory<T1, T2, TService> etc. A single call on startup to add this facility then allows any IFactory<...> to be injected / resolved, which will instantiate an instance of TService for a given set of argument types, provided a constuctor exists whose last parameters match the T* types of the factory generic. Source code, NuGet package and explanatory blog article below:
https://github.com/jmg48/useful
https://www.nuget.org/packages/Ariadne.Extensions.ServiceCollection/
https://jon-glass.medium.com/abstract-factory-support-for-microsoft-net-dependency-injection-3c3834894c19
An alternative to the other answers. Follow the options pattern.
First introduce a strong type for your configuration;
public class RespositoryOptions {
public string Mode { get; set; }
public string ApiKey { get; set; }
}
public GlobalRepository(IOptions<RespositoryOptions> options) {
// use options.Value;
}
You could still use a service factory method to unwrap the IOptions<RespositoryOptions> if you prefer. But then you lose the ability to verify that your service dependencies have all been met.
Then you can seed your options from configuration;
public void ConfigureServices(IServiceCollection services) {
...
services.Configure<RespositoryOptions>(_configuration.GetSection(name));
...
}
And write another service to update that options instance from other services, like a database;
public class ConfigureRespositoryOptions : IConfigureOptions<RespositoryOptions> {
private readonly IDbRepository repo;
public ConfigureRespositoryOptions(IDbRepository repo) {
this.repo = repo;
}
public void Configure(RespositoryOptions config) {
string apiKey = repo.GetApiKeyMethodHere();
}
}

How do I register with Autofac a type that implements multiple interfaces?

I have 2 classes that handle 2 different resources, they are SettingsHandler and StorageHandler.
Both have similar constructors:
public class StorageHandler
{
private readonly IStorageConfig _config;
private readonly ApiClient _apiClient;
public StorageHandler(IStorageConfig config, ApiClient apiClient)
{
_config = config;
_apiClient = apiClient;
}
/------- ! -------/
}
public class SettingsHandler
{
private readonly ISettingsConfig _config;
private readonly ApiClient _apiClient;
public SettingsHandler(ISettingsConfig config, ApiClient apiClient)
{
_config = config;
_apiClient = apiClient;
}
/------- ! -------/
}
Then I have my config like this:
public class Config: ISettingsConfig, IStorageConfig
{
}
In my module class I register the config file twice (more times if there are more interfaces) like so:
builder.RegisterType<Config>().As<ISettingsConfig>().SingleInstance();
builder.RegisterType<Config>().As<IStorageConfig>().SingleInstance();
I was hoping that would work, but I am not sure I am doing this correctly.
Can someone give me a hand?
You can register it like:
builder.RegisterType<Config>()
.As<ISettingsConfig>()
.As<IStorageConfig>()
.SingleInstance();
but make sure you register StorageHandler and SettingsHandler too:
builder.RegisterType<StorageHandler>().AsSelf();
builder.RegisterType<SettingsHandler>().AsSelf();
Once you built the container you should be able to Resolve StorageHandler and SettingsHandler:
var container = builder.Build();
var storageHandler = container.Resolve<StorageHandler>();
var settingsHandler = container.Resolve<SettingsHandler>();
Note
It's also possible to call AsImplementedInterfaces() in case you have lots of interfaces on a class.

circular dependency in dotnet core 2.0 console application using ServiceCollection

I'm trying to setup a simple dependency injection using IServiceCollection that comes with Dotnet core 2.0 Microsoft.Extensions.DependencyInjection nuget package. I am new to it so I started with a small experiment:
public interface IService
{
}
public class JobService : IService
{
public IService m_service { get; set; }
public JobService(IService service)
{
m_service = service;
}
}
class Program
{
static void Main(string[] args)
{
IServiceCollection serviceCollection = new ServiceCollection();
ConfigureService(serviceCollection);
var serviceProvider = serviceCollection.BuildServiceProvider();
//exception on next line
var service = serviceProvider.GetService<App>();
Console.WriteLine("Hello World!");
}
private static void ConfigureService(IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<IService, JobService>();
serviceCollection.AddTransient<App>();
}
}
The above should register all types with the container but during runtime, I get :
System.InvalidOperationException: 'A circular dependency was detected for the service of type 'TestCore.IService'.'
I don't see a circular dependency in my implementation. Can someone point out where this circular dependency comes from?
As for the service, it should be injected into this App class I made:
public class App
{
private IService m_service;
public App(IService service)
{
m_service = service;
}
}
The dependency injection framework is unable to resolve the dependency for IService due to a circular dependency.
This arises from the fact that your implementation of IService (JobService) is itself dependent on an implementation of IService (i.e. itself). It would not be possible to instantiate JobService as it is dependent on itself. The DI framework recognizes this and throws the exception you are seeing.
In order to avoid this you would need to make JobService dependent on an implementation of a different interface:
public interface IService
{
}
public interface IAnotherService
{
}
public class JobService : IService
{
public IAnotherService m_service { get; set; }
public JobService(IAnotherService service)
{
m_service = service;
}
}
public class AnotherService : IAnotherService
{
}
class Program
{
static void Main(string[] args)
{
IServiceCollection serviceCollection = new ServiceCollection();
ConfigureService(serviceCollection);
var serviceProvider = serviceCollection.BuildServiceProvider();
//exception on next line
var service = serviceProvider.GetService<App>();
Console.WriteLine("Hello World!");
}
private static void ConfigureService(IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<IAnotherService, AnotherService>();
serviceCollection.AddTransient<IService, JobService>();
serviceCollection.AddTransient<App>();
}
}
Edit/Aside: If you were using Autofac you could use keep the IService dependency in JobService but provide different implementations using Named and Keyed Services.

Autofac: Register type where parameter is dependant on propertie of ApiController

I want to register Repository with Autofac so that it is the same as in parameterless constructor? Which I then intend to remove.
Example code:
public class GroupController : ApiController
{
protected IRepository Repository;
protected ISettings Settings;
protected GroupController()
{
Settings = new Settings();
Repository = new Repository(User.Identity.IsAuthenticated ? Settings.ConfigAuth : Settings.Config)
}
public GroupController(ISettings settings, IRepository repository)
{
Repository = repository;
Settings = settings;
}
}
This is an api controller in .Net framework.
Settings are written in web.config.
This is how autofac config looked like before I had only one config.
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var settings = new Settings();
Builder.RegisterType<Repository>()
.As<IRepository>()
.WithParameter(new TypedParameter(typeof(RepoConfig), settings.Config))
.InstancePerRequest();
There is currently only one implementation of IRepository.
public class Repository : IRepository
{
private readonly RepoConfig _config;
public(RepoConfig config)
{
_config = config;
}
}
You can use Lambda Registrations. From Autofac documentation
You can register components using lambda expressions and make a
runtime choice right in the registration for how to handle things.
Note this may have an effect on performance depending on the expense
of the runtime check and how often it gets executed, but it’s an
option.
http://docs.autofac.org/en/latest/register/registration.html (Check lambda expression components)
Based on your example using Lambda Registrations, you can do autofac reg as below (I have not tested)
var builder = new ContainerBuilder();
builder.Register(c => new Settings()).As<ISettings>();
builder.Register<Repository>((c) =>
{
ISettings s = c.Resolve<ISettings>();
Settings repoSettings = User.Identity.IsAuthenticated ? s.ConfigAuth : s.Config;
return new Repository(repoSettings);
}
)
.As<IRepository>()
.InstancePerRequest();
Container = builder.Build();
Then remove your parameter-less constructor and add
public GroupController(IRepository repository)
{
Repository = repository;
}
hope it helps.
I implemented an workaround for this implementation. Not the best way but it works.
This way initialization of Repository doesn't need parameter and I set it with a propertie in constructor of Controller.
public class GroupController : ApiController
{
protected IRepository Repository;
protected ISettings Settings;
public GroupController(ISettings settings, IRepository repository)
{
Settings = settings;
Repository = repository;
Repository.RepoConfig = User.Identity.IsAuthenticated ? Settings.ConfigAuth : Settings.Config
}
}
public class Repository : IRepository
{
private readonly RepoConfig _config;
public RepoConfig RepoConfig
{
get => _config;
set
{
_config = value;
}
}
...
}
And for autofac there is standard DI refister:
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
Builder.RegisterType<Repository>()
.As<IRepository>()
.InstancePerRequest();

Dependency injection, inject with parameters

I'm using vNext implementation of DI.
How to pass parameters to constructor?
For example, i have class:
public class RedisCacheProvider : ICacheProvider
{
private readonly string _connectionString;
public RedisCacheProvider(string connectionString)
{
_connectionString = connectionString;
}
//interface methods implementation...
}
And service register:
services.AddSingleton<ICacheProvider, RedisCacheProvider>();
How to pass parameter to constructor of RedisCacheProvider class?
For example for Autofac:
builder.RegisterType<RedisCacheProvider>()
.As<ICacheProvider>()
.WithParameter("connectionString", "myPrettyLocalhost:6379");
You can either provide a delegate to manually instantiate your cache provider or directly provide an instance:
services.AddSingleton<ICacheProvider>(provider => new RedisCacheProvider("myPrettyLocalhost:6379"));
services.AddSingleton<ICacheProvider>(new RedisCacheProvider("myPrettyLocalhost:6379"));
Please note that the container will not explicitly dispose of manually instantiated types, even if they implement IDisposable. See the ASP.NET Core doc about Disposal of Services for more info.
If the constructur also has dependencies that should be resolved by DI you can use that:
public class RedisCacheProvider : ICacheProvider
{
private readonly string _connectionString;
private readonly IMyInterface _myImplementation;
public RedisCacheProvider(string connectionString, IMyInterface myImplementation)
{
_connectionString = connectionString;
_myImplementation = myImplementation;
}
//interface methods implementation...
}
Startup.cs:
services.AddSingleton<IMyInterface, MyInterface>();
services.AddSingleton<ICacheProvider>(provider =>
RedisCacheProvider("myPrettyLocalhost:6379", provider.GetService<IMyInterface>()));
You can use :
services.AddSingleton<ICacheProvider>(x =>
ActivatorUtilities.CreateInstance<RedisCacheProvider>(x, "myPrettyLocalhost:6379"));
Dependency Injection : ActivatorUtilities will inject any dependencies to your class.
Here is the link to the MS docs: Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance
Also: See #poke's answer here for more information. Basically it pulls from the provided services and any other params you pass, like a composit constructor.
You can use something like the example code below.
Manager class:
public class Manager : IManager
{
ILogger _logger;
IFactory _factory;
public Manager(IFactory factory, ILogger<Manager> logger)
{
_logger = logger;
_factory = factory;
}
}
Startup.cs class:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFactory, Factory>(sp =>
{
var logger = sp.GetRequiredService<ILogger<Factory>>();
var dbContext = sp.GetRequiredService<MyDBContext>();
return new Factory(dbContext, logger);
});
services.AddTransient<IManager, Manager>(sp =>
{
var factory = sp.GetRequiredService<IFactory>();
var logger = sp.GetRequiredService<ILogger<Manager>>();
return new Manager(factory, logger);
});
}
You can read the full example here: DI in Startup.cs in .Net Core
A bit late to the party, but you could DI inject a factory that creates and exposes an instance of your provider class.

Categories