Dependency injection in ASP. NET Web API

Source: Internet
Author: User

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

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.