ASP.NET Web API中的依赖注入什么是依赖注入ASP.NET Web API依赖解析器使用Unity解析依赖配置依赖解析
什么是依赖注入
依赖,就是一个对象需要的另一个对象,比如说,这是我们通常定义的一个用来处理数据访问的存储,让我们用一个例子来解释,首先,定义一个领域模型如下:
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
- 搭建 Jenkins-2.83 服务,部署 spring boot 项目
- Spring Boot 中使用 Java API 调用 lucene
- Spring Boot 中使用 Java API 调用 Elasticsearch
- Spring Boot 中使用 公共配置
- WebView 和 JS 交互,如何将 Java 对象和 List 传值给 JS ?
- Spring Boot 中使用 LogBack 配置
- Spring Boot 中使用 RabbitMQ
- 手把手教你dubbo怎么用?
- 一步一步实现Android的MVP框架
- Base封装之我的最简MVP架构
- 请求跨域的解决方案
- 运用Kubernetes进行分布式负载测试
- Spring Cloud(五)断路器监控(Hystrix Dashboard)
- 微信技术团队的又一力作,WCDB 简单易用的数据库框架
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux 不改变目录结构移动 home 目录到新分区的操作方法
- ubuntu14.04安装opencv3.0.0的操作方法
- Linux中让alias设置永久生效的方法详解
- Centos系统下“无法打开并写入文件”问题的解决
- 如何在Linux下设置录音笔时间
- Linux下ZooKeeper分布式集群安装教程
- CentOS 6.5中利用yum搭建LNMP环境的步骤详解
- Linux下Kafka分布式集群安装教程
- Centos下升级Python及Mongodb驱动安装问题
- centOS6中使用crontab定时运行执行jar程序的脚本
- 基于cobbler 实现自动安装linux系统
- Polysh命令实现多日志查询的方法示例
- linux中启动tomcat后浏览器无法访问的解决方法
- Linux查看系统配置常用命令详解
- LNMP下提示File not found问题的解决方法