What is Dependency injection
Dependency, which is another object that an object needs, for example, this is a store that we typically define to handle data access, let's use an example to explain, first, define a domain model as follows:
namespace Pattern.DI.MVC.Models
{
Public class Product
{
Public int Id {get; set;}
Public string Name {get; set;}
Public decimal Price {get; set;}
}
}
Then there is a simple storage class for the instance:
namespacePattern.DI.MVC.Models
{
Public classProductcontext
{
PublicList<product> products {get;InternalSet }
PublicProductcontext ()
{
Products.add (NewProduct () {Id = 1, Name ="Aunt Cang", Price = 100});
Products.add (NewProduct () {Id = 2, Name ="Muto Grandma", Price = 200});
Products.add (NewProduct () {Id = 3, Name ="Sister Ozawa", Price = 300});
}
}
Public classProductrepository
{
PrivateProductcontext context=NewProductcontext ();
PublicIenumerable<product> GetAll ()
{
returnContext. Products;
}
PublicProduct GetById (intId
{
returnContext. Products.firstordefault (p = = P.id = = Id);
}
}
}
Now, we define an ASP. NET WEB API controller to support get requests to the product entity set:
namespacePattern.DI.MVC.Controllers
{
Public classProductcontroller:apicontroller
{
Private ReadOnlyProductrepository productrepository=NewProductrepository ();
PublicIenumerable<product> Get ()
{
returnProductrepository.getall ();
}
PublicProduct Get (intId
{
returnProductrepository.getbyid (ID);
}
}
}
Now notice that this controller relies on the "Productrepository" class, we instantiate the productrepository in the class, this is the "bad taste" of the design, because of the following reasons:
- If you want to use another implementation to replace Productrepository, you also have to modify the Productcontroller class;
- If productrepository exists, you have to configure them in Productcontroller, and for a large project with many controllers, you will be able to drill down to wherever possible;
- It's hard to do unit tests because the controller has hard-coded queries to the database, and for a unit test, you can use a clone of the pile storage before you have the exact design.
We can solve this problem by injecting a productrepsoitory, first refactoring the Productrepository method into one socket:
namespacePattern.DI.MVC.Models
{
Public InterfaceIproductrepository
{
Ienumerable<product> GetAll ();
Product GetById (intID);
}
Public classProductrepository:iproductrepository
{
PrivateProductcontext context =NewProductcontext ();
PublicIenumerable<product> GetAll ()
{
returnContext. Products;
}
PublicProduct GetById (intId
{
returnContext. Products.firstordefault (p = = P.id = = Id);
}
}
}
Then use the parameters in the Productc0ntroller to pass in the iproductrepository:
namespacePattern.DI.MVC.Controllers
{
Public classProductcontroller:apicontroller
{
Private ReadOnlyIproductrepository productrepository;
PublicProductcontroller (Iproductrepository productrepository)
{
This. productrepository = Productrepository;
}
PublicIenumerable<product> Get ()
{
returnProductrepository.getall ();
}
PublicProduct Get (intId
{
returnProductrepository.getbyid (ID);
}
}
}
This example uses constructor injection, and you can also use the method of the set-up injection, where the ASP. NET WEB API creates the controller after mapping the route for the request, and now he doesn't know any details about iproductrepository, which is resolved through the API dependency.
ASP. NET Web API Dependency Parser
The ASP. NET Web API defines a idependencyresolever used to parse a dependent project, the following is the definition of this interface:
Public Interface Idependencyresolver:idependencyscope, IDisposable
{
Idependencyscope BeginScope ();
}
Public Interface Idependencyscope:idisposable
{
Object GetService (Type servicetype);
ienumerable<Object> GetServices (Type servicetype);
}
There are two methods of this interface
- GetService creates an instance for a type;
- GetServices creating an instance collection for a specific type
This interface inherits from Idependencyscope and adds the BeginScope method, which is discussed next in this article.
When the ASP. NET WEB API creates a controller instance, it first calls Idependencyresolver's GetService method, returns a controller instance, You can use an extended hook to create a controller and resolve dependencies. If the GetService method returns null,asp.net the Web API will look for a parameterless constructor.
Using Unity to resolve dependencies
While you can start writing a idenpendencyresolver implementation from scratch, this interface has been designed to be a bridge between the ASP and IOC tools.
The IOC container is a build for managing dependent projects, where you can register types, create objects when used, and IOC will easily resolve dependent relationships automatically, and many IOC containers allow you to control the object's life cycle.
First install unity in the project using the NuGet package Manage console, the introduction to unity can be found here for details.
Install-package Unity
The following is an implementation of idependencyresolver using the Unity container:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingsystem.web;
usingMicrosoft.Practices.Unity;
usingSystem.Web.Http.Dependencies;
namespacePattern.DI.MVC.Models
{
Public classUnityresolver:idependencyresolver
{
protectedIunitycontainer container;
PublicUnityresolver (Iunitycontainer Container)
{
if(Container = =NULL)
{
Throw NewArgumentNullException ("Container");
}
This. container = container;
}
Public ObjectGetService (Type servicetype)
{
Try
{
returnContainer. Resolve (servicetype);
}
Catch(resolutionfailedexception)
{
return NULL;
}
}
Publicienumerable<Object> getservices (Type servicetype)
{
Try
{
returnContainer. ResolveAll (servicetype);
}
Catch(resolutionfailedexception)
{
return Newlist<Object> ();
}
}
PublicIdependencyscope BeginScope ()
{
var child = container. Createchildcontainer ();
return NewUnityresolver (child);
}
Public voidDispose ()
{
Container. Dispose ();
}
}
}
Configuring dependency resolution
The dependency parser is set on the Dependencyresolver property in the global Httpconfiguration object. The following code uses unity to register the Iproductrepository interface and creates a unityresolver that modifies the Register method in App_start/webapiconfig.cs
namespacePattern.DI.MVC
{
Public Static classWebapiconfig
{
Public Static voidRegister (httpconfiguration config)
{
var container =NewUnityContainer ();
Container. Registertype<iproductrepository, productrepository> ();
Config. Dependencyresolver =NewUnityresolver (container);
Config. Routes.maphttproute (
Name"Defaultapi",
Routetemplate:"Api/{controller}/{id}",
DefaultsNew{id = routeparameter.optional}
);
}
}
}
When finished, the test API returns data
Original address: Http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver