Ninject: Get the instance injected to a parent object - c#

I have a crazy dependency injection case which I'll explain, but first let me show you some code:
class Foo : IFoo
{
Foo(
IBar bar,
IFooContext context,
IService service)
{
...
}
}
class Service : IService
{
Service(
IBar bar)
{
...
}
}
I'm resolving dependencies using Ninject. All of the above are InTransientScope. IBar is provided by a factory method, which uses one of the IFooContext properties for creation. What I want to achieve is to have Service injected into Foo with the same IBar instance that was injected into Foo.
I have no idea how to achieve this with Ninject. Is it even possible? If not, I'm thinking about exposing IBar property in IService and setting it in Foo constructor, but honestly I don't like this idea.
I simplified my case for sake of...simplicity, but in reality Foo is Rebus message handler, IFooContext is a message context, IBar is a logger. I want to format logger messages so that they include ID from a Rebus message being handled. And I want both Foo's and Service's log events to have that ID.

This can be solved with Ninject.Extensions.NamedScope
kernel.Bind<IFoo>().To<Foo>().DefinesNamedScope("FooScope");
kernel.Bind<IBar>().To<Bar>().InNamedScope("FooScope");

Thanks to Nkosi who pointed me towards right direction, I've managed to get what I wanted:
Bind<IFoo>()
.To<Foo>
.InScope(ctx => FooContext.Current);
Bind<IBar>()
.ToMethod(ctx =>
{
var scope = ctx.GetScope() as IFooContext;
// Some logic to create Bar by IFooContext...
});
Bind<IService>()
.To<Service>
.InScope(ctx => FooContext.Current);
As I said, in reality Foo is a Rebus message handler. For my example that means, that for every Foo new IFooContext is created and also I have access to current one.
As for Jan Muncinsky's answer - I didn't test it, but from what I read from Ninject's documentation, it seems that it's also a valid solution for this problem.
Thank you.

Related

Passing constructor parameter throught multiple objects while resolving in AutoFac

i have difficulties getting my registration in AutoFac done.
Let`s say i have the following classes
class Foo : IFoo
{
public Foo(string test, IBar bar) {}
}
class Bar : IBar
{
public Bar(bool someFlag) {}
}
The issue I'm having now is that i don't know how to set this boolean 'someFlag' while resolving.
I am only able to create these objects and fill in the flag while resolving, not while registering the classes.
Note: This is just an easy example to show the problem. In my case there are half a dozen classes in between Foo and Bar.
Can anyone please help me?
I know how to fill a parameter directly like the string 'test'. But I don`t understand how i pass the boolean through Foo to Bar.

How to dipose helper disposables using DI in ASP.NET core?

For regular case how to manage disposables such post as How to correctly and safely dispose of singletons instances registered in the container when an ASP.NET Core app shuts down explains how to do it.
But I have a slightly different case -- I don't have single instance of some worker IFoo like here:
interface IFoo : IDisposable // not my case
which you know how to dispose, just call Dispose on an instance of IFoo.
No, my IFoo is not IDisposable:
interface IFoo // my case
instead of single instance, I have a pair of instances on creation -- (IFoo,IDisposable). When I have to do real work, I use the first item, because there is all logic there, when I am done, I call Dispose on the second item.
You could say it is decoupling put at extreme.
And when I am at ASP.NET Core I have problem with DI -- I have a pair like above, I can register IFoo with for example services.AddScoped, but how to tell services that there is distinct/separate IDisposable at hand which should be disposed when the work is done and the scope is gone?
You could create a wrapper around (IFoo, IDisposable), let's say:
public class DisposableFoo : IDisposable
{
// Assume FooConcrete implements IFoo and IDisposable
private readonly FooConcrete _foo;
public DisposableFoo(FooConcrete fooConcrete) { _foo = fooConcrete; }
public IFoo Instance => _foo;
public void Dispose() => _foo.Dispose();
}
And then in Startup.cs you could do the following to keep your abstractions clean:
services.AddTransient<FooConcrete>();
services.AddScoped<DisposableFoo>();
services.AddScoped<IFoo>(ctx => ctx.Resolve<DisposableFoo>.Instance);
In this case the underlying FooConrecte will be disposed at the end of scope lifetime properly.

Creating a Singleton with Multiple Service Registrations Using DryIoc

