2

I'm trying to implement the Dependency Injection from Core on my software in order to replace Ninject and update everything to our new technology.

Btw, I'm facing a problem on some interfaces that are generic. For such cases I'm getting directly an Exception that the injector could not create an instance of my class.

I inserted above a small snippet of a sample case that puts me on fire.

services.AddTransient(typeof(IRepository), typeof(MyRepository<,>))

Is that way correct? How can I do that?

Class implementation:

public class MyRepository<TEntity, TContext> : IRepositoryBase
    where TEntity : class 
    where TContext : IDbContext, new()
{
...
}

Interface:

public interface IRepository : IDisposable
{
...
}

Thanks!

8
  • Here is how I am doing the DependencyInjection with my repositories in Core: services.AddScoped<IWorldRepository, WorldRepository>(); Commented Aug 2, 2016 at 14:56
  • There is a distinct difference between yours (lucas) and the OPs. Note the open generics. You still use a DI framework in core, core just exposes some interfaces to easily hook it in. Commented Aug 2, 2016 at 14:57
  • I would still continue to remove Ninject though and add something like Autofac, StructureMap or LightInject. But, the documentation states there is a very limited set of functionality and I don't think that extends to open generics. I like structuremap due to it's convention based assembly scanning Commented Aug 2, 2016 at 14:59
  • I would think it would just be services.AddTransient<IRepository, MyRepository<T1, T2>>(); no? Commented Aug 2, 2016 at 15:00
  • 1
    I think the OP wants to be able to specify the open generic not bind to that closed generic Commented Aug 2, 2016 at 15:01

3 Answers 3

5

This doesn't really make sense. You will be asking the container for IRepository, so how would it know what the generic type arguments should be such that it can give you a MyRepository<,>?

So when asked to return an object like this:

public class MyService
{
    private IRepository<Something, SomethingElse> _repo;

    public MyService(IRepository<Something, SomethingElse> repo)
    {
        // Container will actually give us MyRepository<Something, SomethingElse>
        _repo = repo;
    }
}

I would expect either:

services.AddTransient(typeof(IRepository<,>), typeof(MyRepository<,>));

or, if your repository doesn't need to be generic (I don't understand why it'd need two generic arguments as it is), then I'd expect this:

services.AddTransient(typeof(IRepository), typeof(MyRepository));

However, since there's no generics involved here, you could use the alternative form to achieve the same thing with less typing:

services.AddTransient<IRepository, MyRepository>();

So really the answer is to solve your interface/class design. Showing more of the implementation of them would help.

UPDATE

Your implementation needs to be:

Class implementation:

public class MyRepository<TEntity, TContext> : IRepository<TEntity, TContext>
    where TEntity : class 
    where TContext : IDbContext, new()
{
...
}

Interface:

public interface IRepository<TEntity, TContext> : IDisposable
    where TEntity : class 
    where TContext : IDbContext, new()
{
...
}
Sign up to request clarification or add additional context in comments.

4 Comments

I agree with you, but only in parts, my implementation really accepts that and make sense. I've updated my question with more pieces of code.
Sorry that hasn't helped. What you have shown will not work in C#. You class has no relation to the interface, so no container will be able to do this for you. Also, not that typically abstract classes have the "base" suffix convention, not interfaces (which have the "I" prefix instead).
That really works and so work on Ninject and Autofac, problem is only with Microsoft's DI that don't accept Generics
It can't work. There is something missing from the picture. If a component requires IRepository, if the container is configured to return MyRepository<TEntity, TContext>, how does it actually know what to use for TEntity and TContext?
0

I ended up using Autofac and without any changes on my structure everything started working again.

Will wait a little more for documentation and more people using, so I can change my implementation to use MS DI.

Comments

0

To register all repositories use this:

        var allRepositories = GetType().GetTypeInfo()
        .Assembly.GetTypes().Where(p =>
            p.GetTypeInfo().IsClass &&
            !p.GetTypeInfo().IsAbstract &&
            typeof(IRepository).IsAssignableFrom(p));
        foreach (var repo in allRepositories)
        {
            var allInterfaces = repo .GetInterfaces();
            var mainInterfaces = allInterfaces.Except
                    (allInterfaces.SelectMany(t => t.GetInterfaces()));
            foreach (var itype in mainInterfaces)
            {
                services.AddScoped(itype, repo);
            }
        }

Then resolve it:

public YourClass(IRepository<T> repo)
{
    //...
}

4 Comments

My code was almost exactly this, the problem is not with all the registrations but only when it's a generic interface, that throws an exception on my face. Anyway, thanks for the help
I have a similar scenerio. I have IValidator<T>(inherit from IValidator) generic interface and implementations of this interface. It works for me.
It seems i misunderstand you, sorry.
not working.. getting problems.. for example with IContextManager<T> and ContextManager<T>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.