introduce
IOC uses components as the basic building blocks for applications. Providing access to the constructor parameters and properties of a component is often used as a means of implementing deployment-time configuration.
This is usually a questionable practice for the following reasons:
Constructors can change: changes to constructor signatures or component properties may disrupt deployed app.config files-issues that may occur late in the development process.
Json/xml difficult to maintain: a large number of component configuration files may be difficult to maintain.
The code begins to appear in the configuration: Exposing class properties and constructor parameters is an unpleasant violation of the "encapsulation" inside the application-these details are not part of the configuration file.
This is where the module can help.
A module is a small class that can be used to bundle a set of related components behind the "skins" to simplify configuration and deployment. The module exposes a set of intentional, limited configuration parameters that can be changed independently of the components that are used to implement the module.
Components in a module still use component/service-level dependencies to access components of other modules.
The module itself is not injected by dependency. They are used to configure containers that are not actually registered and parsed as other components do. For example, if your module requires constructor parameters, you need to pass the parameter yourself. It will not come from the container. Advantages of the module Reduce configuration Complexity
When you configure an application through IOC, you typically need to set parameters between multiple components. The module combines related configuration items into one place to mitigate the burden of finding the correct components.
The implementation of the module determines how the configuration parameters of the module are mapped to the component's properties and constructor parameters. configuration parameters are explicit
Configuring the application directly through the component creates a large surface area that needs to be considered when upgrading the application. When you can set any potential properties through a configuration file, the configuration files for each site are different, and refactoring is no longer secure.
The creation module limits the configuration parameters that the user can configure and enables the maintenance programmer to identify these parameters.
You can also avoid trade-offs between a good program element and a good configuration parameter. abstraction of the internal application architecture
Configuring an application through a component means that the configuration needs to vary based on things like using enumerations and creating policy classes. Use modules to hide these details of the application structure and keep the configuration simple. Better type safety
A small reduction in type security is always present when the class that makes up the application may vary by deployment. However, registering a large number of components through an XML configuration can exacerbate this problem.
Modules are built programmatically, so you can check all of the component registration logic at compile time. Dynamic Configuration
Components within the configuration module are dynamic: The behavior of the module can vary depending on the run-time environment. A purely component-based configuration, even if possible, is so difficult. Advanced Extensions
Not only can modules be used for simple type registration, they can also be attached to component resolution events and extend the resolution of the parameters or perform other extensions. The Log4net Integration module example shows one such module. Sample
In Autofac, the module implements the Autofac.Core.IModule interface. Typically they will derive from the Autofac.module abstract class.
The module provides the Ivehicle service:
public class Cartransportmodule:module
{public
bool Obeyspeedlimit {get; set;}
protected override void Load (Containerbuilder builder)
{
Builder. Register (c => New Car (c.resolve<idriver> ())). As<ivehicle> ();
if (obeyspeedlimit)
Builder. Register (c => new Sanedriver ()). As<idriver> ();
else
Builder. Register (c => new Crazydriver ()). As<idriver> ();
}
Packaged Configuration
Our cartransportmodule provides obeyspeedlimit configuration parameters and does not expose this by choosing between a sensible or crazy driver. " Customers who use the module can use it by declaring their intent:
Builder. Registermodule (New Cartransportmodule () {
Obeyspeedlimit = True
});
Or in the Microsoft.Extensions.Configuration configuration format:
{
' modules ': [{
' type ': ' Mynamespace.cartransportmodule, myassembly ',
' properties ': {
' Obeyspeedlimit ': True
}}
]
}
This is very valuable because the implementation of the module may change without the effect of flow. After all, this is the idea of encapsulation. Flexibility Coverage
Although Cartransportmodule clients may be focused on the Ivehicle service, the module also registers its idriver dependencies in the container. This ensures that the configuration can still be overwritten at deployment time, just as the component that makes up the module has been registered independently.
This is a "best practice" when you add an XML configuration using AUTOFAC after programmatic configuration, for example:
Builder. Registermodule (New Cartransportmodule ());
Builder. Registermodule (New Configurationsettingsreader ());
In this way, you can create a "emergency" overlay in a configuration file:
{
' components ': [{
' type ': ' Mynamespace.learnerdriver, myassembly ',
' services ': [{
' type ': '] Mynamespace.idriver, MyAssembly "}]}"
}
So, the module adds encapsulation, but it doesn't rule out that you have to patch them inside. adapt to the deployment environment
Modules can be dynamic-that is, they can configure themselves into their own execution environment.
When a module is loaded, it can do a lot of beautiful things, such as checking the environment:
protected override void Load (Containerbuilder builder)
{
if (Environment.OSVersion.Platform = = Platformid.unix)
Registerunixpathformatter (builder);
else
registerwindowspathformatter (builder);
}
common use cases for modulesConfigure related services that provide subsystems, such as data access with NHibernate
To package the optional application features as "Plug-ins"
Provides precompiled packages for system consolidation, such as an account system registration many similar services that are often used together, such as a set of file format converters to configure a new or customized mechanism for a container, such as a json/xml configuration that is implemented using a module; You can add a configuration that uses attributes in this way