The Problem
I'm trying to register a singleton using DryIoc, but container is returning multiple instances of my singleton class. The singleton class is registered as the implementation type for multiple different service interfaces. When any of the aforementioned service interfaces is requested from DryIoc, I expect to get the same instance of my singleton class back, but that's not happening and I don't know why.
An Example
Here's a basic example of what I'm trying to do. In this example, I have a class, Foo that I would like to use as the singleton implementation for interfaces IFoo and IBar. In other words, when either IFoo or IBar are resolved from the container, I'd like for the same instance of Foo to be returned.
The Service Interfaces
interface IFoo
{
}
interface IBar
{
}
The Singleton (Implementation) Class
class Foo : IFoo, IBar
{
}
The Test
Container container = new Container();
container.Register<IFoo, Foo>(Reuse.Singleton);
container.Register<IBar, Foo>(Reuse.Singleton);
object foo = container.Resolve<IFoo>();
object bar = container.Resolve<IBar>();
Assert.AreSame(foo, bar); // Why does this fail?
Considered Solutions
I've considered using DryIoc's RegisterInstance method but that would require the class to be manually created and I'm trying to avoid that because, unlike the simplified example above, the real-world class has dependencies of its own.
The Register method adds separate / independent registrations to the container. You need to specifically say to use the same registration for multiple services.
Option 1: RegisterMany
// registers with Foo interfaces and itself. Remove #nonPublicServiceTypes to restrict for public types
container.RegisterMany<Foo>(Reuse.Singleton, nonPublicServiceTypes: true);
Assert.AreSame(container.Resolve<IFoo>(), container.Resolve<IBar>());
Option 2: RegisterMapping
container.Register<IFoo, Foo>(Reuse.Singleton);
container.RegisterMapping<IBar, IFoo>(); // maps to the IBar registration
Assert.AreSame(container.Resolve<IFoo>(), container.Resolve<IBar>());
Other:
Manually delegate the resolution as in #Fyodor answer.
DryIoc's concept of "reuse" applies to services, not implementations. Your registrations are for two different services (IFoo and IBar), so they get different reuses, and the fact that they share implementation (Foo) does not apply here.
To achieve your goal, you can register the services via made that redirects to the implementation:
container.Register<Foo>( Reuse.Singleton );
container.Register<IFoo, Foo>( made: Made.Of( () => ReturnThis( Arg.Of<Foo>() ) ), reuse: Reuse.Singleton );
container.Register<IBar, Foo>( made: Made.Of( () => ReturnThis( Arg.Of<Foo>() ) ), reuse: Reuse.Singleton );
// Where ReturnThis is define thusly:
static T ReturnThis<T>( T t ) => t;
(you need the ReturnThis call, because naked Made.Of( () => Arg.Of<Foo>() ) doesn't work; Made always expects a method call)

Ninject context extraction from factory parameter

I have an object that defines a scope:
Bind<ISomething>().To<Something>().DefinesNamedScope(SomethingScope);
I also have a auto-generated factory that creates IAnotherThing:
public interface IAnotherThingFactory
{
IAnotherThing CreateAnotherThing(ISomething x);
}
And bind it:
Bind<IAnotherThingFactory>().ToFactory();
I would like to create the IAnotherThing in the context of ISomething, so I can e.g. have a ISharedPrivateDependency that both get the same instance of. However, Something must not be aware of IAnotherThing. That means that, ideally, there should be a way to extract the context from the ISomething parameter, and use it to set the context for IAnotherThing.
What binding do I have to define or code to write in order to get this behavior?
I do not want to expose the kernel directly, only the factory.
Edit after comments:
Putting the Factory for AnotherThing into ISomething solves the context problem, but exposes ISomething to IAnotherThing. A requirement for an answer is stated above: ISomething must not be aware of IAnotherThing. So that's a no-go.
The same goes for exposing Ninject-internals in the ISomething interface.
Have a look at ninject contextpreservation extension: https://github.com/ninject/ninject.extensions.contextpreservation/wiki
ISomething will need to provide the IAnotherThingFactory (p.Ex. as property) in order for the objects created by IAnotherThingFactory to use the same context as ISomething.
Hint: The scope of the factory can be relevant. If you define the factory .InSingletonScope it won't work, or rather, all objects created by the factory will have the same context as the object that first requested the factory.
In case you need it even more generic, what you can do is inject an IResolutionRoot into ISomething and provide it as property. Then someone can do ISomething.ResolutionRoot.GetContextPresreving<IFoo>(); or even
ISomething.ResolutionRoot.GetContextPresreving<IAnotherThingFactory>().CreateAnotherThing();
If you don't want to reference ninject, what you can do is hide IResolutionRoot in a wrapper IFactory, like:
internal class Factory : IFactory {
private readonly IResolutionRoot resolutionRoot;
public Factory(IResolutionRoot resolutionRoot) {
this.resolutionRoot = resolutionRoot;
}
T Create<T>() {
return this.resolutionRoot.GetContextPreserving<T>();
}
}
However i suggest that this can probably be solved by improving the design (in a larger scope). For us at least it was never necessary to do such a thing - even though we have the requirement of late creating objects in the same context as another object, while the creation is triggered from a different context.

Instantiate dependency injected class

Is there any way to get an instance of a class from the dependency injector?
For example, I register my types and then have a class like this:
public class A {
private readonly Iinterface _object;
public A (Iinterface object) {
_object = object;
}
//do stuff using _object
}
public class B {
public void DoSomething() {
var instanceOfA = DIContainer.GetInstance(typeof(A));
//do stuff with instanceOfA which has been constructed using DI
}
}
Currently, I would have to register class A to be injected, and then have that injected into class Bs constructor. I'm just curious if there is a way to get an instance of A created for me from Unity with the depedencies injected automatically so I don't have to register it or pass through objects.
Please keep in mind that is not an actual use case I am considering, but I want to learn more about my options with dependency injection and Unity specifically.
In Unity, there are a few ways to get dependencies.
Constructor Injection
Property Injection
Manually resolve
I believe what you're asking for is #3.
In your example, you can get a class A instance (granted you've already registered Iinterface) by:
unityContainer.Resolve<A>();
A simplified way to think of Unity is it's a really smart Factory that can give you an object in the Constructor, Property, or by calling a Method. Ask for any object type or interface type, and it will give you one. The caveat is you need to give it clues on how to handle ambiguities. That's basically where the registrations come into play.
In your example above, the only ambiguity is Iinterface so that's the only class that you will need to register. Resolving class A or B doesn't need any registrations because it's already a concrete type.
It depends on the relationship between A and B:
If B depends on A, then it would make sense for A to inject the dependency into B (or perhaps to inject A itself).
I would not advise allowing B to "find" the dependency by looking at A. At best you have a strong dependency between B and A, at worst you end up with a "Service Locator" anti-pattern.
Unless you have a critical need to keep the dependency the same between A and B I would not couple them any more than you have to.

Categories