.net-core Dependency Injection - c#

I have a Generic repository which I want to register for DI, it implements an interface IRepository.
Normally I would create an instance of it like this:
IRepository repo = new Repository<Order>();
However I am trying to get up to speed in .net 5 ahead of release and want to get this working with DI, I have resorted to the following :
services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>();
But this feels wrong, I don't want 50+ lines in there one for each of the classes in my model...
I cannot find anything online about this, I know its possible with other ioc containers.. but as this is a learning project I dont want to use another container, Im aiming to do it all with .net5s native container.

You should be able to register the open generic with
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));

After some back and forwards in the comments to other answers I have a working solution, It might not be the best way but it works. Ill update again if I find a better way to implement this.
The two issues I had were : Needed to register a generic interface, the issue here was a lapse in concentration on my part.. I had the syntax wrong for registering a generic type which of course is :
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
The second issue was that I have an assembly which contains 50+ different models which I wanted registered, The way that I addressed this was to write a method that I can pass a list of assemblies to along with the Namespace that I want to register and it iterates over any types that match the criteria and registers them in the DI container.
public void RegisterModels(IServiceCollection services, string[] Assemblies, string #NameSpace)
{
foreach (var a in Assemblies)
{
Assembly loadedAss = Assembly.Load(a);
var q = from t in loadedAss.GetTypes()
where t.IsClass && !t.Name.Contains("<") && t.Namespace.EndsWith(#NameSpace)
select t;
foreach (var t in q.ToList())
{
Type.GetType(t.Name);
services.AddTransient(Type.GetType(t.FullName), Type.GetType(t.FullName));
}
}
}
This is then called from the startup.cs method ConfigureServices :
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<TestContext>(options =>
options.UseSqlServer(#"Server=LOCALHOST\SQLEXPRESS;Database=Test;Trusted_Connection=True;"));
services.AddMvc();
RegisterModels(services, new string[] { "UI" }, "UI.Models");
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
}
There may be a better way to do this, there definitely is using different DI containers, if anyone has improvements to offer please let me know.

You could use a convention based registration library like Scrutor.
Scrutor is a small open source library that provides a fluent API to register services in your Microsoft.Extensions.DependencyInjection container based on conventions (Similar to Autofac's RegisterAssemblyTypes method, StructureMap's Scan method and Ninject's Conventions package).
This will allow you to do something like this:
services.Scan(scan => scan
.FromAssemblies(<<TYPE>>.GetTypeInfo().Assembly)
.AddClasses(classes => classes.Where(x => {
var allInterfaces = x.GetInterfaces();
return
allInterfaces.Any(y => y.GetTypeInfo().IsGenericType && y.GetTypeInfo().GetGenericTypeDefinition() == typeof(IRepository<>)));
}))
.AsSelf()
.WithTransientLifetime()
);

What you can do is create an extension method to encapsulate all those individual items that need to be registered.
That is the same technique Microsoft is using, for example you only put this in startup:
services.AddMvc();
but that is an extension method and behind the scenes you can bet it is registering a bunch of stuff it needs.
so you can create your own extension method like this:
using Microsoft.Extensions.DependencyInjection;
public static IServiceCollection AddMyFoo(this IServiceCollection services)
{
services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>();
//....
return services;
}
and by making the method return the IServiceCollection you make it fluent so you can do
services.AddMyFoo().AddSomeOtherFoo();
Updated based on comment
the other technique to reduce registrations is when your dependency doesn't itself have dependencies you can make the constructor have a default of null so you still have decoupling and could pass a different one in later but the DI won't throw an error and you can just instantiate what you need if it is not passed in.
public class MyFoo(IFooItemDependency myItem = null)
{
private IFooItemDependency internalItem;
public MyFoo(IFooItemDependency myItem = null)
{
internalItem = myItem ?? new FooItemItem();
}
}

I'm not 100% sure on what your question is I assume you don't want to have
services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>();
services.AddTransient<DAL.IRepository<Models.Person>, DAL.Repository<Models.Person>>();
services.AddTransient<DAL.IRepository<Models.Invoice>, DAL.Repository<Models.Invoice>>();
etc
I have done this before (with ninject)
Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
I imagine for Unity you can do something similar like
services.AddTransient<DAL.IRepository<>, typeof(Repository<>)();
And then to use it in a service
public OrderService(IRepository<Models.Order> orderRepository)
{
this.orderRepository = orderRepository;
}
EDIT
As pointed out by OP the correct syntax is:
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));

Related

Resolving dependency injected service as part of builder when specifying options

I'm using Microsoft.Extensions.DependencyInjection in my ASP.NET Core project (targeting .NET 7.0).
I have a service that, provided a sizable number of injected other services, yields a string value that I need in order to populate an options method during my DI registrations. Typically, I'd simply have DI inject the service into any of the controllers in which I'd pull the various values needed, but here the situation is a bit different.
Here, I am using one of those many helpful extension methods of IServiceCollection that themselves register their own various types, but it also exposes an action that allows me to specify some settings. I need to resolve a string value from my aforementioned service that I can use in the option specification method later on.
This extension method isn't something I have written, but part of a third-party library and it itself is quite extensive (e.g. not something I want to write/maintain my own version of). The extension itself looks like the following:
builder.Services.AddMySpecialService().SpecifyOptions(opt => {
opt.Id = "<Insert DI string value here>";
});
Ideally, I need to inject the service in such a way so as to pass that string value into my settings, but short of creating a local instance (not really feasible given all its own dependencies), I'm at a loss of how I'd go about this, if it's even possible at all.
Has anyone successfully done this and if so, how? Thanks!
Without knowing what that third-party library is, you can use dependencies when configuring your options in a standard way.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder
.Services
.AddSingleton<IStringProviderService, StringProviderService>()
.AddOptions<MyOptions>()
// For .Configure() method you can specify up to 5 dependencies.
.Configure<IStringProviderService>(
(myOptions, stringProviderService) =>
{
myOptions.Id = stringProviderService.GetString();
}
);
public class MyOptions
{
public required string Id { get; set; }
}
public interface IStringProviderService
{
string GetString();
}
public class StringProviderService : IStringProviderService
{
string IStringProviderService.GetString()
{
return Guid.NewGuid().ToString("N");
}
}

How to pass dependencies to a custom .NET Core ILoggerProvider

I am creating a custom .NET Core ILoggerProvider that requires some dependencies to be passed into its constructor.
I believe I am using a fairly common pattern to initialize my logging implementation; it looks something like this:
var services = new ServiceCollection();
// Register some services here
services.AddLogging(builder =>
{
builder.AddProvider(new DebugLoggerProvider());
});
var provider = services.BuildServiceProvider();
I want to add my new provider within the AddLogging block, in the same way that the DebugLoggerProvider is currently added.
My custom provider requires some other services to be passed into its constructor and since these are already registered with the ServiceCollection, I assume that I should be able to reference them. However, unlike methods such as AddSingleton, which have an overload that exposes the IServiceProvider, AddLogging doesn't seem to offer an equivalent.
Is there a simple way to achieve this, or am I attempting to do something that contradicts the way .NET Core logging was designed to be deployed?
UPDATE:
After experimenting with the suggestions proposed by #Nkosi, I can confirm that it is possible to get this to work by bypassing AddLogging and directly implementing what it does internally, as follows:
var services = new ServiceCollection();
// Register some services
services.AddSingleton<IMyService, MyService>();
// Initialize logging
services.AddOptions();
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddSingleton<ILoggerProvider>(p => new DebugLoggerProvider());
services.AddSingleton<ILoggerProvider>(p => new MyLoggerProvider("Constant value", p.GetService<IMyService>()));
var provider = services.BuildServiceProvider();
Now I am not sure if an extension already exists to do this but I see potential here.
First this is how AddProvider is defined in the source code repo.
public static ILoggingBuilder AddProvider(this ILoggingBuilder builder, ILoggerProvider provider) {
builder.Services.AddSingleton(provider);
return builder;
}
You could build up on that by making your own generic version
public static class MyLoggingBuilderExtensions {
public static ILoggingBuilder AddProvider<T>(this ILoggingBuilder builder)
where T: class, ILoggerProvider{
builder.Services.AddSingleton<ILoggerProvider, T>();
return builder;
}
}
which should allow the DI container to build up the object graph when resolved
services.AddLogging(builder =>
{
builder.AddProvider<CustomLoggerProvider>();
});
And there is room to extend this functionality, like adding your own overload that exposes the IServiceProvider and passing that on to the AddSingleton within the extension.
public static ILoggingBuilder AddProvider<T>(this ILoggingBuilder builder, Func<IServiceProvider, T> factory)
where T: class, ILoggerProvider {
builder.Services.AddSingleton<ILoggerProvider, T>(factory);
return builder;
}
And used
services.AddLogging(builder => {
builder.AddProvider<CustomLoggerProvider>(p => new CustomLoggerProvider("Constant value", p.GetService<IMyService>()));
});
Apologies for being a bit late to the party on this one, but I ran into exactly the same problem after having searched high and low. Inspired by the excellent entries in this page, I ended up with the solution below.
services.AddTransient<IMyLogRepository, LogRepository>();
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole()
.AddDbLoggerProvider(services.BuildServiceProvider().GetService<IMyLogRepository>());
});
services.AddSingleton(loggerFactory.CreateLogger("MyLogging"));
The key to this being:
services.BuildServiceProvider().GetService<IMyLogRepository>())
Which allowed me to link my database repository to the dbLogger object I created in a single extra line. In essence, it gives me the ability to pluck my DI database object an send it to the Logging service via standard ILoggerProvider and ILogger interfaces
I got a simple solution to work which is kinda lighter.
serviceCollection.AddLogging(logBuilder =>
{
logBuilder.AddConfiguration(theConfigRoot.GetSection("Logging"));
});
serviceCollection.AddSingleton<ILoggerProvider, MyLogProvider>();
However.... Instanciating the Provider keeps you from running in circular dependency problems--> The service you may want to inject soon want´s a logger himself^^

