Dependency Injection

tip

If you are new to the concepts of inversion of control and dependency injection, check out this article by Martin Fowler.

Geocortex Mobile relies heavily on inversion of control patterns to inject dependencies into its components and services. Under the hood, Geocortex Mobile uses Autofac to register and inject components, services and other classes. To inject a dependency into a class in Geocortex Mobile, two things must happen.

  1. The class to be injected must register itself with the autofac container.
  2. The class that requires the dependency must accept a concrete class or abstract interface in its constructor as a placeholder for the injected class.

A good example of this pattern is the AlertOperations class in the commands and operation tutorial .

using App1.Services.AlertOperations;
using VertiGIS.Mobile.Composition;
using VertiGIS.Mobile.Composition.Messaging;
using VertiGIS.Mobile.Infrastructure.Messaging;
[assembly: Export(typeof(AlertOperations), SingleInstance = true)]
namespace App1.Services.AlertOperations
{
class AlertOperations : OperationsBase
{
public AlertOperations(IOperationRegistry operationRegistry)
: base(operationRegistry)
{
}
}
}
  • This class both registers itself as a dependency, and has dependencies injected itself.
  • The assembly attribute Export is part of the Geocortex Mobile SDK, and registers the class with Autofac as a singleton.
  • The constructor of the class takes an object of the type IOperationRegistry. This dependency will be resolved by Autofac at runtime when AlertOperations is injected by another class. Chaining dependency injection in this manner is both a common and best practice pattern in Geocortex Mobile.

This is an example of a class that injects AlertOperations, which will in turn inject an IOperationRegistry into itself.

[assembly: Service(typeof(CustomService), PropertiesAutowired = true)]
namespace App1.Services
{
class CustomService : ServiceBase
{
public CustomService(AlertOperations AlertOperations)
:base()
{
...
}
}
...
}
tip

Autofac has a number of ways to inject dependencies, including factory functions which can dynamically spin up instances of a class or lazy wrappers for dependencies. For details, check out the Autofac documentation.

Components and Services#

Components and services in Geocortex Mobile are almost always initialized by Autofac. This means that they can inject any class that has been registered with Autofac in their constructor, allowing classes used for behavior like commands and operations to be easily shared and loosely coupled to many components and services. Root level components (components that are instantiated from a layout definition) must always register with Autofac to be correctly initialized, and it is best practice to use dependency injection to initialize instances of any other custom classes, services or components that the root level component depends on.

List of Registration Assembly Attributes#

There's a number of different Geocortex Mobile specific assembly attributes which allow classes to register themselves with Geocortex Mobile's Autofac container.

Export#

Used for registering a generic class with Autofac.

[assembly: Export(typeof(MyCustomClass))]

Component#

Used for registering a component that does not consume configuration. For a more detailed example, see the tutorial on implementing a custom component.

[assembly: Component(typeof(MyCustomComponent), "my-custom-component")]

AppItemComponent#

Used for registering a component that does consume configuration. For a more detailed example, see the tutorial on implementing a custom component with configuration.

[assembly: AppItemComponent(typeof(MyCustomComponent), "my-custom-component", MyCustomComponentConfiguration.ConfigItemtype)]

Service#

Used for registering a service. For a more detailed example, see create a service.

[assembly: Service(typeof(CustomService))]

AppItem#

Used for registering the definition for an app item with Geocortex Mobile. For a more detailed example, see the tutorial on implementing a custom component with app configuration.

[assembly: AppItem(CustomAppItem.AppItemType, typeof(CustomAppItem))]

View#

Used for registering a view with Geocortex Mobile. For a more detailed example see the tutorial on implementing a custom component with UI.

[assembly: View(typeof(CustomView))]

ViewModel#

Used for registering a view model with Geocortex Mobile. For a more detailed example see the tutorial on implementing a custom component with UI.

[assembly: ViewModel(typeof(CustomViewModel))]

Managing Sub-Dependencies#

Sometimes, you may may want to split code associated with a component or service into multiple classes for individual views, utility functions, etc. Each of these classes may have dependencies on global classes registered with Autofac, such as operations, but only the registered component is instantiated by dependency injection, so only the component class can inject these global classes. One solution is to have the component class inject all the dependencies of its associated classes and pass them to the class constructors, but this pattern introduces unnecessary boilerplate and coupling. Instead, if the component class creates instances of associated classes through dependency injection, then Autofac will automatically resolve any dependencies the associated class has.

In the example below, the RelatedClass has a global dependency, MapOperations. In order to resolve this dependency, the CustomComponent creates an instance of the RelatedClass through dependency injection.

using VertiGIS.Mobile.Composition;
using VertiGIS.Mobile.Infrastructure.Messaging;
using VertiGIS.Mobile.Samples.Samples.Custom.Component;
[assembly: Export(typeof(RelatedClass))]
namespace VertiGIS.Mobile.Samples.Samples.Custom.Component
{
internal class RelatedClass
{
private MapOperations _mapOperations;
public RelatedClass(MapOperations mapOperations)
{
_mapOperations = mapOperations;
}
}
}

Relevant SDK Sample#

Check out the Geocortex Mobile SDK Sample for dependency injection.