I'm wondering how scopes are defined in angular2.
Currently I have an service OrderService with a property CurrentOrder.
I have two components ('order.component', 'clients.component') acting as siblings instantiated by routing.
I provide OrderService in bootstrap and use it in both of my components by
import { OrderService} from './order.service';
and
constructor(private orderService:OrderService){ }
in ClientComponent i set CurrentOrder like orderService.CurrentOrder=someNewOrder.
after that I'm routing to OrderComponent and try to access orderService.CurrentOrder but its empty.
shouldn't orderService act as singleton provided in bootstrap ?
If you want a shared service to be one instance only, don't put in the providers arrays of your components - only in the bootstrap call.
Related
I'm having problems finding proper solution for my problem, namely:
Let's consider workflow:
Application starts
Main components are registered in Autofac
Application loads plugin assembly and registers modules within it
Container is being build
Plugin handling logic is run
Plugin can add its own controllers. To properly handle that I had to prepare interface which will provide me types of custom controllers:
interface ICustomControllerProvider
{
IEnumerable<Type> GetControllerTypes();
}
Based on the above my app knows how to integrate specified types as controllers.
All controllers are also defined as services, so Autofac deals with their creation, and so...
Problem:
I want to avoid specifying custom controller type twice
public PluginControllerProvider : ICustomControllerProvider
{
public IEnumerable<Type> GetControllerTypes()
{
// 1st type specification
// controller types are specified here, so they could be integrated with app
yield return typeof(ControllerX);
yield return typeof(ControllerY);
}
}
public class PluginModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<PluginControllerProvider>().As<ICustomControllerProvider>();
// 2nd type specification
// controllers have to be register in module as well
builder.RegisterType<ControllerX>();
builder.RegisterType<ControllerY>();
}
}
Is there any way how ControllerX and ControllerY could be managed by Autofac, where I specified them only in PluginControllerProvider?
I tried achieving that by providing custom registration source and resolving ICustomControllerProvider, however I cannot resolve ICustomControllerProvider based on arguments provided by IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor) from IRegistrationSource
Autofac does not offer the ability to inject a list of types registered with Autofac. You'll have to get that yourself by working with the lifetime scope registry.
Before I get into how you might solve this, I should probably note:
Listing the types registered is not a normal thing from a DI perspective. It'd be like listing all the controllers in your MVC application - you don't normally need to do that, and if you did, you'd likely need to build a whole metadata structure on top of it like the ApiExplorer that was built to do that on top of ASP.NET Core. That structure wouldn't be supported or involved with the DI system because you're querying about the system, not injecting live instances into the system.
If you are relying on DI to resolve controllers, you probably don't need a whole separate controller provider. Once you know what type you need for the request, you'd just resolve it.
All that's to say, while I'll answer the question, the way the design here is posed may be something you'd want to look at. What you're doing, trying to involve DI with listing metadata about the app... seems somewhat backwards (you'd feed the DI container based on the list of types, not get the list of types from the DI container).
But let's just go with it. Given:
There are controllers registered with Autofac
The controllers have no common base class or interface
There's no attributes on the controllers you could query
What I'd do is register all the controllers with some metadata. You need something to be able to locate the controllers in the list of all the types in the container.
builder.RegisterType<ControllerX>().WithMetadata("controller", true);
builder.RegisterType<ControllerY>().WithMetadata("controller", true);
Now in the plugin controller, you need to inject an ILifetimeScope because you have to query the list of stuff registered. The ILifetimeScope that gets injected into the controller will be the same scope from which the plugin controller itself was resolved.
You can use the injected scope to query things in the component registry tagged with your metadata.
public class PluginControllerProvider : ICustomControllerProvider
{
private readonly Type[] _controllerTypes;
public PluginController(ILifetimeScope scope)
{
_controllerTypes = scope
.ComponentRegistry
.Registrations
.Where(r => r.Metadata.ContainsKey("controller"))
.Select(r => r.Activator.LimitType)
.ToArray();
}
public IEnumerable<Type> GetControllerTypes()
{
return _controllerTypes;
}
}
Now, disclaimers:
If you are registering more controllers in child lifetime scopes (e.g., during a BeginLifetimeScope() call), you will need a controller provider from that scope or it won't get all the controller types. The provider needs to come from the scope that has all the registrations.
If you're using registration sources (like the AnyConcreteTypeNotAlreadyRegisteredSource), this won't capture things that come from the registration sources. It'll only capture things that come from direct registrations of a type (or lambda) on a ContainerBuilder.
But it should work.
When you want to provide scoped dependency, Dagger requires to annotate Component with this Scope too. What is the reason for that?
#Singleton // <- for what?
#Component(modules = [MyModule::class])
interface MyComponent {
//...
}
#Module
interface MyModule {
#Binds
#Singleton
fun provideDependency(impl: DepImpl): Dep
}
Scoping in Dagger means "give this binding the same lifetime as the component that contains it", so the component itself holds onto the instance so it can provide the same instance repeatedly.
Components are also hierarchical: through subcomponents and component dependencies you can have multiple components coexisting in the same application. In a typical Android app, you might have an Application component that provides bindings for several Activity components, and and each of those Activity components provides bindings for several Fragment components.
Though Dagger could theoretically infer scopes based on which module installs it, instead of requiring you to specify which scope applies to which component, this makes it more difficult to work with classes that declare scope and #Inject annotations without an explicit Dagger binding. If you're in an Activity component that inherits bindings from an Application component (often "singleton"), and an Activity binding relies on an #ApplicationScope-annotated class with an #Inject constructor, how would Dagger know to put it in the Application component instead of the Activity component? This might also make your code harder for humans to understand—I know I'd have trouble following it.
It seems that each component that creates its own instance of [a] service. I don't understand why.
I note this AngularJs 2 - multiple instance of service created, but I'm not clear on the correct solution. Do I create the service instance _myService in main:
void main() {
bootstrap(AppComponent,[MyService]);
}
and then copy it to [child] components (because I also remove MyService from the component providers)? This doesn't seem correct, because the components reference _myService before it's instantiated, and I have to check it for being null.
Thanks
Steve
You can use factory constructor pattern like here.
Creating your service in the bootstrap will make sure there is only one instance of it for the app (if you don't provide it again in some component).
You get multiple copies of it only if you provide it in some #Component - then each instance of the component (and all its children) will have a separate instance of the service.
I'm considering migrating to Dagger 2 some libraries. This library expose a configurable client, each configuration can be named and later retrieved in a singleton fashion.
Let me show a pseudo-code of how the library works from the user perspective:
// initialization
ClientSDK clientA = new ClientSDK.Builder()
.configuration().attributes().here()
.apiKey("someString") // set api key / credentials
.build();
LibraryAuthenticationManager customAuthManager = new MyCustomAuthenticationManager();
ClientSDK clientB = new ClientSDK.Builder()
.configuration().attributes().here()
.apiKey("someStringElse")
.customAuthManager(customAuthManager) // override some default
.baseApiUrl("https://custom.domain.com/and/path") // override some default setting
.build();
ClientSDK.setSingleton("clientA", clientA);
ClientSDK.setSingleton("clientB", clientB);
And when I need an instance elsewhere:
// usage everywhere else
ClientSDK clientB = ClientSDK.singleton("clientB");
clientB.userManager(); // "singleton" using the configuration of clientB
clientB.subscriptionsManager(); // "singleton" using the configuration of clientB
clientB.currentCachedUser(); // for clientB
clientB.doSomething(); // action on this instance of the ClientSDK
ClientSDK instances are created by the user of the library and the ClientSDK statically keep a map of singletons associated to the name.
(The actual behavior of the SDK is slightly different: the naming is automatic and based on a mandatory configuration parameter.)
It's like I have lot of singleton classes with a single point of entry (the ClientSDK) but since I can have multiple configuration of the ClientSDK each with his own singletons instances this are not really singletons.
If I would try write a library like that with Dagger 2 I would do something like:
class ClientSDK {
#Inject SDKConfiguration configuration;
#Inject LibraryAuthenticationManager authManager;
...
}
The problem is that I need each instance of the ClientSDK to have its own configuration and authManager (and many other services) injected. And they need to be definable (the configuration) and overridable (the actual implementation) from the library user.
Can I do something like this with Dagger 2? How?
I've seen I can create custom Scopes but they are defined at compile time and the library user should be the one defining them.
(the library is an Android Library, but this shouldn't be relevant)
Thanks
It sounds like you should be creating stateful/configurable Module instances and then generating separate Components or Subcomponents for each ClientSDK you build.
public class ClientSDK {
#Inject SDKConfiguration configuration;
#Inject LibraryAuthenticationManager authManager;
// ...
public static class Builder {
// ...
public ClientSDK build() {
return DaggerClientSDKComponent.builder()
.configurationModule(new ConfigurationModule(
apiKey, customAuthManager, baseApiUrl)
.build()
.getClientSdk();
}
}
}
...where your ConfigurationModule is a #Module you write that takes all of those configuration parameters and makes them accessible through properly-qualified #Provides methods, your ClientSDKComponent is a #Component you define that refers to the ConfigurationModule (among others) and defines a #Component.Builder inner interface. The Builder is important because you're telling Dagger it can no longer use its modules statically, or through instances it creates itself: You have to call a constructor or otherwise procure an instance, which the Component can then consume to provide instances.
Dagger won't get into the business of saving your named singletons, but it doesn't need to: you can save them yourself in a static Map, or save the ClientSDKComponent instance as an entry point. For that matter, if you're comfortable letting go of some of the control of ClientSDK, you could even make ClientSDK itself the Component; however, I'd advise against it, because you'll have less control of the static methods you want, and will lose the opportunity to write arbitrary methods or throw exceptions as needed.
You don't have to worry yourself about scopes, unless you want to: Dagger 2 tracks scope lifetime via component instance lifetime, so scopes are very easy to add for clarity but are not strictly necessary if you're comfortable with "unscoped" objects. If you have an object graph of true singleton objects, you can also store that component as a conventional (static final field) singleton and generate your ClientSDKComponent as a subcomponent of that longer-lived component. If it's important to your build dependency graph, you can also phrase it the other way, and have your ClientSDKComponent as a standalone component that depends on another #Component.
For example I have two interfaces: ICustomerService and IOrderService which each has a couple of functions like GetCustomer, GetOrder, etc.
I want one class to implement both interfaces: Server.
How does Castle Windsor respond to this?
Is it possible in the first place?
When I resolve the Server object based on one of the two interfaces, will I get the same object?
What happens when I have a constructor that has both interfaces in its parameters? Will there still be one object constructed.
assuming the LifeStyle is left to its default: Singleton.
There's no hard one-to-one mapping between a CLR type and a Windsor service or component (glossary if needed is here).
So you can have any of the following scenarios:
Many Components with different implementation types expose a single Service
container.Register(
Component.For<IFoo>().ImplementedBy<Foo1>(),
Component.For<IFoo>().ImplementedBy<Foo2>()
);
Many Components with same implementation type expose a single Service
container.Register(
Component.For<IFoo>().ImplementedBy<Foo1>(),
Component.For<IFoo>().ImplementedBy<Foo1>().Named("second")
);
Many Components with same implementation type expose different Services
container.Register(
Component.For<IFoo>().ImplementedBy<Foo1>(),
Component.For<IBar>().ImplementedBy<Foo1>().Named("second")
);
Single Component expose different Services
container.Register(
Component.For<IFoo, Bar>().ImplementedBy<Foo1>()
);
As you can see, yes - it is possible, and whether or not you'll get the same instance (assuming singleton) depends on which option you chose - if both Services will be exposed by the same Component, or not.