什么是依赖注入

依赖,就是一个对象需要的另一个对象,比如说,这是我们通常定义的一个用来处理数据访问的存储,让我们用一个例子来解释,首先,定义一个领域模型如下:

namespace Pattern.DI.MVC.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}

然后是一个用于实例的简单存储类:

namespace Pattern.DI.MVC.Models
{
public class ProductContext
{
public List<Product> Products { get; internal set; }

public ProductContext()
{
Products.Add(new Product() {Id = 1, Name = "苍阿姨", Price = 100});
Products.Add(new Product() {Id = 2, Name = "武藤奶奶", Price = 200});
Products.Add(new Product() {Id = 3, Name = "小泽姐姐", Price = 300});
}
}

public class ProductRepository
{
private ProductContext context=new ProductContext();

public IEnumerable<Product> GetAll()
{
return context.Products;
}

public Product GetById(int id)
{
return context.Products.FirstOrDefault(p => p.Id == id);
}
}
}

现在,我们定义一个ASP.NET Web API控制器来支持对Product实体集的GET请求:

namespace Pattern.DI.MVC.Controllers
{
public class ProductController : ApiController
{
private readonly ProductRepository productRepository=new ProductRepository();

public IEnumerable<Product> Get()
{
return productRepository.GetAll();
}

public Product Get(int id)
{
return productRepository.GetById(id);
}
}
}

现在注意到,这个控制器依赖了“ProductRepository”这个类,我们在类中实例化了ProductRepository,这就是设计的“坏味道”了,因为如下几个原因:

  • 假如你想要使用另外一个实现替换ProductRepository,你还要去修改ProductController类;
  • 假如ProductRepository存在依赖,你必须在ProductController中配置他们,对于一个拥有很多控制器的大项目来说,你就配置工作将深入到任何可能的地方;
  • 这是很难去做单元测试的因为控制器中硬编码了对数据库的查询,对于一个单元测试,你可以在没有确切设计之前,使用一个仿制的桩存储体。

我们可以使用注入一个ProductRepsoitory来解决这个问题,首先重构ProductRepository的方法到一个接口中:

namespace Pattern.DI.MVC.Models
{

public interface IProductRepository
{
IEnumerable<Product> GetAll();
Product GetById(int id);
}

public class ProductRepository:IProductRepository
{
private ProductContext context = new ProductContext();

public IEnumerable<Product> GetAll()
{
return context.Products;
}

public Product GetById(int id)
{
return context.Products.FirstOrDefault(p => p.Id == id);
}
}
}

 
然后在ProductC0ntroller中使用参数传入IProductRepository:
namespace Pattern.DI.MVC.Controllers
{
public class ProductController : ApiController
{
private readonly IProductRepository productRepository;

public ProductController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}

public IEnumerable<Product> Get()
{
return productRepository.GetAll();
}

public Product Get(int id)
{
return productRepository.GetById(id);
}
}
}

这个示例使用了构造器注入,你同样可以使用设置器注入的方式,ASP.NET Web API在为请求映射了路由之后创建控制器,而且现在他不知道任何关于IProductRepository的细节,这是通过API依赖器解析到的。

ASP.NET Web API依赖解析器

ASP.NET Web API定义了一个IDependencyResolever用来解析依赖项目,以下是这个接口的定义:

public interface IDependencyResolver : IDependencyScope, IDisposable
{
IDependencyScope BeginScope();
}

public interface IDependencyScope : IDisposable
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}

这个接口有两个方法

  • GetService为一个类型创建一个实例;
  • GetServices为一个特定的类型创建一个实例集合

这个接口继承自IDependencyScope并且添加了BeginScope方法,在这篇文章接下来将讨论这个方法。

当ASP.NET Web API创建一个controller实例的时候,它首先调用IDependencyResolver的GetService方法,传回一个Controller实例,你可以使用一个扩展的钩子去创建控制器并且解析依赖。假如GetService方法返回NULL,ASP.NET Web API将查找一个无参的构造函数。

使用Unity解析依赖

虽然你可以重头开始写一个IDenpendencyResolver的实现,但是这个接口已经设计了可以作为ASP.NET Web API和IoC工具的桥梁。

IoC容器是一个用来管理依赖项目的组建,你可以在其中注册类型,在使用的时候创建对象,IoC容易自动解析出依赖的关系,许多IoC容器允许你在对象的生命周期中进行控制。

首先在项目中使用NuGet Package Manage Console安装Unity,关于Unity的介绍可以点击这里查看详细。

