Skip to content
This repository has been archived by the owner on Sep 16, 2023. It is now read-only.

AddingRegistrations

Craig Fowler edited this page Jan 17, 2018 · 10 revisions

Typically, you will add registrations for your components into the FlexDi container before attempting to resolve them. The registration for a component specifies how it should be resolved. If the applicable option is enabled though, FlexDi is able to resolve some classes without needing registrations.

Using the registration helper

The recommended way to add registrations is via the registration helper, which guides you through the process. This is available via the container or an object which implements IReceivesRegistrations. This example shows how you might register two type registrations.

container.AddRegistrations(helper => {
    helper.RegisterType<MyService>()
        .As<IMyService>();
    helper.RegisterType<OtherService>()
        .As<IOtherService>();
});

Adding the registrations directly to the container

As an alternative to the registration helper, you may add a collection of IServiceRegistration directly to the container. An overload of the AddRegistrations method facilitates this, should you wish to construct your registrations by hand.

Options common to all registrations

Service type

All registrations must have a service type; it indicates the System.Type which will be satisfied by the registration when resolution occurs. This corresponds to the As<T> method on the registration helper, or in some methods it is a mandatory parameter. If the As<T> method is not called for a registration then the service type is set to be the same as the type of the implementation type for the registration.

Service types are often interfaces; the registration declares to the container that "The registered implementation is registered for/as this interface". Thus when the interface is to be resolved, the registered implementation is used to fulfil it. Consider the following example.

// Some types
public interface IMyService
{ string GetName(); }
public class MyServiceImplementation : IMyService
{ public string GetName() => "Joe Bloggs"; }

// Registration code
container.AddRegistrations(helper => {
    helper.RegisterType<MyServiceImplementation>()
        .As<IMyService>();
});

// Resolution code.  Because of the type registration,
// 'myService' would be resolved as an instance of
// MyServiceImplementation
var myService = container.Resolve<IMyService>();

When using the registration helper, the service type must be configured before other options. If you wish to skip providing a service type (IE: register the implementation only as its own type), then use the AsOwnType method.

Registration name

This corresponds to the WithName method on a registration builder (exposed via the registration helper). By default registrations do not have a name. By naming them, multiple registrations for the same service type may coexist within a container.

When resolution occurs, it will favour a registration with a matching name over one with no name.

Default: null (an unnamed registration)

Cacheable

This indicates whether or not instances created by this registration may be cached, corresponding to the .Cacheable() and .NotCacheable() methods on the builder. Caching (in this context) means that subsequent resolutions using the same registration will return the same object instance and will not create a new object. Set this to false if you wish a new object to be created every time for this registration.

Please note that this functionality is also controlled via a caching option on the container itself; if that is set to false then no caching will occur regardless of this per-registration setting. Also, setting a registration as not-cacheable using the registration builder will also set dispose with container to false.

Default: true

Also note that this cannot be set to false for Instance registrations.

Dispose with container

After a container creates an object instance, assuming that the cache is enabled and that the registration is cacheable, then that instance is eligible for automatic disposal when the container which created it is disposed.

If this setting is true then the object instance will be disposed once its associated container is disposed; if false then it will not be disposed, even if it were eligible. Note that a registration may not have this set to true, if their cacheable setting is false. This setting corresponds to the .DisposeWithContainer() and .DoNotDisposeWithContainer() methods on the registration builder.

The default value for this setting is dependant upon the registration type. In short, if the container does not create the instance then by default it will not automatically dispose it.

The registrations available

This section will concentrate on the first mechanism desctibed, using the registration helper. The same options are of course available to every registration.

Type registrations

A type registration registers a non-abstract class to be instantiated by the container when it is resolved.

When resolution occurs, the container will select the constructor on that type which has the most parameters. Whether or not it considers non-public constructors or not is controlled by a setting on the container itself. If more than one eligible constructors are tied for the most parameters then an exception will be raised; in this case use a factory registration to choose the appropriate constructor.

Factory registrations

A factory registration uses a delegate to create a suitable instance which implements the desired service type. This may be a simple inline lambda function or a method. Any parameters to that method will themselves be resolved.

You may use factory registrations in order to perform 'dynamic' resolution of components. Consider the following example, which requires the self-register a resolver container option to be enabled:

// Registrations
container.AddRegistrations(helper => {
    helper.RegisterType<WorkingDayProvider>()
        .As<IGetsCurrentWorkingDay>();
    helper.RegisterType<WeekdayOrderingService>()
        .AsOwnType();
    helper.RegisterType<WeekendOrderingService>()
        .AsOwnType();
    helper.RegisterFactory(GetOrderingService)
        .AsOwnType()
        .NotCacheable();
});

// Factory method
IFulfilsOrders GetOrderingService(IResolvesServices resolver)
{
    var workingDayProvider = resolver.Resolve<IGetsCurrentWorkingDay>();
    var isWeekend = workingDayProvider.GetToday().IsWeekend;
    
    if(isWeekend) return resolver.Resolve<WeekendOrderingService>();
    return resolver.Resolve<WeekdayOrderingService>();
}

Via this example, any time the container is used to resolve an instance of IFulfilsOrders, it will provide an instance of either the weekend or weekday service, depending upon the current day.

Instance registrations

An instance registration provides an existing object instance (created by whatever means appropriate) to the container. This same object instance is returned as the result of resolution.