I'm pretty new to Aurelia (only been using it a few days) and I love it!
I know how to make a service with Aurelia, but how can I make that service a singleton that I can then share data with between multiple ViewModels?
Thanks
Just inject it
By default, the DI container assumes that everything is a singleton instance; one instance for the app. However, you can use a registration decorator to change this.
So I realized I was thinking about this too hard. I was trying to depend on the framework (Aurelia) to do all the work, but actually it was a simple ES6 class change that makes it an instance.
let instance = null;
export class SingletonService {
constructor() {
if(!instance) {
instance = this;
}
return instance;
}
}
Related
I am looking for a way to dynamically select the correct dependency during runtime using google guice.
My usecase is a kotlin application which can work with either sqlite or h2 databases depending on the configuration file provided.
The file is read when the application is executed and if the database is not found, the correct one is created and migrated into.
My database structure contains the Database (Interface), H2Database: Database, SQLiteDatabase: Database and the module binding class which looks like this:
class DatabaseModule: KotlinModule() {
override fun configure() {
bind<Database>().annotatedWith<configuration.H2>().to<H2Database>()
bind<Database>().annotatedWith<configuration.SQLite>().to<SQLiteDatabase>()
}
}
So far, with SQlite alone, I would simply request the dependency using:
#Inject
#SQLite
private lateinit var database: Database
How would I make this selection during runtime?
Without knowing too much about the specific of your code, I'll offer three general approaches.
(Also, I have never used Kotlin. I hope Java samples are enough for you to figure things out.)
First Approach
It sounds like you need some non-trivial logic to determine which Database implementation is the right one to use. This is a classic case for a ProviderBinding. Instead binding Database to a specific implementation, you bind Database to a class that is responsible providing instances (a Provider). For example, you might have this class:
public class MyDatabaseProvider.class implements Provider<Database> {
#Inject
public MyDatabaseProvider.class(Provider<SQLiteDatabase> sqliteProvider, Provider<H2Database> h2Provider) {
this.sqliteProvider = sqliteProvider;
this.h2Provider = h2Provider;
}
public Database get() {
// Logic to determine database type goes here
if (isUsingSqlite) {
return sqliteProvider.get();
} else if (isUsingH2) {
return h2Provider.get();
} else {
throw new ProvisionException("Could not determine correct database implementation.");
}
}
}
(Side note: This sample code gets you a new instance every time. It is fairly straightforward to make this also return a singleton instance.)
Then, to use it, you have two options. In your module, you would bind Database not to a specific implementation, but to your DatabaseProvider. Like this:
protected void configure() {
bind(Database.class).toProvider(MyDatabaseProvider.class);
}
The advantage of this approach is that you don't need to know the correct database implementation until Guice tries to construct an object that requires Database as one of its constructor args.
Second Approach
You could create a DatabaseRoutingProxy class which implements Database and then delegates to the correct database implementation. (I've used this pattern professionally. I don't think there's an "official" name for this design pattern, but you can find a discussion here.) This approach is based on lazy loading with Provider using the Providers that Guice automatically creates(1) for every bound type.
public class DatabaseRoutingProxy implements Database {
private Provider<SqliteDatabse> sqliteDatabaseProvider;
private Provider<H2Database> h2DatabaseProvider;
#Inject
public DatabaseRoutingProxy(Provider<SqliteDatabse> sqliteDatabaseProvider, Provider<H2Database> h2DatabaseProvider) {
this.sqliteDatabaseProvider = sqliteDatabaseProvider;
this.h2DatabaseProvider = h2DatabaseProvider;
}
// Not an overriden method
private Database getDatabase() {
boolean isSqlite = // ... decision logic, or maintain a decision state somewhere
// If these providers don't return singletons, then you should probably write some code
// to call the provider once and save the result for future use.
if (isSqlite) {
return sqliteDatabaseProvider.get();
} else {
return h2DatabaseProvider.get();
}
}
#Override
public QueryResult queryDatabase(QueryInput queryInput) {
return getDatabase().queryDatabase(queryInput);
}
// Implement rest of methods here, delegating as above
}
And in your Guice module:
protected void configure() {
bind(Database.class).to(DatabaseRoutingProxy.class);
// Bind these just so that Guice knows about them. (This might not actually be necessary.)
bind(SqliteDatabase.class);
bind(H2Database.class);
}
The advantage of this approach is that you don't need to be able to know which database implementation to use until you actually make a database call.
Both of these approaches have been assuming that you cannot instantiate an instance of H2Database or SqliteDatabase unless the backing database file actually exists. If it's possible to instantiate the object without the backing database file, then your code becomes much simpler. (Just have a router/proxy/delegator/whatever that takes the actual Database instances as the constructor args.)
Third Approach
This approach is completely different then the last two. It seems to me like your code is actually dealing with two questions:
Does a database actually exist? (If not, then make one.)
Which database exists? (And get the correct class to interact with it.)
If you can solve question 1 before even creating the guice injector that needs to know the answer to question 2, then you don't need to do anything complicated. You can just have a database module like this:
public class MyDatabaseModule extends AbstractModule {
public enum DatabaseType {
SQLITE,
H2
}
private DatabaseType databaseType;
public MyDatabaseModule(DatabaseType databaseType) {
this.databaseType = databaseType;
}
protected void configure() {
if (SQLITE.equals(databaseType)) {
bind(Database.class).to(SqliteDatabase.class);
} else if (H2.equals(databaseType)) {
bind(Database.class).to(H2Database.class);
}
}
}
Since you've separated out questions 1 & 2, when you create the injector that will use the MyDatabaseModule, you can pass in the appropriate value for the constructor argument.
Notes
The Injector documentation states that there will exist a Provider<T> for every binding T. I have successfully created bindings without creating the corresponding provider, therefore Guice must be automatically creating a Provider for configured bindings. (Edit: I found more documentation that states this more clearly.)
I found this line of code in Aurelia Dialog
static inject = [DialogService];
This is the full class:
import {Prompt} from './prompt';
import {DialogService} from '../dialog-service';
export class CommonDialogs {
static inject = [DialogService];
constructor(dialogService){
this.dialogService = dialogService;
}
prompt(question){
return this.dialogService.open({viewModel:Prompt, model:question});
};
}
What is the static inject doing? I get that it is injecting the dialog service into the constructor. But why do it this way instead of the usual inject?
As the blog post you linked to mentions, static inject was the original way to do dependency injection. Once Babel started supporting decorators, we implemented the inject decorator to make Aurelia code look a little nicer. Under the covers, it simply adds the inject property to the class at runtime (https://github.com/aurelia/dependency-injection/blob/master/src/decorators.js#L13).
In summary:
I've undefined of unknowed IProducerPlugin implementations on several assemblies located on a plugins folder.
I've a Core object stores a list of current registered users.
Core is Composition Root.
So, I need:
To create as many IProducerPlugin inherited class objects as the number of registered users.
When a new user is un/registered I need to create / release these objects.
In order to register my "plugins":
this.Kernel.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(Extensibility.IProducerPlugin))
.BindAllInterfaces());
I'm not quite figuring out how to implement this.
Could you help me please?
I'll appreciate a LOT your help.
DI containers in general and Ninject in special are not suitable to add and remove new bindings to the container during runtime. Some, like Autofac, don't even allow adding bindings once the container is created.
Ninject allows adding new bindings at any time, but you cannot, ever, remove them (*from some use cases there's Rebind, but that's not the same).
kernel.Release(object) is not removing the binding, it's only removing all references to the object that it holds.
For example:
var foo = new object();
kernel.Bind<object>().ToConstant(foo);
to allow garbage collecting of foo you can do one of the following:
kernel.Release(foo);
kernel.Dispose(); kernel = null;
and exactly this is what kernel.Release(...) is for. Maybe you could also Release a singleton and thus force ninject to create a new one on the next request. But i don't know whether this really works, and if it does, it certainly is quite an unexpected hack.
So what you should do is manage the list/dictionary yourself. You can bind and inject the list/dictionary/manager what ever you call it using ninject, but you cannot have ninject manager the list itself.
I've managed to do something like that similar using this a IBindingGenerator interface method...
I've used .BindWith<>() binding method...
this.Kernel.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(Extensibility.IProducerPlugin))
.BindWith<PluginBindingGenerator<Extensibility.IProducerPlugin>>()
);
I've implemented a IBindingGenerator:
public class PluginBindingGenerator<T> : IBindingGenerator
{
public System.Collections.Generic.IEnumerable<Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, Ninject.Syntax.IBindingRoot bindingRoot)
{
if (type != null && !type.IsAbstract && type.IsClass && typeof(T).IsAssignableFrom(type))
{
Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object> syntax = bindingRoot.Bind(typeof(Extensibility.IProducerPlugin)).ToProvider(new PluginProvider());
yield return (Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>)syntax;
}
}
}
public class PluginProvider : IProvider<object>
{
private System.Collections.Generic.Dictionary<Domain.Identity.ClientIdentity, Extensibility.IProducerPlugin> plugins;
And then, the provider:
public PluginProvider()
{
this.plugins = new System.Collections.Generic.Dictionary<Domain.Identity.ClientIdentity, Extensibility.IProducerPlugin>();
}
public object Create(IContext ctx)
{
//... I don't know what to do here...
return objects;
}
public Type Type
{
get { throw new NotImplementedException(); }
}
}
I use an external service to provide properties, but want to make those properties available as #Named(..) vars. Trying to do this in a configure method fails with npe:
Names.bindProperties(binder(), myPropRetriever.getProperties());
is failing because the myPropRetriever isn't appearing until guice has done it's work. I can see why this makes sense - anyone know of any funky hacks that might work around though? Would be handy in this instance..
Thanks to durron597 for the pointer to the related question which gave me enough to figure out. The answer is to use a child injector to take action on the previous injectors output. Example below:
Injector propInjector = Guice.createInjector(new PropertiesModule());
PropertiesService propService = propInjector.getInstance(PropertiesService.class);
Injector injector = propInjector.createChildInjector(new MyModule(Objects.firstNonNull(propService.getProperties(), new Properties())));
Injector is now your injector for the remainder of the app.
And then in MyModule you can take action on the created objects:
public class MyModule extends AbstractModule {
private final Properties properties;
public MyModule(Properties properties){
this.properties=properties;
}
#Override
protected void configure() {
// export all the properties as bindings
Names.bindProperties(binder(), properties);
// move on to bindings
// bind(..);
}
}
In case it helps anyone else..!
I'm working on a framework extension which handles dynamic injection using Ninject as the IoC container, but I'm having some trouble trying to work out how to achieve this.
The expectation of my framework is that you'll pass in the IModule(s) so it can easily be used in MVC, WebForms, etc. So I have the class structured like this:
public class NinjectFactory : IFactory, IDisposable {
readonly IKernel kernel;
public NinjectFactory(IModule[] modules) {
kernel = new StandardKernel(modules);
}
}
This is fine, I can create an instance in a Unit Test and pass in a basic implementation of IModule (using the build in InlineModule which seems to be recommended for testing).
The problem is that it's not until runtime that I know the type(s) I need to inject, and they are requested through the framework I'm extending, in a method like this:
public IInterface Create(Type neededType) {
}
And here's where I'm stumped, I'm not sure the best way to check->create (if required)->return, I have this so far:
public IInterface Create(Type neededType) {
if(!kernel.Components.Has(neededType)) {
kernel.Components.Connect(neededType, new StandardBindingFactory());
}
}
This adds it to the components collection, but I can't work out if it's created an instance or how I create an instance and pass in arguments for the .ctor.
Am I going about this the right way, or is Ninject not even meant to be be used that way?
Unless you want to alter or extend the internals of Ninject, you don't need to add anything to the Components collection on the kernel. To determine if a binding is available for a type, you can do something like this:
Type neededType = ...;
IKernel kernel = ...;
var registry = kernel.Components.Get<IBindingRegistry>();
if (registry.Has(neededType)) {
// Ninject can activate the type
}
Very very late answer but Microsoft.Practices.Unity allows Late Binding via App.Config
Just in case someone comes across this question