Install-Package Unity

以下是一个使用Unity容器对IDependencyResolver的实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Practices.Unity;
using System.Web.Http.Dependencies;

namespace Pattern.DI.MVC.Models
{
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;

public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}

public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}

public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}

public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}

public void Dispose()
{
container.Dispose();
}
}
}

配置依赖解析

在全局的HttpConfiguration对象中DependencyResolver属性上设置依赖解析器,以下的代码使用Unity注册IProductRepository接口并且创建一个UnityResolver,修改App_Start/WebApiConfig.cs中的Register方法


namespace Pattern.DI.MVC
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>();
config.DependencyResolver = new UnityResolver(container);

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}

至此完工,测试Api返回数据

原文地址:http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

ASP.NET Web API中的依赖注入的更多相关文章

  1. 如何在 ASP.Net Web Forms 中使用依赖注入

    依赖注入技术就是将一个对象注入到一个需要它的对象中,同时它也是控制反转的一种实现,显而易见,这样可以实现对象之间的解耦并且更方便测试和维护,依赖注入的原则早已经指出了,应用程序的高层模块不依赖于低层模 ...

  2. 使用Autofac在ASP.NET Web API上实现依赖注入

    在ASP.NET Web API里使用Autofac 1.通过NuGet安装Autofac.WebApi(当时安装的是Autofac 3.1.0) PM > Install-Package Au ...

  3. ASP.NET Web API 中的返回数据格式以及依赖注入

    本篇涉及ASP.NET Web API中的返回数据合适和依赖注入. 获取数据 public IEnumerable<Food> Get() { var results = reop.Get ...

  4. 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建

    目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建 通过上面的介绍我们知道利用HttpControllerSelector可以根据 ...

  5. ASP.NET Web API中的Controller

    虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...

  6. 在ASP.NET Web API中使用OData

    http://www.alixixi.com/program/a/2015063094986.shtml 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在A ...

  7. ASP.NET Web API 中的异常处理(转载)

    转载地址:ASP.NET Web API 中的异常处理

  8. 【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化

    谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予“推荐”.但前几天有人询 ...

  9. Asp.Net Web API 2第十三课——ASP.NET Web API中的JSON和XML序列化

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文描述ASP.NET W ...

随机推荐

  1. JAVA开发--U盘EXE恢复工具

    原理比较简单,在学校机房U盘总被感染,写一个工具来方便用 package com.udiskrecover; import java.awt.Container; import java.awt.Fl ...

  2. nyoj325 zb的生日(DFS)

    zb的生日 时间限制:3000 ms  |  内存限制:65535 KB 难度:2   描述 今天是阴历七月初五,acm队员zb的生日.zb正在和C小加.never在武汉集训.他想给这两位兄弟买点什么 ...

  3. java中类名.class、实例.getclass()区别

    import java.util.HashSet; import java.util.Iterator; /** * Created by GOD on 2016/1/23. * Class对象的生成 ...

  4. netbeans环境的建立

    这是一个简单的实验,熟悉NetBeans的IDE环境的开发 首先下载一个NetBeans,可以在官网上下https://netbeans.org/downloads/index.html 要装NetB ...

  5. 64位Eclipse运行时提示“Failed to load the JNI shared library \Java\jre6\bin\client\jvm.dll”的一个解决方案

    系统安装的32位JREE,64位eclipse无法识别,解决方案:下载安装64位jdk即可.

  6. iOS - AVPlayer 音视频播放

    前言 NS_CLASS_AVAILABLE(10_7, 4_0) @interface AVPlayer : NSObject @available(iOS 4.0, *) public class ...

  7. java运行内存分配图(转)

    Java的内存分配   Java程序运行时的内存结构分成:方法区.栈内存.堆内存.本地方法栈几种.    方法区    存放装载的类数据信息,包括:基本信息:每个类的全限定名.每个类的直接超类的全限定 ...

  8. Python学习(14)模块一

    目录 Python 模块 import语句 from ... import 语句 from ... import * 语句 定位模块 PYTHONPATH变量 命名空间和变量 dir()函数. glo ...

  9. (七)C语言中的void 和void 指针类型

    许多初学者对C中的void 和void 的指针类型不是很了解.因此常常在使用上出现一些错误,本文将告诉大家关于void 和void 指针类型的使用方法及技巧. 1.首先,我们来说说void 的含义: ...

  10. Jump Game II

    Description: Given an array of non-negative integers, you are initially positioned at the first inde ...