I know we can create singleton classes using the factory in Dart. But i happen to recall reading somewhere, classes registered using type(MyController) or type(MyServiceClass) happen to be singleton on their own.
Is that true? If so, does it apply to just classes registered with type(MyController) or does it use the annotation #NgController, etc. How does that impact the service and factory classes we write.
Also, where can i find a doc or link explaining the same.
Short answer: No, NgControllers are not singletons. The long answer discussed hierarchial dependency injection and the AngularDart template compiler.
Dependency Injection (DI)
The basic setup for DI is to create a single instance for each type registered with the DI system. Types are registered through modules before the injector is created. Once the injector is created, it will create instances on-demand.
var injector = new Injector([
new Module()
..type(SomeClass)
..value(AnotherClass, new AnotherClass('toplevel'))]);
Hierarchical DI
AngularDart uses a hierarchical DI system, which allows us to "shadow" types in the injector by creating child injectors. Consider
var childInjector = new Injector.fromParent([
new Module()..type(AnotherClass, implementedBy: AnotherSubclass)], injector);
If you get the AnotherClass type from the first injector, you will get the "toplevel" AnotherClass. From the childInjector, you will get an instance of AnotherSubclass. However, both injectors share the same instance of the first registered type, SomeClass.
AngularDart's Compiler
When Angular instantiates a template, it walks the template's DOM looking for elements that match directive selectors. When it finds an element which matches one or more directives, it will create a new child injector for that element. It then uses the new child injector to create directives.
This means that you have a hierarchical injector structure which mirrors the DOM structure. When the same directive is created for two different elements, they are created in two different injectors.
However, since directives can request other directives from the injector (say in their constructor), it is possible for two directives to share the same instance of a second if the second directive was created on a shared parent injector.
Directive selectors and significant types
When the compiler is created, it gets a list of all registered directives and their selectors. It does this by asking the DI system for all types annotated with #NgAnnotation. #NgDirective, #NgComponent, #NgController are all subtypes of #NgAnnotation, so they are included in that list.
This is why you may have two types, MyController and MyService, in the same module but only have one, MyController, be used by the compiler.
Angular 2 Dart
DI maintains a single instance per provider.
DI looks from the providers of a component that requests a dependency (constructor parameter) to the providers of the parent component, then the parent of this parent, up to the root component, and then further to the providers added at bootstrap(AppComponent, [/* providers */]) and the providers provided by Angular itself.
The instance of the first provider found this way is injected.
If there are more providers, there are more instances.
If there are providers registered in #Component(...), then there is a different instance for each provider on every component instance.
Angular 1 Dart
From the same injector you get the same instance every time when you request an instance of a specific type.
But in angular the injectors are hierarchical (similar to scope).
When you request a type it is looked up the hierarchy upwards for an injector that has that type registered and this injector returns the same instance every time.
If you apply the same selector for your controller to multiple DOM elements you get a new controller instance each time because there gets a new injectors instance created which gets some types registered like the controller and the element the controller was applied to. That injector returns its own instance when you request a type it has registered.
Related
According to the official documentation here:
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters#authorization-filters
To implement a custom ActionFilter in ASP.NET Core I have three choices:
SeviceFilterAttribute
TypeFilterAttribute
IFilterFactory
But for all three it is stated that:
Shouldn't be used with a filter that depends on services with a lifetime other than singleton.
So how can I inject scoped services in my custom ActionFilter? I can easily get a scoped service from the current HttpContext like this:
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
ISubscriptionHelper subscriptionHelper =
actionContext.HttpContext.RequestServices
.GetRequiredService<ISubscriptionHelper>();
}
But then I am wondering if I am doing something wrong? What is the correct way to depend on scoped services in a custom ActionFilterAttribute?
Resolving services from the HttpContext.RequestServices will correctly resolve scoped and transient instances without causing any problems such as Captive Dependencies. In case resolved components implement IDisposable, they will be disposed of when the request ends. ASP.NET Core passes on the current HttpContext object to filter's OnActionExecuting method and that HttpContext gives access to the DI Container.
This is completely different from injecting those services into the constructor, because the action filter will be cached for the lifetime of the application. Any dependencies stored in private fields will, therefore, live as long as that filter. This leads to the so called Captive Dependency problem.
Code that accesses the DI Container (the HttpContext.RequestServices is your gateway into the DI Container) should be centralized in the infrastructure code of the startup path of the application—the so called Composition Root. Accessing your DI Container outside the Composition Root inevitably leads to the Service Locator anti-pattern—this should not be taken lightly.
To prevent this, it is advised to keep the amount of code inside the action filter as small as possible and implement the filter as a Humble Object. This means that preferably, the only line of code inside the filter is the following:
actionContext.HttpContext.RequestServices
.GetRequiredService<ISomeService>() // resolve service
.DoSomeOperation(); // delegate work to service
This means all (application) logic is moved to the ISomeService implementation, allowing the action filter to become a Humble Object.
We have migrated from a windows Framework 4.7 application to .NET 6.0. Lamar is added for Dependency Injection. We are trying to finalize a refactor to the latest "one-file" program.cs but are getting unexpected System.ObjectDisposedException: 'Cannot access a disposed object'. In all cases, the error is against a Func<T> during object creation.
All our tests are running correctly using the same environment, except to start the tests we (a) create the DI container and (b) use the container to create an object that loads the singletons (from MongoDB):
Container = new Container(registry);
var start = Container.GetInstance<HomeService>();
In the program.cs, we configure the container, but do not get to see it created, or access it inside program.cs. Instead we create HomeService from IServiceProvider during the first use of a controller. Here we were trying to limit the lifecyle scope during creation:
using (var scope = _container.CreateScope())
{
scope.ServiceProvider.GetService<INewHomeService>();
}
For test, we use the same loading steps, except for adding controllers/mvc, of course (i.e. NOT using builder.Services.AddControllers(); and builder.Services.AddMvc() for (integration) testing).
We have tried a lot of different things, like creating our object independently to the startup, but that did not align the singletons. We can get functionality by using static instead, but then we lose dynamic change access.
Some great tips like Resolving instances with ASP.NET Core DI from within ConfigureServices and https://andrewlock.net/exploring-dotnet-6-part-10-new-dependency-injection-features-in-dotnet-6/ but I can't see the specific example to get the live container just after initial creation.
Is it possible that the issue is just the difference between the lifecycle management of the new .NET DI implementation? As this is configuration at the composition root, if we can configure as per our testing approach, it should solve our problem. Other solutions welcome!
The problem 'Cannot access a disposed object' was being caused by a lifecycle mismatch between retained context and the controller access. The code retained a handle on the state object, that had a handle on the factory using FUNC. As we did not configure the Func as anything, it was transient during the controller graph creation, and so was disposed when the controller request ended.
To solve, we tried registering ALL of the FUNC, per How to use Func<T> in built-in dependency injection which was a large task as we had a few factories throughout an old codebase.
The better solution was to create a factory in the composition root, and use an injected IserviceProvider (or with Lamar an IContainer). This is a simple workaround.
With our creation concern, the creation of our object after the completion of the startup process is working correctly as a lazy validation of the first controller access.
So, I have a viewmodel class in a xamarin project that I inject some dependencies into via ninject binding on app start. One of these is an IDialogService.
When my MainPage in my application changes it raises a property changed event and I rebind the implementation of the dialog service since it is tied to the MainPage.
If my viewmodel has already been created with lets say DialogServiceA and then when MainPage changes we rebind to DialogServiceB, will my viewmodel be using service A or B? I think it is using A and therefore does not display in the UI because it is tied to a MainPage that no longer exists.
So, if this is the case how can I dynamically change my dialog service but then update classes that have already been instantiated without changing everything to get the current dialog service from the container every time its used (therefore not injecting it at all really, and doing more of a servicelocator)
Also, if this approach is completely wrong, set me straight.
You're right. Re-configuration of the container does not affect already instanciated objects.
If you want to change dependencies without re-instanciating the dependent (parent ViewModel) there's a few possibilities for you:
use a factory to instanciate the service every time. Implement an Abstract Factory (Site by Mark Seeman) or use Ninject.Extensions.Factory to do so
instead of injecting a service directly, inject an adapter. The adapter then redirects the request to the currently appropriate service. To do so, either all service can be injected into the adapter, or you can use a factory as with the possibility above.
instead of inject a service directly, inject a proxy. The proxy is quite similar to the adapter, but instead of coding every method / property redirection specifically, you code a generic redirect by an interceptor. Here's a tutorial on castle dynamic proxy
At the end of the day, however, i believe you'll also need a way to manage when to change the service / which it should be. There's probably a design alternative which doesn't rely on exchanging objects in such a manner.. which would make it an easier (and thus better?) design.
Edit: i just saw that you also tagged the question as xamarin-forms. In that case it most likely won't be an option to use either a dynamic proxy nor ninject.extensions.factory (it relies on dynamic proxies, too). Why? dynamic proxy / IL emitting is not supported on all platforms, AFAIR specifically on Apple devices this can't be done.
I am using the NamedScoped Ninject extension in an attempt to create object graphs that are constructed everytime a command handler is constructed by the container. In other words, I want a fresh object graph for every command that might get processed by its corresponding handler.
I have used the .DefinesNamedScope("TopLevelOrhcestrator") binding when registering my "command handlers" as they are the top level for command processing.
A type in this named scope needs to be injected with the result of a method call on a type already registered in this named scope. I thought the best way to do this would be with a ninject provider.
Inside the provider I attempt to resolve the type in hopes I can call a method on it to pass into another object I am creating within this named scope. The problem I'm having is that when I ask the IContext for the instance inside the customer provider I get an exception that says "No matching scopes are available, and the type is declared InNamedScope(TopLevelOrchestrator).
context.Kernel.Get<TypeAlreadyRegisteredInScope>().MethodThatGetsAnotherDependency()
Is it possible to get types from the container inside a Ninject provider when they are registered inside a named scope?
EDIT
I apologize if the use case seems a bit odd, I am experimenting with some ideas about how to manage my units of work and other services/managers that may need a handle to the uow to complete a business usecase. I know its common for the unit of work to be "started" and then passed into all dependencies that may need to take part in a larger process. I was thinking I'd rather let my orchestrator take a unit of work factory so that it could deterministically destroy the UOW and it would be clear who the owner of a usecase is. What would get supplied to the managers/services would be a proxy to the unit of work that would be null until a real unit of work was started by the orchestrator. That's why I was attempting to link the proxy from the already registered type in my provider. This is all very experimental at this point and was testing some ideas.
I'd be happy to hear any further thoughts.
For MethodThatGetsAnotherDependency() to be able to .Get<>() an instance that is bound .InNamedScope(...) you will need to add the Context Preservation Extension.
This is because NamedScope is adding a parameter to the request context of the binding that has .DefinesNamedScope(...). As soon as that request is over, that context and it's parameters are forgotten. Now with the ContextPreservation extension the context is kept and reused for late / factory creations (Func<>, interface factory with .ToFactory() binding...). It think it should also work with providers.
If not, just switch to a factory instead of a provider.
However i have to admit that i don't fully understand why/what you are trying to achieve. There might be simpler ways.
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?