"ASP. MVC3" uses unity to implement dependency injection

Source: Internet
Author: User
Tags connectionstrings

What is Unity?

Unity is a lightweight and extensible dependency injection container that supports constructors, properties, and method invocation injections. Unity can handle the problems faced by developers who work on component-based software engineering. The key to building a successful application is to implement a very loosely coupled design. Loosely coupled applications are more flexible and easier to maintain. Such a program is also easier to test during development. You can simulate objects that have strong specific dependencies on shims (lightweight simulation implementations), such as database connections, network connections, ERP connections, and rich user interface components. For example, an object that handles customer information might depend on the data store that other objects access, validate the information, and check whether the user is authorized to perform the update. Dependency injection technology ensures that the client class correctly instantiates and populates all of these objects, especially if the dependency may be abstract.

How to get unity?

You can access http://unity.codeplex.com/releases to get the latest version of Unity now. Of course, if you have the NuGet Package Manager installed in your Visual Studio, you can get the latest version of unity directly from NuGet.

Api

Unitycontainer.registertype<itfrom,tto> ();

unitycontainer.registertype< Itfrom, TTO > ();

unitycontainer.registertype< Itfrom, TTO > ("KeyName");

ienumerable<t> databases = unitycontainer.resolveall<t> ();

IT instance = unitycontainer.resolve<it> ();

T instance = unitycontainer.resolve<t> ("KeyName");

Unitcontainer.registerinstance<t> ("KeyName", New T ());

Unitycontainer.buildup (existinginstance);

Iunitycontainer childContainer1 = Parentcontainer.createchildcontainer ();

Code examples

We have to do some preparatory work before we start. Start by creating a console application. Add unity to the current project using NuGet. We can see that there are 3 more dll:Microsoft.Practices.ServiceLocation in DLL references, Microsoft.Practices.Unity and Microsoft.Practices.Configuation.

Example 1: Creating a class based on interface dependencies

This is a simple introduction to Unity's API. What happens if you resolve a type without registering?

Let's say we need to process the log. Let's first declare an interface ILogger:

  public interface ILogger
{
void Write (string log);

}

We can implement this interface in a number of ways, and we assume that we want to write the log to a file:

  public class Filelogger:ilogger
{

#region ILogger Members

public void Write (string log)
{
Console.WriteLine ("Write Log in file.");
}

#endregion
}

We have a variety of choices about databases in real life. We create a base class for a database:

public class Database
{
}

Create a derived class:

public class Customerdatabase:database
{
Private ILogger _logger;
Public Customerdatabase (ILogger logger)
{
_logger = logger;
}
}

Note that the argument to its constructor is the ILogger type. First we will create a unity container:

UnityContainer container = new UnityContainer ();

Next we need to register a type in the container, which is a type of mapping, the interface type is ILogger, and the type I want to return is FileLogger:

Container. Registertype<ilogger, filelogger> ();

Then we use the Resolve method:

Database Database = container. Resolve<customerdatabase> ();

After debugging we can find that if there is no registered type in the container. After the Resolv method is executed, unity attempts to create the type, which executes the constructor for that class. The type of the last database variable is customerdatabase, and the current instance of its private field ILogger is also filelogger.

Example 2: Type mapping

We want to return an instance of a log class, regardless of which implementation class it is. We can specify the type as interface ILogger directly in the Resolve type:

UnityContainer container = new UnityContainer ();
Container. Registertype<ilogger, filelogger> ();
ILogger logger = container. Resolve<ilogger> ();

Every time container will return a new logger instance.

Example 3: Registration of a singleton mode

If we want to tell unity that we want to control the life cycle, we want to use a singleton pattern. The Registertype method contains an overload that will use Lifetimemanager. Every time we want to get to the database instance, unity always returns the first time I created the customerdatabase.

UnityContainer container = new UnityContainer ();
Container. Registertype<database, customerdatabase>
(New ContainerControlledLifetimeManager ());
Example 4: Key is included with registration

When we register with the container, we can attach a string-type key value.

UnityContainer container = new UnityContainer ();
Container. Registertype<database, sqldatabase> ("SQL");
Container. Registertype<database, oracledatabase> ("ORACLE");
ienumerable<database> databases = container. Resolveall<database> ();
Database Database = container. Resolve<database> ("SQL");