How to register Dependencies by Names in Unity

I'm using unity to implement Dependency Injection in my .NET Web Api app.
Here is the relevent part of my WebApiCongig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
AppDependancyRegistry.Register(container);
config.DependencyResolver = new UnityResolver(container);
}
}
And here is my AppDependancyRegistry class
public static class AppDependancyRegistry
{
public static void Register(UnityContainer container)
{
container.RegisterType(typeof(IBaseRepository<>), typeof(BaseRepository<>));
//container.RegisterTypes( AllClasses.FromLoadedAssemblies(), WithMappings.FromMatchingInterface, WithName.Default);
}
}
I have mapped the Generic Repositores but I couldnt get through with registering the Manager classes to its interfaces. I dont want to map every one of Manager classes Manaually.
I have commented the part I have done from all the research. I just want a confirmation, this is how I do it as I cant get my App running now without doing some more of stuff
My manager classes:interfaces looks like
DutyManager: IDutyManager
UserDetailManager:IUserDetailManager
etc. Thanks in Advance
You will need, at some point, to register each of them. However, if you don't want to manually do each and every one of them, what you could "basically" do is, by reflection, load the assembly, iterate over every interface, check how many classes implement that interface, if there is only one, register the interface to that class as an unnamed registration.
Why unnamed? Well, named registration are useless unless you actually use the name in the registration, or in the ResolvedParameter constructor, and since you're not "hand crafting" the registrations, you wouldn't refer to them most likely.
Don't forget though that in your case, since the interface and the classes are generics, you'll need to check the ParameterType too.
I found the solution to this qn. Using Unity we can directly Map all classes to respecive Interfaces by using
container.RegisterTypes( AllClasses.FromLoadedAssemblies(), WithMappings.FromMatchingInterface, WithName.Default);
Here, Unity maps by convention where they map like this
DutyManager: IDutyManager
UserDetailManager:IUserDetailManager

