Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to register dependency injection with generic types? (.net core)

I have an asp.net core web app with multiple parameters in appSettings.json file.

I didnt' want to have services having IOptions<MyObject> in the constructor.

I wanted MyObject in the constructor. So I found the following article: https://weblog.west-wind.com/posts/2017/dec/12/easy-configuration-binding-in-aspnet-core-revisited which is very interesting.

But I want to go further. I would like to create an extension method to generate the injection.

Here is what I would like to do:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Common.WebTools.Extensions
{
    public static class IServiceCollectionExtensions
    {
        public static IServiceCollection AddSingletonConfigurationObject<T>(this IServiceCollection services, 
            IConfiguration configuration,
            string appSettingsKey) where T:new()
        {   
            var obj2 = new T();
            configuration.Bind(appSettingsKey, obj);
            services.AddSingleton(obj2); //compilation failed
            return services;
        }
    }
}

And then in my ConfigureServices method I can call

services.AddSingletonConfigurationObject<Common.Tools.Configuration.GoogleAnalyticsConfiguration>(Configuration, "GoogleAnalytics");

But I Have a compliation error on this line:

services.AddSingleton(obj2); 

Does somebody know how could I correct the error?

like image 724
Rémy Avatar asked May 23 '19 09:05

Rémy


3 Answers

You can use services.AddScoped to use only 1 instance in the scope request. So in general improvement compare to AddTransient

services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));

So my interface and class will look like this

public interface IGenericRepository<T> where T : class
public class GenericRepository<T> : IGenericRepository<T> where T : class
like image 86
Tony Ngo Avatar answered Sep 30 '22 14:09

Tony Ngo


I was able to use this style to encapsulate (as an extension method)

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace MyProject.DependencyInjection
{
    public static class MyEncapsulatedIocRegistration
    {
        public static IServiceCollection AddTypeT<T>(this IServiceCollection services) where T : class
        {
            services.AddSingleton<IMyThingInterface<T>, MyThingConcrete<T>>();

            return services;
        }
    }
}
like image 41
granadaCoder Avatar answered Sep 30 '22 13:09

granadaCoder


As stated in the comments you should set the generic constraint to where T: class in order to satisfy the constraint of the AddSingleton call.

Reference AddSingleton(IServiceCollection, TService)

Additionally you can bind the object graph using ConfigurationBinder.Get<T>

Reference Configuration in ASP.NET Core : Bind to an object graph

ConfigurationBinder.Get<T> binds and returns the specified type. Get<T> is more convenient than using Bind.

like in the following example

public static class IServiceCollectionExtensions {
    public static IServiceCollection AddSingletonConfigurationObject<TService>(
        this IServiceCollection services, 
        IConfiguration configuration,
        string appSettingsKey) where TService: class
    {   

        var setting = configuration.GetSection(appSettingsKey).Get<TService>();
        services.AddSingleton(setting);
        return services;
    }
}
like image 39
Nkosi Avatar answered Sep 30 '22 14:09

Nkosi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!