Overview
Unity Application Block (Unity) is a lightweight and scalable dependency injection container that supports constructor, attribute, and method call injection. It provides developers with the following benefits:
This simplifies object creation, especially hierarchical object structures and dependencies.
Allows developers to specify dependency requirement abstraction during runtime or configuration, and simplifies management of cross-concern.
The service positioning function allows the customer to save or cache the container code. This is particularly useful when developers can persistently send containers to ASP. NET sessions or ASP. NET web applications in applications.
Common scenarios
In addition to the components that independently address cross-cutting concerns such as logs, authentication, authorization, caching, and exception handling, modern Business systems generally consist of custom business objects and components that complete special or general tasks in applications.
The key to successfully building such an application is to obtain a decoupled or extremely loosely coupled design. Loosely Coupled applications are more flexible and easy to maintain. At the same time, tests can be conducted during development to simulate the object's pile (implementation of lightweight simulation), which enhances the Actual dependency. For example, database connection, network connection, ERP connection, and rich user interface components.
Dependency injection is a major technique used to build loosely coupled applications. It provides methods to process dependencies between objects. For example, an object that processes user information may depend on other objects that access data storage, verify information, and check whether the user is authorized to execute updates. The dependency Injection Technology ensures that the user class correctly initializes and assembles all these objects, especially the dependency is abstract.
Using containers can have many advantages, but it will change the design method of the application, especially for Component-Based Development. Friends can choose to use it.
Prepare relevant code
For the following description, we first compile Several Interfaces and classes that are later required:
Interface ilogger
public interface ILogger{ void Write(string message);}
Flatfilelogger class
public class FlatFileLogger : ILogger{ public void Write(string message) { Console.WriteLine(String.Format("Message:{0}", message)); Console.WriteLine("Target:FlatFile"); }}
Databaselogger class
public class DatabaseLogger : ILogger{ public void Write(string message) { Console.WriteLine(String.Format("Message:{0}",message)); Console.WriteLine("Target:Database"); }}
Create a container
There are two methods to create a container instance in unity: one is to create a container instance directly using the constructor, as shown in the following code:
class Program{ static void Main(string[] args) { IUnityContainer container = new UnityContainer(); }}
The second method is to create a container by using the parent container. in unity, you can create a container by using the parent container:
You can use createchildcontainer to create a container using the parent container:
class Program{ static void Main(string[] args) { UnityContainer parentContainer = new UnityContainer(); UnityContainer childContainer = (UnityContainer )parentContainer.CreateChildContainer(); }}
The benefit of using hierarchical containers is that we can place objects with different lifecycles in different containers. If a sub-container is released, the objects in other sub-containers will not be affected, however, if the parent container at the root node is released, all sub-containers will be released.
class Program{ static void Main(string[] args) { UnityContainer parentContainer = new UnityContainer(); UnityContainer childContainer = (UnityContainer )parentContainer.CreateChildContainer(); // can use both generated objects here // Dispose child container childContainer.Dispose(); // can use only object in parent container here // Dispose parent container parentContainer.Dispose(); }}
Register interface ing
The registertype method is provided in unity for us to register the interface ing in the container:
class Program{ static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType<ILogger, DatabaseLogger>(); container.RegisterType<ILogger, FlatFileLogger>("flatfileLogger"); }}
The first generic parameter is the base type, and the second generic parameter is the component type. They must satisfy certain generic constraints:
IUnityContainer RegisterType<TFrom, TTo>() where TTo : TFrom;
In addition, if we do not specify a component when registering it, we can also use the non-generic registertype Method for interface ing:
class Program{ static void Main(string[] args) { IUnityContainer container = new UnityContainer();
container.RegisterType(typeof(ILogger),typeof(DatabaseLogger)); container.RegisterType(typeof(ILogger),typeof(FlatFileLogger),"flatfileLogger"); }}
Get object instance
The get method is provided in unity to obtain the object instance, as shown in the following code:
class Program{ static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType<ILogger, FlatFileLogger>(); ILogger logger = container.Resolve<ILogger>(); logger.Write("TerryLee"); }}
In the above Code, we registered an ilogger interface to the flatfilelogger ing in the container. When the resolve <ilogger> () method is called, a default type instance of ilogger is returned.
In the previously registered interface ing section, a reload of the register method is to specify a specific name for the interface ing, so that we can obtain a specific type of object instance based on the name and interface, the following code registers the fling between flatfilelogger and databaselogger to the ilogger interface at the same time, without specifying a name for databaselogger. When using the resolve method, you can obtain the databaselogger instance through ilogger and the specified name:
class Program{ static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType<ILogger, FlatFileLogger>(); container.RegisterType<ILogger, DatabaseLogger>("databaseLogger"); ILogger logger = container.Resolve<ILogger>("databaseLogger"); logger.Write("TerryLee"); }}
Run the code again. You can see that the databaselogger instance is obtained.
If we register the fling between flatfilelogger and databaselogger to the ilogger interface at the same time without specifying any names, directly calling the resolve method will return the object instance of the registered component, as shown in the following code:
class Program{ static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType<ILogger, FlatFileLogger>(); container.RegisterType<ILogger, DatabaseLogger>(); ILogger logger = container.Resolve<ILogger>(); logger.Write("TerryLee"); }}
After running, the system returns the databaselogger instance:
Of course, we can also use the non-generic resolve method to obtain the object instance:
class Program{ static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType<ILogger, FlatFileLogger>(); ILogger logger = container.Get(typeof(ILogger)) as ILogger; logger.Write("TerryLee"); }}
Get all object instances
In addition to getting a single object instance, we can also get all the object instances mapped to a certain interface in the container at a time, but it depends on the name provided during the registration ing, if no name is specified, it will not be obtained through the resolveall method.
class Program{ static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType<ILogger, FlatFileLogger>(); container.RegisterType<ILogger, FlatFileLogger>("flatFileLogger"); container.RegisterType<ILogger, DatabaseLogger>("DatabaseLogger");
IEnumerable<ILogger> loggers = container.ResolveAll<ILogger>(); foreach (ILogger logger in loggers) { if (null != logger) { Console.WriteLine(logger.GetType().ToString()); } } }}
After running, the first type instance without a name will not be obtained:
Note:
The untity container can contain the container-configured registration of types abstract interface type.
- Iunitycontainer mycontainer = new unitycontainer ();
- Mycontainer. registertype <imyservice, customerservice> ();
- Imyservice myserviceinstance = mycontainer. Resolve <imyservice> ();
You can also include an instance of container-configured registration of existing object instances in the container.
- Iunitycontainer mycontainer = new unitycontainer ();
- Loggingservice myexistingobject = new loggingservice ();
- Mycontainer. registerinstance <imyservice> (myexistingobject );
- Imyservice myserviceinstance = mycontainer. Resolve <imyservice> ();
Outstanding flexibility, providing excellent support for decoupling and program looseness.