We registered the database named "SQL" and "ORACLE" to the container separately. When we use the Resolverall method is. The container returns all classes of type database in the container.

If we just want to go back to the SQL instance, we can use container. Resolve<database> ("SQL");

Example 5: Registering an instance that already exists

We can register an instance in container by the following way:

  UnityContainer container = new UnityContainer ();
Container. Registerinstance<database> (New SQLDatabase ());
Container. Registerinstance<database> ("Oracle", New Oracledatabase ());
Database Database = container. Resolve<database> ();
Database oracledatabase = container. Resolve<database> ("Oracle");

It seems to be no different from the way it is above. It is important that unity registers a singleton when we use the RegisterInstance method.

We also have a way to inject existing instances into the container.

             UnityContainer container = new UnityContainer ();
Container. Registertype<ilogger, filelogger> ();
SQLDatabase existdatabase = new SQLDatabase ();
Container. BuildUp (existdatabase);
Container. Registerinstance<database> (existdatabase);
Database Database = container. Resolve<database> ();

As in the above code, we already exist a database is db2database. What you want unity to do is inject dependency into the container.

We use the buildup method to tell unity what we think. That's when unity goes back to the Db2database class, if he discovers [Dependency] this feature. He automatically injects our front-registered FileLogger into the db2database logger field.

The following are the Db2database classes:

public class Db2database:database
{
[Dependency]
Public ILogger Logger {get; set;}
}
Using configuration files to implement relational mappings

We can also configure the dependency mappings for the configuration files in the Web. config. First I open the Web. config file. Add a section according to the following structure. Here I simply mapped the ILogger interface and the FileLogger. and specifies that the life cycle is a singleton.

<configuration>
<configSections>
<section name= "Unity"

Microsoft.Practices.Unity.Configuration "/>
</configSections>
<unity xmlns= "Http://schemas.microsoft.com/practices/2010/unity" >
<container name= "Containerone" >
<types>
<type type= "Unitydemo_consoleapplication.ilogger" mapto= "Unitydemo_consoleapplication.filelogger"
Lifetime= "Singleton"/>
</types>

</container>

</unity>
...
...
</configuration>

If you want to learn more about the use of elements and attributes, you can look at the following Unity -configured structure diagram in xml:



For more detailed information, see:

Http://msdn.microsoft.com/en-us/library/ff647848.aspx

Http://msdn.microsoft.com/zh-cn/library/dd203230.aspx

How to read the configuration and load

Unity also allows us to write set mappings in the config file.

First we will introduce namespaces: Microsoft.Practices.Unity.Configuration;

The previous method has been deprecated in the Unity2.0 version. Now we have 2 ways to read the configuration.

First, we use ConfigurationManager:

Reference namespace: System.Configuration

            Iunitycontainer MyContainer = new UnityContainer ();

Mycontainer.loadconfiguration ("Containerone");
Unityconfigurationsection section
= (unityconfigurationsection) configurationmanager.getsection ("Unity");
Section. Configure (MyContainer, "Containerone");

Second, we can read the configuration information directly with the container:

Iunitycontainer MyContainer = new UnityContainer ();
Mycontainer.loadconfiguration ("ContainerName");

Specifying dependencies through the injection API

Suppose we have a class of genericdatabase:



public class Genericdatabase:database
{
private string _connectionstring;
Public ILogger Logger {get; set;}

Public Genericdatabase (String connectionString)
{
_connectionstring = connectionString;
}
}

Here we are going to inject ConnectionString and Logger into this class through the injection API.

First, we're just like the front. Register a mapping Relationship:

            Iunitycontainer container = new UnityContainer ();
Container. Registertype<ilogger, filelogger> ();
Container. Registertype<database, genericdatabase> ();

Then inject connectionstrings and logger into the genericdatabase via the injection API:

Container. Configure<injectedmembers> ()
. Configureinjectionfor<genericdatabase> (
New Injectionconstructor (

? "DefaultConnectionString": configurationmanager.connectionstrings["ConnectionStrings"]. ConnectionString),
New Injectionproperty ("Logger")
);
Database Database = container. Resolve<database> ();

So the last database we get is the connection and the Logger.

nested containers

Containers can be nested, and the rules that are followed when getting instances are that if the child container does not contain the object that is needed, it is fetched to the parent container. If there is, get it from yourself.

Once the parent container is destroyed, the child container is destroyed as well.

