Binding Generic Repository and Specific Repository with Ninject 2.2 - repository

I have a IRepository that I have implemented in Repository and I extended Repository for specific type as UsersRepository I need to bind all types using the generic binding for Ninject however when requesting instance for IRepository I need to get UsersRepository instead of Repository.
Bind<IDbContext>().To<SMSDataContext>()
.WithConstructorArgument("connectionStringName", "dbcsname");
Here I am binding the generic repository:
Bind(typeof(IRepository<>)).To(typeof(Repository<>))
.WithConstructorArgument("dbContext",new SMSDataContext("dbcsname"));
Here I am trying to bind a specific instance:
Bind<IRepository<Setting>>().ToConstant(settingsRepository);
Tried different approaches with ".ToConstant" and with only ".To" also tried to bind to concrete implementation like follows:
UsersRepository usersRepository = new UsersRepository(new SMSDataContext("SMSDB"));
Bind<IRepository<Setting>>().To<SettingsRepository>().WithConstructorArgument("dbContext", new SMSDataContext("dbscname")); ;
Please advise.

Currently it is only possible using some cheat because open generic bindings have the same priority as closed generic bindings. But you can increase the priority of a binding by adding a condition.
Bind<IRepository<Setting>>().ToConstant(settingsRepository).When(ctx => true);

Related

How do I auto-register/resolve services by their interface?

I'm developing a MVC .NET Core 3/Angular/Entity Framework application. My application will likely have a lot of repositories in it. To support this I would like to resolve the service (repository) by its default interface (i.e. I request IRepository and the DI resolver gives me Repository). I know I can manually wire up the dependencies, but all of my DI frameworks in the past have had a means of auto-registering/resolving based on patterns or the like.
For example, with Castle Winsdor I could wire it up like this:
container.Register(Classes
.FromAssemblyNamed("MyLibary.Repository")
.InNamespace("MyLibrary.Repository")
.WithService.DefaultInterfaces()
.LifestyleTransient()
);
This would register all classes in the MyLibrary.Repository namespace to be resolved by their default interfaces they implement. How can this be done in .NET Core 3? If this isn't built-in, I'm assuming I will have to use reflection to query all the classes in the assembly, iterate through each class and register it by its interface it implements.
I would recommend AutoRegisterDI lib to not reinvent a bicycle. It's fast, simple and based on Microsoft Dependency Injection. This benchmark will show you the speed difference.
And this is the article about how to use it
Install this package:
NetCore.AutoRegisterDi
Add this code to your program.cs:
builder.Services.RegisterAssemblyPublicNonGenericClasses()
.Where(c => c.Name.EndsWith("Service"))
.AsPublicImplementedInterfaces(ServiceLifetime.Scoped); // default is Transient
If you have a Singleton service , add [RegisterAsSingleton] on top of your service class.
If you want to ignore injection of an particular interface add this line after .Where() :
.IgnoreThisInterface<IMyInterface>()
you can do this with reflection in c#.first create an extension method like this :
public static void AddScopedServices(this IServiceCollection serviceCollection)
{
}
and use it in startup.cs ,ConfigureServices method : services.AddScopedServices();
now to implement this method like this:
var allProviderTypes = System.Reflection.Assembly.GetAssembly(typeof(ICartRepository))
.GetTypes().Where(t => t.Namespace != null).ToList();
foreach (var intfc in allProviderTypes.Where(t => t.IsInterface))
{
var impl = allProviderTypes.FirstOrDefault(c => c.IsClass && intfc.Name.Substring(1) == c.Name);
if (impl != null) serviceCollection.AddScoped(intfc, impl);
}
you just need to put all your interfaces in a namespace and introduce one of them in this method ,in my case I used ICartRepository ,so it takes all interfaces and search for classes which inherit from that interface.
one point you need to consider is that class names must be like interfacenames without 'I' in the beginning ,like 'CartRepository'
I recently got tired of writing the same old
services.AddTransient<IInterface,IImplementation>
so I created a simple library to help me auto-register services.
You can check it out here.
Register the library in Startup.cs
There are 3 interface -> ITransient, IScoped, ISingleton generic and non-generic versions.
Let's say you want to register service "TestService" as transient.
TestService: ITransient<ITestService>, ITestService
Inherit ITransient interface and its done.
For more detailed information please refer to the Readme section.
Currently it lacks registering services with implementation factory, but it's something I'm willing to do in the near future.

Ninject Conditional injection problems