Why is an ASP.NET-Core app 'Configuration/AppSettings' POCO passed around as IOptions<T> instead of just T? [duplicate]

It seems to me that it's a bad idea to have a domain service require an instance of IOptions<T> to pass it configuration. Now I've got to pull additional (unnecessary?) dependencies into the library. I've seen lots of examples of injecting IOptions all over the web, but I fail to see the added benefit of it.
Why not just inject that actual POCO into the service?
services.AddTransient<IConnectionResolver>(x =>
{
var appSettings = x.GetService<IOptions<AppSettings>>();
return new ConnectionResolver(appSettings.Value);
});
Or even use this mechanism:
AppSettings appSettings = new AppSettings();
Configuration.GetSection("AppSettings").Bind(appSettings);
services.AddTransient<IConnectionResolver>(x =>
{
return new ConnectionResolver(appSettings.SomeValue);
});
Usage of the settings:
public class MyConnectionResolver
{
// Why this?
public MyConnectionResolver(IOptions<AppSettings> appSettings)
{
...
}
// Why not this?
public MyConnectionResolver(AppSettings appSettings)
{
...
}
// Or this
public MyConnectionResolver(IAppSettings appSettings)
{
...
}
}
Why the additional dependencies? What does IOptions buy me instead of the old school way of injecting stuff?
Technically nothing prevents you from registering your POCO classes with ASP.NET Core's Dependency Injection or create a wrapper class and return the IOption<T>.Value from it.
But you will lose the advanced features of the Options package, namely to get them updated automatically when the source changes as you can see in the source here.
As you can see in that code example, if you register your options via services.Configure<AppSettings>(Configuration.GetSection("AppSettings")); it will read and bind the settings from appsettings.json into the model and additionally track it for changes. When appsettings.json is edited, and will rebind the model with the new values as seen here.
Of course you need to decide for yourself, if you want to leak a bit of infrastructure into your domain or pass on the extra features offered by the Microsoft.Extensions.Options package. It's a pretty small package which is not tied to ASP.NET Core, so it can be used independent of it.
The Microsoft.Extensions.Options package is small enough that it only contains abstractions and the concrete services.Configure overload which for IConfiguration (which is closer tied to how the configuration is obtained, command line, json, environment, azure key vault, etc.) is a separate package.
So all in all, its dependencies on "infrastructure" is pretty limited.
In order to avoid constructors pollution of IOptions<>:
With this two simple lines in startup.cs inside ConfigureServices you can inject the IOptions value like:
public void ConfigureServices(IServiceCollection services)
{
//...
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddScoped(cfg => cfg.GetService<IOptions<AppSettings>>().Value);
}
And then use with:
public MyService(AppSettings appSettings)
{
...
}
credit
While using IOption is the official way of doing things, I just can't seem to move past the fact that our external libraries shouldn't need to know anything about the DI container or the way it is implemented. IOption seems to violate this concept since we are now telling our class library something about the way the DI container will be injecting settings - we should just be injecting a POCO or interface defined by that class.
This annoyed me badly enough that I've written a utility to inject a POCO into my class library populated with values from an appSettings.json section. Add the following class to your application project:
public static class ConfigurationHelper
{
public static T GetObjectFromConfigSection<T>(
this IConfigurationRoot configurationRoot,
string configSection) where T : new()
{
var result = new T();
foreach (var propInfo in typeof(T).GetProperties())
{
var propertyType = propInfo.PropertyType;
if (propInfo?.CanWrite ?? false)
{
var value = Convert.ChangeType(configurationRoot.GetValue<string>($"{configSection}:{propInfo.Name}"), propInfo.PropertyType);
propInfo.SetValue(result, value, null);
}
}
return result;
}
}
There's probably some enhancements that could be made, but it worked well when I tested it with simple string and integer values. Here's an example of where I used this in the application project's Startup.cs -> ConfigureServices method for a settings class named DataStoreConfiguration and an appSettings.json section by the same name:
services.AddSingleton<DataStoreConfiguration>((_) =>
Configuration.GetObjectFromConfigSection<DataStoreConfiguration>("DataStoreConfiguration"));
The appSettings.json config looked something like the following:
{
"DataStoreConfiguration": {
"ConnectionString": "Server=Server-goes-here;Database=My-database-name;Trusted_Connection=True;MultipleActiveResultSets=true",
"MeaningOfLifeInt" : "42"
},
"AnotherSection" : {
"Prop1" : "etc."
}
}
The DataStoreConfiguration class was defined in my library project and looked like the following:
namespace MyLibrary.DataAccessors
{
public class DataStoreConfiguration
{
public string ConnectionString { get; set; }
public int MeaningOfLifeInt { get; set; }
}
}
With this application and libraries configuration, I was able to inject a concrete instance of DataStoreConfiguration directly into my library using constructor injection without the IOption wrapper:
using System.Data.SqlClient;
namespace MyLibrary.DataAccessors
{
public class DatabaseConnectionFactory : IDatabaseConnectionFactory
{
private readonly DataStoreConfiguration dataStoreConfiguration;
public DatabaseConnectionFactory(
DataStoreConfiguration dataStoreConfiguration)
{
// Here we inject a concrete instance of DataStoreConfiguration
// without the `IOption` wrapper.
this.dataStoreConfiguration = dataStoreConfiguration;
}
public SqlConnection NewConnection()
{
return new SqlConnection(dataStoreConfiguration.ConnectionString);
}
}
}
Decoupling is an important consideration for DI, so I'm not sure why Microsoft have funnelled users into coupling their class libraries to an external dependency like IOptions, no matter how trivial it seems or what benefits it supposedly provides. I would also suggest that some of the benefits of IOptions seem like over-engineering. For example, it allows me to dynamically change configuration and have the changes tracked - I've used three other DI containers which included this feature and I've never used it once... Meanwhile, I can virtually guarantee you that teams will want to inject POCO classes or interfaces into libraries for their settings to replace ConfigurationManager, and seasoned developers will not be happy about an extraneous wrapper interface. I hope a utility similar to what I have described here is included in future versions of ASP.NET Core OR that someone provides me with a convincing argument for why I'm wrong.
I can't stand the IOptions recommendation either. It's a crappy design to force this on developers. IOptions should be clearly documented as optional, oh the irony.
This is what I do for my configuraition values
var mySettings = new MySettings();
Configuration.GetSection("Key").Bind(mySettings);
services.AddTransient(p => new MyService(mySettings));
You retain strong typing and don't need need to use IOptions in your services/libraries.
You can do something like this:
services.AddTransient(
o => ConfigurationBinder.Get<AppSettings>(Configuration.GetSection("AppSettings")
);
Using Net.Core v.2.2, it's worked for me.
Or then, use IOption<T>.Value
It would look something like this
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
I would recommend avoiding it wherever possible. I used to really like IOptions back when I was working primarily with core but as soon as you're in a hybrid framework scenario it's enough to drive you spare.
I found a similar issue with ILogger - Code that should work across frameworks won't because I just can't get it to bind properly as the code is too dependent on the DI framework.

Find out which module registered type

I'm debugging autofac issues in an application with quite a lot of modules. Is there a way to find out what module registered some registration? I'm looking at the ComponentRegistry of the container, but I can't find any information there.
EDIT:
A clarification. I have a lot of modules in my solution:
public class MyModule : Autofac.Module {
public override void Load(ContainerBuilder builder) {
builder.RegisterType<MyConcreteType>().As<IMyInterface>();
}
}
I then register in my container by scanning my assemblies:
var builder = new ContainerBuilder();
builder.RegisterAssemblyModules(/* Get all assemblies in base dir */);
var container = builder.Build();
Now, I have a lot of registrations. My question is "What Module registered MyConcreteType?". I would like to do something like container.ComponentRegistry.Registrations.Select(reg => new { reg.Service, reg.RegisteredBy }), where RegisteredBy is some magic property.
Ok, I am not a 100% sure what you mean, but I'll give it a go:
For debugging, the implemented type is displayed in the Registrations collection of the ComponentRegistry:
i.e. at index 0, the implementation type is CustomDataElement.
As what service type the implementation type is registered can be seen in a ComponentRegistrations Services collection.
Does that help? Can you give an example otherwise?
EDIT:
Got it... Try this:
var l = _container.ComponentRegistry.Registrations
.SelectMany(r => r.Services.OfType<IServiceWithType>(),
(r, s) => new { r.Activator.LimitType, s.ServiceType });
Not sure whether it works 100% as expected, but it should get you there...
EDIT 2:
I misunderstood the question, didn't distinguish between the registered service and the registering module. I don't think it is possible out of the box, as it would either require passing the module as an argument or Autofac to reflect the caller upon registration. Both is not the case, as far as I can tell. I can't find any built in features in Autofac.
If you can modify the modules, one approach would be to register the types with metadata. You probably know the approach, it is something like
public class MyModule: Autofac.Module
{
public override void Load(ContainerBuilder builder)
{
builder.RegisterType<MyConcreteType>()
.As<IMyInterface>()
.WithMetadata<IRegisteredByModuleMetadata>(m =>
m.For(am => am.RegisteringModuleType, GetType());;
}
}
with the metadata interface
public interface IRegisteredByModuleMetadata
{
Type RegisteringModuleType { get; set; }
}
Then in the container, resolving with metadata will allow to access the module types via the registrations Metadata property. Depending on your requirements you could simplify the type registration by providing a protected type registration method on a custom module base class which automatically appends the metadata, so you don't have to repeat yourself here.
If modifying every module in your solution is an option, that's probably not a bad way to go. Sorry I can't give any out-of-the-box solution. There might be one, I am missing, but that's all I can do for you here. Hope it helps nonetheless.

Categories

Resources