Search code examples
c#dependency-injectioninversion-of-controlasp.net-core

.net-core Dependency Injection


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.


Solution

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