Dependency Injection

Gazel uses Castle.Windsor for Dependency Injection. With Convention over Configuration capabilities of Castle.Windsor, you won't have to register your classes to use them. Every public class in module projects are automatically registered to Castle.Windsor. In this document you will find ways on how to make use of this feature.

Public Constructors

Every public class should contain a public constructor, in order for Castle.Windsor to register and configure them.

public class ProductManager { ... public ProductManager() { ... } ... }

Injecting Classes

Every public class is registered to Castle.Windsor by their own type so that they can be injected to other classes.

public class ProductManager { private readonly UserManager userManager; public ProductManager(UserManager userManager) { this.userManager = userManager; } ... } public class UserManager { ... }

Avoid creating circular dependencies as shown below;

public class ProductManager { ... public ProductManager(UserManager userManager) { ... } ... } public class UserManager { ... public UserManager(ProductManager userManager) { ... } ... }

For such cases;

  1. Consider refactoring your code. Two classes shouldn't depend on each other.
  2. If you think you have no other choice, then you can refactor code as shown below;
public class UserManager { private readonly IModuleContext context; public UserManager(IModuleContext context) { this.context = context; } private ProductManager ProductManager { get { return context.Resolve(typeof(ProductManager), Scope.Any); } } ... }

Injecting Interfaces

Public classes can also be injected using their interfaces

public class ProductManager { private readonly IUserManager userManager; public ProductManager(IUserManager userManager) { this.userManager = userManager; } ... } public interface IUserManager { ... } public class UserManager : IUserManager { ... }

Injecting Multiple Implementations

If an interface has more than one implementations then you can inject all of them at once by using IList<T>.

public class ProductManager { private IList<INotifier> notifiers; public ProductManager(IList<INotifier> notifiers) { this.notifiers = notifiers; } ... } public interface INotifier { ... } public class SmsNotifier : INotifier { ... } public class MailNotifier : INotifier { ... } public class PushNotifier : INotifier { ... }

Scopes

There are 3 types of scope;

  1. Transient: For every resolution, Windsor creates a new instance.
  2. Request: For every request there is only one instance. After the request ends, object is disposed.
  3. Singleton: There is only one instance until application is shut down.

Manager and Query classes are singleton by convention and the rest are transient.

IModuleContext interface

Gazel provides you with a gateway to all of the frameworks behind it. This gateway, IModuleContext, is an abstraction layer for your business functionality to be independent of those frameworks.

For singleton objects, mainly Manager objects, we encourage you to inject them through constructor. On the other hand, if you want to create a transient object using Castle.Windsor, you can make use of IModuleContext.

public class ProductManager { private readonly IModuleContext context; public ProductManager(IModuleContext context) { this.context = context; } public void DoSomethingHeavy() { context.New<BatchUserOperation>().DoSomethingHeavy(); } ... } public class BatchUserOperation { private readonly UserManager userManager; public BatchUserOperation(UserManager userManager) { this.userManager = userManager; } internal void DoSomethingHeavy() { ... } }

A word on Manager classes

For a class to be a manager class, name of the class should end with Manager.

public class ProductManager { ... }

Manager classes are singleton by convention.

Their purpose is to create an initial point of contact to a module and the functionality it provides. By that, we do not mean that it is a Façade layer.

Assume that there are 2 tables in your module: Company and Employee. Company class can be responsible for creating Employee records under Company records. But which class should create the first Company record.

This is where you need Manager classes. This problem cannot be solved by persistent classes because to have a persistent object there should be a record in the corresponding table. It cannot be a query class because its only responsibility is to read data. Manager classes are responsible for creating first database record of a module.

Aside from this responsibility, you can make use of Manager classes to provide batch operations or reporting services.