UnityContainer Parentcontainer = new UnityContainer ();
Iunitycontainer childContainer1 = Parentcontainer.createchildcontainer ();
Iunitycontainer childContainer2 = Parentcontainer.createchildcontainer ();
Parentcontainer.registertype<ilogger, filelogger> (New ContainerControlledLifetimeManager ());
Childcontainer1.registertype<ilogger, eventlogger> (New ContainerControlledLifetimeManager ());
Should get FileLogger from Parentcontainer.
ILogger logger = childcontainer2.resolve<ilogger> ();
Logger. Write ("Test");
Should get EventLogger from himself.

ILogger logger2 = childcontainer1.resolve<ilogger> ();

Using unity to inject controllers in MVC

In MVC2 we will write a controllefactory inherited from Defaultcontrollerfactory.

and override GetControllerInstance () this method.

MVC3 provides better support for dependency injection. We can use-idependencyresolver and icontrolleractivator to inject the controller.

The specific implementation is as follows:

Create a MVC3 project.

We want to implement the new two interfaces available in MVC3: Idependencyresolver and Icontrolleractivator

Idependencyresolver exposes two methods-GetService's Getservices.the GetService method solves a separate registered service, supports the creation of arbitrary objects, and getservices resolves the registration of multiple services. The implementation of the Idependencyresolver interface should be delegated to the underlying dependency injection container to provide the type of registration service request. When there is a type of service request that is not registered, the ASP. NET MVC framework expects the implementation of this interface to return GetService to null and return an empty collection from GetServices. Let's create a custom dependency parser class with the Idependencyresolver Intreface derivation, which provides a unified dependency injection effort.

We define a class named Unitydependencyresolver:

  public class Unitydependencyresolver:idependencyresolver
{
Iunitycontainer container;
Public unitydependencyresolver (Iunitycontainer container)
{
This.container = container;
}

public Object GetService (Type servicetype)
{
Try
{
Return container. Resolve (servicetype);
}
Catch
{
return null;
}
}

Public ienumerable<object> getservices (Type servicetype)
{
Try
{
Return container. ResolveAll (servicetype);
}
Catch
{
return new list<object> ();
}
}
}

Implement two methods GetService and GetServices. Use the Unity container to return the service or ojbect we need.

Implement two methods GetService and GetServices. Use the Unity container to return the service or ojbect we need.

ASP. 3 has introduced a new interface, Icontrolleractivator, that lets you activate a behavior controller with a custom, and can use dependency injection. Let's create a derived from Icontrolleractivator A custom controller for the interface

IController icontrolleractivator.create (System.Web.Routing.RequestContext RequestContext,
Type Controllertype)
{
Return dependencyresolver.current
. GetService (Controllertype) as IController;
}

DependencyResolver.Current.GetService executes the methods in our own definition of unitydependencyresolver.

With these two classes defined, we find Global.asax.cs and add a private method Getunitycontainer () in it:

        Private Iunitycontainer Getunitycontainer ()
{
Create UnityContainer
Iunitycontainer container = new UnityContainer ()
. Registertype<icontrolleractivator, Customcontrolleractivator> ()
. Registertype<ilogger, flatfilelogger> ();
return container;
}

This method defines a new container. And the mapping relationship is registered. The container we want to return contains: Customcontrolleractivator and Flatfilelogger.

Iunitycontainer container = Getunitycontainer ();

Dependencyresolver.setresolver (new Unitydependencyresolver (container));

The top is all done. We add the following code to the Application_Start method:

protected void Application_Start ()
{
...
Iunitycontainer container = Getunitycontainer ();
Dependencyresolver.setresolver (new Unitydependencyresolver (container));
}

First we get container through the Getunitycontainer method, and setting the current resolver is the unitydependencyresolver of our own implementation.

In the controller we only need to add a [Dependency] feature, we can easily get into the logger we injected.

  public class Homecontroller:controller
{
[Dependency]
Public ILogger Logger {get; set;}

Public ActionResult Index ()
{

Viewbag.message = "Welcome to ASP. mvc!";

Logger.gettype ();

return View ();
}

Public ActionResult About ()
{
return View ();
}
}

We can use Logger.gettype () to see that our current logger is our previously registered Flatfilelogger.

"ASP. MVC3" uses unity to implement dependency injection

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.