Before we start talking about Orchard Framework implementation of dependency injection, and how we can use and extend it, you can start with this link to understand the ASP.Net MVC dependency injection.
Orchard DI was built on top of Autofac library (Which known as one of the best DI libraries for .Net framework), also Orchard framework layer will simplify the manipulation of injectable dependencies, in many aspects as creating, suppressing and scoping.
Register New Dependency
Orchard has automatic discovery and registration mechanism for dependencies, so if you want to register new one, simply make it implement "IDependency" interface like the following:
Public interface IServiceDependency : IDependency {
}
Public class ServiceDependency : IServiceDependency {
}
Now, "ServiceDepenency" is injectable.
Control Dependency Lifetime Scope
One of the main advantages of using dependency injection pattern, is how it make controling the lifetime of dependencies very simple, combining that with the automation of registration in Orchard will make our life easier than ever.
Orchard has four predefined scopes to be used in our registrations, every one of them has a specific interface to be implemented, this way we will tell Orchard how to register our dependencies, as following:
- IDependency: Base interface for services that are instantiated per unit of work (i.e. web request).
- ISingletonDependency: Base interface for services that are instantiated per shell/tenant.
- IUnitOfWorkDependency: Base interface for services that may *only* be instantiated in a unit of work, this interface is used to guarantee they are not accidentally referenced by a singleton dependency.
- ITransientDependency: Base interface for services that are instantiated per usage.
Feature Based Dependencies
What you should do to bind a dependency to a specific feature? then, simply if the feature being disabled, then all its bound dependencyies will not going to be registered from the beginning, this also can be done simply by what Orchard offers.
To bind a dependency to specific feature, you can decorate it by "OrchardFeatureAttribute" attribute, like:
[OrchardFeature("CustomFeature")]
Public class ServiceDependency : IServiceDependency {
}
Now, "ServiceDependency" will be bound to feature called "CustomFeature", so we can have multiple implementations of "IServiceDependency" interface with the ability to switch between them easily by enabling or disabling their parent feature.
Suppressing Dependencies
Sometimes, we need to override one of the dependencies without disabling its feature, here you will need to decorate your dependency by "OrchardSuppressDependency" attribute, which take the full qualified name of the original dependency as a parameter, like:
[OrchardFeature("OtherCustomFeature")]
[OrchardSuppressDependency("CustomFeature.Services.ServiceDependency")]
Public class OtherServiceDependency : IServiceDependency {
}
Now, if "OtherCustomFeature" feature is enabled, "OtherServiceDependency" will be registered as an implementation of "IServiceDependency", instead of "ServiceDependency".
Manual Dependency Registration
Although, automatic dependency registration with lifetime scope controling is very useful, but in some cases you will need to manually registering your dependencies, to take full control of the registration.
Since Orchard DI is based on Autofac, then you can use one of Autofac features (which supported by Orchard) to do this.
With the usage of "Modules" Autofac feature (Please refer to this link for more information), in addition to Orchard automatic discovery and registration mechanism which includes Modules also, you can gain more space to configure your registrations and doing some magical things with them, inside "Module" implementation you will find the following skeleton:
public class CustomModule : Module {
protected override void Load(ContainerBuilder builder) {
// Add registrations to the container
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) {
// Attach module-specific functionality to a component registration.
}
protected virtual void AttachToRegistrationSource(IComponentRegistry componentRegistry, IRegistrationSource registrationSource) {
// Perform module-specific processing on a registration source.
}
}
No Comments