Using Dependency Injection in Aurelia

Welcome to Part 4 of this series reviewing the Pluralsight course Aurelia Fundamentals by Brian Noyes.

briannoyes

Brian is your Aurelia Author

Brian is CTO and Architect at Solliance, an expert technology solutions development company.

Brian is a Microsoft Regional Director and MVP, and specializes in rich client technologies including XAML and HTML 5, as well as building the services that back them with WCF and ASP.NET Web API.

You can follow Brian through his blog at http://briannoyes.net

Also in this series:

Part 1 – Aurelia Prerequisites

Part 2 – Getting Started

Part 3 – Implementing MVVM

Using Dependency Injection in Aurelia

Purpose of Dependency Injection and Related Patterns

Dependency Injection is mostly about having loose coupling between dependent components.

Brian also mentions a couple of closely related patterns: Inversion of Control and Service Location

There are also many other Pluralsight Courses which cover Dependency Injection and/or Inversion of Control.

The ones that I have seen and found worthwhile are:

C# Interfaces by Jeremy Clark
RequireJS Dependency Injection and Module Loading by Jeff Valore
Creating JavaScript Modules with Browserify by Jeff Valore
Understanding ASP.NET Core by Roland Guijt
SOLID Principles of Object Oriented Design by Steve Smith
Inversion of Control by John Sonmez
Practical IoC with ASP.NET MVC4 by John Sonmez

To learn more about the Service Locator pattern, see John Brown’s Service Locator module in the Design Patterns Library course. For just a very brief Service Locator summary read this wikipedia article.

Also see my Design Patterns page.

Inversion of Control/Dependency Injection: Problem and Solution

Brian gives an example:

  • Some Consumer object is dependent on A
  • A is dependent on B and C
  • B is dependent on D
  • C is dependent on D and E

The brute force way to implement this is to new up every object before it is used, i.e. in A we would have new B(); and new C(); and so on. There are two problems with this:

  1. Very tight coupling between each component
  2. There may be shared state, and we can’t use that when we are creating separate instances of that state

There are some possible hacky workarounds, but Dependency Injection and Inversion of Control offers us a much better solution.

Brian explains the process that an IoC container goes through in this example.

Using ‘inject’ Decorator in Aurelia

The pattern is:

  • import the necessary modules
  • use the @inject decorator, passing in a service as a parameter

I recommend reading either Addy Osmani’s medium post Exploring ES7 Decorators, and/or Yehuda Katz’s decorators readme to learn more about Class Decorators.

Brian says here that they are an ES2016 feature. This is not true because they are currently a just a ES2017 stage 1 proposal. It is supported by TypeScript, and you can read more about that in the TypeScript Handbook.

Brian explains that there is an alternate solution supported by Aurelia which is static property injection, with an array of type names

static inject = [SomeService];

Dependency Injection in Action

This demonstration uses the class decorator syntax to inject DataCache into the Event and Events class constructors.

We see that the DataCache is shared state, and that the default mode of dependency injection in Aurelia is a singleton.

Declaratively Registering Lifetime Instances in Aurelia

We can indicate on class what instance lifetime it should have in container. There are two main patterns:

  • Singleton – constructed on first injection, same reference passed into other injections
  • Transient – new instance created for each injection

As the default mode is singleton, it is not necessary to specify the instance lifetime as a singleton, but you can make it explicit if you prefer.

Using Lifetime Management Decorators in Aurelia

Brian demonstrates how to use the transient decorator to specify a transient property.

We see in the console logs 3 separate constructions of DataCache

Explicitly Registering Types and Instances in Aurelia

There are three options:

  1. instance – just new up an object, then register it with the container
  2. singleton
  3. transient

For further information see Object Lifetime, Child Containers and Default Behavior

Using Framework Configuration to Explicitly Register Types

This demo updates our configure function again, and we see how to implement each of the three options described in the previous lesson.

Using Resolvers in Aurelia

There are currently 4 out of the box resolvers. Three of them are described in this lesson

  • Lazy.of(T) –  Injects a function for lazily evaluating the dependency
  • All.of(T) –  Injects an array of all services registered with the provided key
  • Optional.of(T) – Injects an instance of a class only if it already exists in the container; null otherwise.

See Resolvers in the official documentation to learn Parent.of(T)

Lazy Loading and Plugin Instancing with Aurelia

First a demo of using Lazy.of(T).

Brian creates an ImLazy class with a constructor and a doStuff method.

Then events.js is created with Events class and the method createAndUseImLazy.

In events.html there’s a button that calls createAndUseImLazy

The effect of all this is to defer the construction of the dependent object until the point where we need to use it.

Next, a demo of All.of(T), which is useful for plugins. We might want to register all plugins that are associated with a 3rd party system.

First we need a plugin definition. We see a class PlugIn1 with a doPlugInStuff method and another class PlugIn2 with another doPlugInStuff method.

In main.js we see how to import these plugin types and register them as transient.

Finally we inject All.of(“SuperPlugIn”) into our Events class.

So we have got multiple instances of different types all registered under the same name “SuperPlugIn”.

Registering Global Dependencies

This is a great way to avoid repetitive import declarations. We register a dependency globally through the app configure method.

It will then be available for injection into our modules without an import statement, and can be used in our views without a <require> element.

We do this with the globalResources keyword.

For more information see the FrameworkConfiguration documentation.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s