I am doing some dependency injection with Microsoft.Practices.Unity.
For some classes, I am using injection factories like this:
container.RegisterType<ICar>(new InjectionFactory(o => {return new Car("Toyota")}));
Later in my code, I want to be able to find out if I have used or not an injection factory for a given interface.
I see that I can get regitrations in container.Registrations, but these objects do not give me injection members.
A possible way to get them would be to implement a wrapper around my IUnityContainer, that records the injection members.
But maybe there is some better way that directly leverages unity API ? Is there a way to get these injection members directly from the unity container ?
as suggested in my comment (but not with unity). Just copied it from my project.
public void ConfigureServices(IServiceCollection services)
{
var lgr = LogManager.GetCurrentClassLogger();
var logger = new NlogLogger(lgr);
services.AddSingleton<ILogger>(provider => logger);
services.AddSingleton<IMachineConfigFactory, MachineConfigFactory>();
services.AddSingleton<IMemoryCacheService, MemoryCacheService>();
services.AddSingleton<IServerManagerService, ServerManagerService>();
services.AddSingleton<ISubscriberServerHubService, SubscriberServerHubService>();
services.AddSingleton<IPurgeService, PurgeService>();
var configuration = GetConfiguration(option);
services.AddSingleton(configuration);
services.AddOptions();
services.Configure<HostConfig>(configuration.GetSection("HostConfig"));
services.AddSingleton<ServerManager>();
services.AddSingleton<CacheManagerService>();
return services;
}
and then:
public class HealthChecker : IHealthChecker
{
private readonly HealthCheckerConfig _config;
private readonly IAssetProvider _assetProvider;
public HealthChecker(IOptions<HealthCheckerConfig> config, IAssetProvider assetProvider)
{
_config = config.Value;
_assetProvider = assetProvider;
}
}
or am i missing something?
Related
As you can tell from this question I’m still a newbie with .Net Core and understanding about Dependency Injection.
I’m in the process of writing a .Net Core Console app and I was finally able to get to a point where I’m doing a little bit of DI for logging and configuration settings. What I’m not understanding is using DI when calling another class from within a class.
I created a class called AppHost which has a function called Run() in it. In my Program.cs I’ve setup DI and then will call the AppHost.Run() to execute my main code.
Inside of my AppHost I need to call some database functions in another file I’ve called Data/DataManager. My understanding was that I would setup the class in the DI container and would be able to get my logging and configuration from there. As far as I know, I’ve done that in my “host” declaration. However, when I call my DataManager.GetActiveEmployees() it’s wanting me to create an object since my DataManager is not set a static. When I create a DataManager object it is wanting me to pass in my logger and configuration since that is what is in the constructor of the class. I can do that but is sure seems like that is not the correct way to do it. I thought with DI I would be able to get the logger and configuration out of DI and not need to pass it into the object? Am I supposed to create the DataManager object and pass the logger and configuration from my AppHost into it?
Program.cs
var host = Host.CreateDefaultBuilder().ConfigureServices((context, services) =>
{
services.AddTransient<IAppHost, AppHost>();
services.AddTransient<IFileManager, FileManager>();
services.AddTransient<IDataManager, DataManager>();
services.AddLogging(builder =>
{
builder.AddNLog("nlog.config");
});
}).Build();
var svc = ActivatorUtilities.CreateInstance<AppHost>(host.Services);
svc.Run();
AppHost.cs
private void CheckEmailAddresses()
{
DataManager oDataManager = new DataManager();
var listEmployees = new List<Employee>();
listEmployees = oDataManager.GetActiveEmployees();
}
DataManager.cs
public class DataManager : IDataManager
{
private readonly ILogger<DataManager> _log;
private readonly IConfiguration _configuration;
public DataManager(ILogger<DataManager> log, IConfiguration config)
{
_log = log;
_configuration = config;
}
}
You've already registered your IDataManager in DI dependency. So, instead of doing new which killing the purpose of DI anyway you need to change your CheckEmailAddresses like this.
private void YouClassName()
{
private readonly IDataManager _dataManager;
public YouClassName(IDataManager dataManager)
{
_dataManager = dataManger.
}
private void CheckEmailAddresses()
{
var listEmployees = new List<Employee>();
listEmployees = _dataManager.GetActiveEmployees();
}
}
Now we are inject IDataManager into your class and your other dependencies like Logger will be build automatically.
I am writing a dotnet standard library class that will contain an HttpClient that calls a web api method. I want the input/output classes available for ease of use to the caller. The projects consuming the package will be framework apps (4.7)
As far as I can tell the "correct" way to do that is to have a extension method taking an IServiceCollection which registers my client according to some known "defaults" and allows clients to pass in options.
I guess I'm wondering how that would get utilized in a framework app properly? So after I configure the service collection pipeline to know how to do things properly... How does the framework app ever get a ServiceCollection? Do i just make a static class that news up a ServiceCollection and stores the reference? Again to make that as easy as possible would I just include a static factory method in the library class to do that for the consumer? Something like this?
public sealed class DependencyInjectionHelper
{
private static readonly Lazy<DependencyInjectionHelper> _instance = new Lazy<DependencyInjectionHelper>();
public static DependencyInjectionHelper Instance => _instance.Value;
public readonly IServiceCollection ServiceCollection;
public readonly ServiceProvider ServiceProvider;
private DependencyInjectionHelper()
{
ServiceCollection = new ServiceCollection();
ServiceProvider = ServiceCollection.BuildServiceProvider();
}
public MyHttpClient GetClient()
{
return ServiceProvider.GetService<MyHttpClient>();
}
}
public static IServiceCollection AddMyClient(this IServiceCollection services, Action<MyClientOptions, IServiceProvider> configureOptions)
{
services.AddOptions();
services.AddLogging();
services.AddHttpClient<IMyClient, MyClient>().ConfigureHttpClient(client =>
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//configure baseaddress from options here somehow
client.BaseAddress = new Uri("https://someurl:5001/");
if (!AppContext.TryGetSwitch("System.Net.Http.UseSocketsHttpHandler", out var enabled) || !enabled)
{
//https://www.nimaara.com/beware-of-the-net-httpclient/
var servicePoint = ServicePointManager.FindServicePoint(client.BaseAddress);
int desiredLeaseTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;
if (servicePoint.ConnectionLeaseTimeout != desiredLeaseTimeout)
{
servicePoint.ConnectionLeaseTimeout = desiredLeaseTimeout;
}
}
});
return services;
}
Guess i'm looking for examples in the proper pattern to accomplish this. I understand dependency injection all the way through is probably the best way... but I can't just change monolithic apps to have it. So i want something flexible enough to be used if you have dependency injection, but super simple to consume out of the box.
I have no extensive experience in testing, but I'm setting up a Singleton instance injection for a class I created. However, I don't know how to call that class. If I do call, I need constructors. If I create an additional empty constructor, the dependencies will appear as null.
I have spent a few days looking for it in the documentation, but it only shows examples of how to inject. I cannot find how to instantiate the class afterwards.
Also, I see some examples, but many of them are using MVC Controllers, which are instantiated automatically by the framework.
Connector.cs
public class Connector
{
private IConfiguration _configuration;
public Connector(IConfiguration configuration) {
_configuration = configuration;
}
public Connector() {
}
public string DoSomething() {
//return Something related to _configuration
}
}
startup.cs
public void ConfigureServices(IServiceCollection services)
{
//Other default config
services.AddSingleton(new Connector(Configuration));
}
HomeController.cs
public IActionResult Index()
{
var x = (new Connector()).DoSomething(); //This will fail as _configuration is not injected
return View();
}
How can I call Connector with the injected Configuration? Am I missing any dependency resolving? Am I calling the class incorrectly?
I hope somebody can shed some light on this.
The idea behing DI container is that you don't need to handle object creation in your methods. Your HomeController also doesn't need to know if Connector is actually a singleton or not.
You just inject the dependency to your constructor.
Since you have configured it to be a singleton, DI container will resolve Connector to the same instance every time.
public class HomeController
{
private readonly Connector _connector;
public HomeController(Connector connector)
{
_connector = connector;
}
public IActionResult Index()
{
var x = _connector.DoSomething();
// ...
}
I have implemented an adapter that implement IServiceProvider and returned it from the ConfigureServices method in the Startup. class:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var kernel = new StandardKernel();
var container = new NinjectComponentContainer(kernel);
// ...
return ServiceProviderFactory.Create(container, services);
}
However, my implementation doesn't seem to be used everywhere. I even tried to override the IHttpContextAccessor to return a modified HttpContext:
public HttpContext HttpContext {
get
{
var result = _httpContextAccessor.HttpContext;
result.RequestServices = _serviceProvider;
return result;
}
set => _httpContextAccessor.HttpContext = value;
}
To test whether I could get to my implementation I used a filter in order to see what the HttpContext.RequestServices would return:
public class AuthorizationTestAttribute : ActionFilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var service = context.HttpContext.RequestServices.GetService(typeof(IAccessConfiguration));
}
}
The type returned by context.HttpContext.RequestServices is:
My main issue was trying to get registered components resolved in the constructor of a filter but it always seems to fail saying the component is not registered. However it does seem to work when using the TypeFilter attribute:
[TypeFilter(typeof(RequiresSessionAttribute))]
However, my attribute does inherit from TypeFilter:
public class RequiresSessionAttribute : TypeFilterAttribute
{
public RequiresSessionAttribute() : base(typeof(RequiresSession))
{
Arguments = new object[] { };
}
private class RequiresSession : IAuthorizationFilter
{
private readonly IAccessConfiguration _configuration;
private readonly IDatabaseContextFactory _databaseContextFactory;
private readonly ISessionQuery _sessionQuery;
public RequiresSession(IAccessConfiguration configuration,
IDatabaseContextFactory databaseContextFactory, ISessionQuery sessionQuery)
{
Guard.AgainstNull(configuration, nameof(configuration));
Guard.AgainstNull(databaseContextFactory, nameof(databaseContextFactory));
Guard.AgainstNull(sessionQuery, nameof(sessionQuery));
_configuration = configuration;
_databaseContextFactory = databaseContextFactory;
_sessionQuery = sessionQuery;
}
I did come across this question but there is no definitive answer.
Any ideas on how to correctly provider a custom implementation of the IServiceProvider interface that will be used throughout the solution?
Even though Microsoft states that it is possible to replace the built-in container it appears as though it is not quite this simple, or even possible.
As stated by Steven in his very first comment, if you choose to use your container of choice, you should run them side-by-side.
The guidance from Microsoft suggests changing the ConfigureServices in the Startup class from this:
public void ConfigureServices(IServiceCollection services)
{
// registrations into services
}
to the following:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var container = new YourContainer(); // Castle, Ninject, etc.
// registrations into container
return new YourContainerAdapter(container);
}
However, there are a number of issues with this since there are already framework registrations in services that we do not necessarily know how to re-register in our own container. Well, there is a descriptor so if our container supports all the various methods then it is actually possible to re-register all the components. The various DI containers have different mechanisms when it comes to registration and service resolution. Some of them have a very hard distinction between the two making it quite tricky at times to accommodate a "common" solution.
My initial idea was to provide an adapter that accepts both my own container as well as the services collection from which I would then get the built-in service provider by calling services.BuildServiceProvider(). In this way I could attempt to resolve from the built-in provider and then, if the resolving bit failed, attempt to resolve from my own container. However, it turns out that the .net core implementation does in fact not use the returned IServiceProvder instance.
The only way I could get this to work was to wire up my own container and use it to resolve my controllers. That could be done by providing an implementation of the IControllerActivator interface.
In this particular implementation I was fiddling with Ninject although I typically prefer Castle but the same applies to any DI container:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKernel>(new StandardKernel());
services.AddSingleton<IControllerActivator, ControllerActivator>();
}
public class ControllerActivator : IControllerActivator
{
private readonly IKernel _kernel;
public ControllerActivator(IKernel kernel)
{
Guard.AgainstNull(kernel, nameof(kernel));
_kernel = kernel;
}
public object Create(ControllerContext context)
{
return _kernel.Get(context.ActionDescriptor.ControllerTypeInfo.AsType());
}
public void Release(ControllerContext context, object controller)
{
_kernel.Release(controller);
}
}
In order to register the controller types I did my DI wiring in the Configure method since I have access to the IApplicationBuilder which can be used to get to the controller types:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime)
{
var kernel = app.ApplicationServices.GetService<IKernel>();
// kernel registrations
var applicationPartManager = app.ApplicationServices.GetRequiredService<ApplicationPartManager>();
var controllerFeature = new ControllerFeature();
applicationPartManager.PopulateFeature(controllerFeature);
foreach (var type in controllerFeature.Controllers.Select(t => t.AsType()))
{
kernel.Bind(type).ToSelf().InTransientScope();
}
applicationLifetime.ApplicationStopping.Register(OnShutdown);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(
options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()
);
app.UseMvc();
}
This worked swimmingly for the controllers but resolving "filters" was still a problem given that they use the IFilterFactory on the filter itself to implement a factory method:
public IFilterMetadata CreateInstance (IServiceProvider serviceProvider);
Here we can see that the IServiceProvider implementation is provided in order to resolve any depedencies. This applies when using the TypeFilterAttribute or when defining new filters that inherit from TypeFilterAttribute as I have in my question.
This mechanism is actually a very good example of the difference between "Inversion of Control" and "Dependency Injection". The control lies with the framework (inversion) and we have to provide the relevant implementations. The only issue here is that we are not able to hook in properly since our provided IServiceProvider instance is not passed to the CreateInstance method which then results in a failure when attempting to create an instance of the filter. There are going to be a number of ways to fix this design but we'll leave that to Microsoft.
In order to get my filters working I decided to go the "cross-wiring" route as alluded to by Steven by simply registering the depedencies required by my filters in the services collection also:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKernel>(new StandardKernel());
services.AddSingleton<IControllerActivator, ControllerActivator>();
services.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>();
services.AddSingleton<IDatabaseGateway, DatabaseGateway>();
services.AddSingleton<IDatabaseContextCache, ContextDatabaseContextCache>();
// and so on
}
Since I do not have many dependencies in my filter it works out OK. This does mean that we have "duplicate" registrations that we need to be careful of depending on how the instances are used.
I guess another option may be to forego your DI container of choice and use only the built-in container.
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.