I have the following bindings declared
Bind<IDataSource>().To<DataSourceOne>();
Bind<ISettings>().To<DataSourceSettings>
.WhenInjectedInto<DataSourceOne>();
Bind<ISettings>().To<Settings>();
now I call
Kernel.Get<IDataSourc>();
Ninject correctly injects a DataSourceSettings, but I need to pass a constructor argument to Settings and DataSourceSettings based on data from a config file. so I've changed the IDataSouce binding as follows
Kernel.Bind<IDataSource>().To<DataSourceOne>()
.WithConstructorArgument("settings", Kernel.Get<ISettings>(
new ConstructorArgument("data", objectContainingConfigFileData)
)
);
in that case Ninject injects Settings class instead of DataSourceSettings class. I assume the problem is that the ISettings is getting resolved before it is injected into the DataSourceSettings class so Ninject does not use the binding I intended it to. Is there a way to get around this. I haven't found anything yet.
It should work if you define the constructor argument for the ISettings binding and not for the DataSource binding. Assuming you already know the object with the config file data in the module. Otherwise maybe a factory would be more appropriate.
kernel.Bind<IDataSource>().To<DataSourceOne>();
kernel.Bind<ISettings>().To<DataSourceSettings>()
.WhenInjectedInto<DataSourceOne>()
.WithConstructorArgument("data", objectContainingConfigFileData);
kernel.Bind<ISettings>().To<Settings>();

Named binding - MVC3

I'm trying to register to implementations of same interface using named instances
kernel.Bind<IRepository>().To<CachedRepository>().InSingletonScope();
kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope().Named("db");
the idea, is that if I not specify the name then the CachedRepository gets created, if I need a DB oriented one then I'd use the Named attribute, but this miserable fails when a simple object would get created
public class TripManagerController : Controller
{
[Inject]
public IRepository Repository { get; set; } // default Cached repo must be created
public TripManagerController()
{
ViewBag.LogedEmail = "test#test.com";
}
}
the error is
Error activating IRepository More than one matching bindings are
available. Activation path: 2) Injection of dependency IRepository
into parameter repository of constructor of type TripManagerController
1) Request for TripManagerController
Suggestions: 1) Ensure that you have defined a binding for
IRepository only once.
Is there a way to achieve what I want without creating a new interface for BD oriented repositories?
Thx
The [Named] attribute as shown in the wiki should work.
BTW stay away from anything other than ctor injection!
It would seem you cannot do what you're trying, I've just come across the same issue and as well as finding your question I also found this one where the author of Ninject Remo Gloor replied.
https://stackoverflow.com/a/4051391/495964
While Remo didn't explicitly say it couldn't be done his answer was to name both bindings (or use custom attribute binding, amounting the same thing).

Service Resolution/Location and Parameters

How would you pass parameters to a resolver to create an object?
I have a UoW object which I want to pass into a data service objects, I want to be able to ensure that the data service objects created in a particular sequence are created using the one UoW object
for example
using (var context = Resolver.GetService<IUoW>())
{
var dataService1 = Resolver.GetService<IDataService1>();
var dataService2 = Resolver.GetService<IDataService2>();
// do some stuff
context.Commit();
}
Option 1, pass IUoW into the Resolver.GetService call
- there is no knowledge of the constructors for IDataServiceX implementations
Option 2, add a property to IDataServiceX for IUoW
- not setting it would be easily done, how would a programmer know this property was required to be set
I've previously implemented a Unit of Work (UoW) and Repository pattern over Entity Framework.
In reality the UoW abstracted the EF context, and the repositories abstracted the entity sets.
In my implementation of the Repositories were properties of the UoW, meaning it was not the IoC container that managed the life-cycle of the repositories, that was the responsibility of the UoW.
In your situation the repositories are named services, but maybe the same applies. Can the IUoW interface have two (or more) properties for all the services that exist within the specific unit of work?

Getting real instance from proxy under Unity Interception with NHibernate

I'm using Unity to resolve types dynamically for a pluggable architecture. I'm also using interception to apply business rule validation via AOP (using ValidationAspects). Finally, I'm using NHibernate as an ORM to persist domain objects.
In order for AOP to work, we use the VirtualMethodInterceptor, as interface interception doesn't work with NHibernate. I have a facade over ISession that handles casting between interface and real types for repository operations.
To make sure that all objects in the graph fetched via NHibernate are properly proxied for AOP, I made an NH IInterceptor implementation and overrode the Instantiate() method, so I could supply NH with created objects rather than have it call new(). I then use Container.Resolve() to get back proxied objects with the validation injected, and give this back to NH to populate. This works OK.
The problem comes when the session flush occurs. NHibernate gets upset because the objects it sees in the graph are of the proxy type rather than the real type. The way we're mapping (all via property, all virtual) NH should be able to get all the values it needs via the proxy, if I could override the type-checking.
What I need to know is: given a transparently proxied object created by Unity with Interception enabled, is there a) any way to obtain a direct reference to the 'real' instance it's proxying, or b) to override NH and tell it to treat objects of a proxy type as if it were of a known mapped type, dynamically at runtime?
We use interception for caching. So in our class, that implements ICallHandler we have code like this:
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
//...
var nextHandler = getNext();
var realReturn = nextHandler(input, getNext);
var cacheRefreshingItemParameters = new CacheRefreshingItemParameters
{
InterfaceMethod = input.MethodBase,
InterfaceType = input.MethodBase.DeclaringType,
TargetType = input.Target.GetType() //remember original type
};
_cacheProvider.Add(cacheKey, realReturn.ReturnValue, cacheRefreshingItemParameters);
//...
return (cachedReturn);
}
We put cacheRefreshingItemParameters in cache UpdateCallback and then resolve original service:
var service = _unityContainer.Resolve(parameters.TargetType);