前言

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

本文主要来介绍在Asp.Net Web API使用Web API的Decpendency Resolver在控制器中如何注入依赖。

本文使用VS2013。本文的示例代码下载链接为http://pan.baidu.com/s/1BvFTs

为什么要使用Dependency Resolver

一个dependency 其实就是一个对象或者另外一个对象需要的一个接口。例如,在Asp.Net Web API 2第二课——CRUD操作 http://www.cnblogs.com/aehyok/p/3434578.html中,我们定义了一个ProductsController的类,这个类需要一个IProductRepository 的实例,这个实现看起来像这样:

public class ProductsController : ApiController
{
private static IProductRepository repository = new ProductRepository(); // Controller methods not shown.
}

这不是最好的设计,因为对于调用创建的ProductRepository 是通过在控制器中硬编码的方式实现的。如果要使用IProductRepository的不同实例,我们将需要在ProductRepository中改变代码。如果ProductsController不依赖于任何具体实例的IProductRepository那会是比较好的。

Dependency injection解决了这个问题。在Dependency injection中,对象是不会负责创建自己的依赖项的。相反,当你创建一个对象,注入这个依赖的时候是通过构造函数参数或者setter方法。

这里是ProductsController中修改后的实现代码:

public class ProductsController : ApiController
{
private readonly IProductRepository repository; public ProductsController(IProductRepository repository)
{
if (repository == null)
{
throw new ArgumentNullException("repository");
}
this.repository = repository;
}

这样是比较好的。现在可以切换到另外一个IProductRepository 的实例,而不用触及到ProductsController的实现。

但是,在Asp.Net Web API中,你不能直接的创建一个控制器。相反,这个框架给你创建一个控制器,而且它并不知道IProductRepository 的相关信息。这个框架也只能通过调用无参数的构造函数来创建你的控制器。

就在这个时候dependency resolver来了。dependency resolver的工作就是创建这个框架所需要的对象,包含congtrollers对象。通过提供一个自定义的dependency resolver,你可以代表框架来创建控制器实例。

一个简单的dependency resolver

下面的代码展示了一个简单的dependency resolver。这个代码主要只是展示了在Web API中依赖注入如何工作的。之后,我们将看到怎样来合并一个Ioc的容器。

class SimpleContainer : IDependencyResolver
{
static readonly IProductRepository respository = new ProductRepository(); public IDependencyScope BeginScope()
{
// This example does not support child scopes, so we simply return 'this'.
return this;
} public object GetService(Type serviceType)
{
if (serviceType == typeof(ProductsController))
{
return new ProductsController(respository);
}
else
{
return null;
}
} public IEnumerable<object> GetServices(Type serviceType)
{
return new List<object>();
} public void Dispose()
{
// When BeginScope returns 'this', the Dispose method must be a no-op.
}
}

一个 dependency resolver实现了这个IDependencyResolver 接口。这个IDependencyResolver  接口继承了另外的两个接口IDependencyScope 、IDisposable。

namespace System.Web.Http.Dependencies
{
public interface IDependencyResolver : IDependencyScope, IDisposable
{
IDependencyScope BeginScope();
} public interface IDependencyScope : IDisposable
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
}

IDependencyScope 接口定义了两个方法:

  • GetService: 创建一个指定类型的实例
  • GetServices: 创建一个指定类型的集合对象

对于控制器,这个框架调用 GetService来获得控制器的单个实例。这就是我们简单的容器创建控制器和注入repository

对于你的dependency resolver不处理的任何类型,GetService 会返回null,GetServices 也会返回一个空的集合对象,尤其是,别抛出一个未知类型的异常。

这个IDependencyResolver 接口继承了IDependencyScope ,添加了一个方法:

  • BeginScope: 创建一个嵌套的范围

之后,我们将来讨论嵌套的范围内如何来管理我们对象的生命周期。现在,BeginScope 方法的实现我们简单的返回一个this。

Setting the Dependency Resolver

现在在Web API全局配置对象中来设置Dependency Resolver。

主要是在Global.asax这个文件当中。然后在Application_Start 方法中,将GlobalConfiguration.Configuration.DependencyResolver设置为你的Dependency Reslover。

public class WebApiApplication : System.Web.HttpApplication
{
void ConfigureApi(HttpConfiguration config)
{
config.DependencyResolver = new SimpleContainer();
} protected void Application_Start()
{
ConfigureApi(GlobalConfiguration.Configuration); // ...
}
}

那么现在你可以正常运行程序了。

范围和对象声明周期

控制器被创建的每个请求。为了帮助管理对象的声明周期,IDependencyResolver 使用了IDisposable接口。被添加到HttpConfiguration 上的dependency resolver对象拥有全局的范围。当框架创建一个新的控制器实例的时候,它调用IDependencyResolver.BeginScope。这个方法返回一个IDependencyScope 。这个框架在IDependencyScope 上调用GetService 去获得这个控制器。当框架处理完这个请求的时候,它在子范围中调用Dispose 。你能通过Dispose 方法来释放控制器的依赖。

Dependency Injection with IoC Containers

一个Ioc容器就是一个软件组件,它负责创建依赖。Ioc容器为依赖注入提供公共的框架。如果你使用一个Ioc容器,你不需要在代码中直接连同对象,几个开源的.Net Ioc容器是可以利用的,例如Autofac, Castle Windsor, Ninject, Spring.NET, StructureMap 等等。

下面的例子我们来使用Unity,这个Ioc容器是由Microsoft patterns & practices开发的。

namespace ProductStore
{
using System;
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Dependencies;
using Microsoft.Practices.Unity; class ScopeContainer : IDependencyScope
{
protected IUnityContainer container; public ScopeContainer(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
} public object GetService(Type serviceType)
{
if (container.IsRegistered(serviceType))
{
return container.Resolve(serviceType);
}
else
{
return null;
}
} public IEnumerable<object> GetServices(Type serviceType)
{
if (container.IsRegistered(serviceType))
{
return container.ResolveAll(serviceType);
}
else
{
return new List<object>();
}
} public void Dispose()
{
container.Dispose();
}
} class IoCContainer : ScopeContainer, IDependencyResolver
{
public IoCContainer(IUnityContainer container)
: base(container)
{
} public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new ScopeContainer(child);
}
}
}

这个ScopeContainer 类实现了IDependencyScope 代表了一个子范围。这个IoCContainer 类实现了全局范围内的依赖解析。并在BeginScope 方法中创建一个新的ScopeContainer对象。这个Unity 容器也有一个子容器的概念。因为我们可以用Unity 的子容器来初始化ScopeContainer 。这个ScopeContainer.Dispose方法释放了Unity的子容器。

下面的代码用Unity注册了controller和repository,然后设置Dependency resolver.

void ConfigureApi(HttpConfiguration config)
{
var unity = new UnityContainer();
unity.RegisterType<ProductsController>();
unity.RegisterType<IProductRepository, ProductRepository>(
new HierarchicalLifetimeManager());
config.DependencyResolver = new IoCContainer(unity);
}

每次HTTP请求的时候Web API 控制器被创建,然后请求被处理之后控制器被释放。

现在同样可以运行了。

总结

对依赖注入的研究,还没有那么深入,只知道简单的怎么用。

对于文中

    public IDependencyScope BeginScope()
{
// This example does not support child scopes, so we simply return 'this'.
return this;
}

如果不适用this,那么其他还可以使用什么,还有待进一步的深入。之后自己还要对依赖Unity的依赖注入进行研究。不过感觉好像没MEF那么好用。

本文的参考链接为http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

本文以同步到Web API系列导航中 http://www.cnblogs.com/aehyok/p/3446289.html

本文的示例代码下载链接为http://pan.baidu.com/s/1BvFTs

Asp.Net Web API 2第十一课——在Web API中使用Dependency Resolver的更多相关文章

  1. Web API中使用Dependency Resolver

    Web API中使用Dependency Resolver 前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyo ...

  2. Asp.Net Web API 2(入门)第一课

    Asp.Net Web API 2(入门)第一课   前言 Http不仅仅服务于Web Pages.它也是一个创建展示服务和数据的API的强大平台.Http是简单的.灵活的.无处不在的.你能想象到几乎 ...

  3. Asp.Net Web API 2第八课——Web API 2中的属性路由

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 路由就是Web API如何 ...

  4. Kali Linux Web 渗透测试视频教程—第十一课-扫描、sql注入、上传绕过

    Kali Linux Web 渗透测试视频教程—第十一课-扫描.sql注入.上传绕过 文/玄魂 原文链接:http://www.xuanhun521.com/Blog/2014/10/25/kali- ...

  5. 【ASP.NET Web API教程】2.4 创建Web API的帮助页面

    原文:[ASP.NET Web API教程]2.4 创建Web API的帮助页面 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 2.4 ...

  6. 【ASP.NET Web API教程】2 创建各种Web API

    原文 [ASP.NET Web API教程]2 创建各种Web API Chapter 2: Creating Web APIs第2章 创建各种Web API 本文引自:http://www.asp. ...

  7. 【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

    HTTP is not just for serving up web pages. It's also a powerful platform for building APIs that expo ...

  8. [转]【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

    本文转自:https://www.cnblogs.com/inday/p/6288707.html HTTP is not just for serving up web pages. It’s al ...

  9. 【ASP.NET Web API教程】2.4 创建Web API的帮助页面[转]

    注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 2.4 Creating a Help Page for a Web API2.4 创建W ...

随机推荐

  1. js动态生成input指定My97DatePicker时间问题

    js生成的input指定onclick时间: 以下1.2为错误: onclick="WdatePicker()"; onclick=WdatePicker(); 若指定到windo ...

  2. 8.11 CSS知识点4

    边框样式 1.边框宽度 border-width:medium | thin | thick | length border-top-width  设置上边框宽度 border-bottom-widt ...

  3. DIOCP之注册编码解码器与ClientContext

    FTcpServer.registerCoderClass(TIOCPStreamDecoder, TIOCPStreamEncoder);//注册编码器与解码器 FTcpServer.registe ...

  4. android笔记:ViewPager实现界面的滑动

    最近在学习ViewPager实现界面的滑动,拜读了郭神的博客文章,并抽取归纳了自己对ViewPager的理解. ViewPager实现界面滑动的步骤如下: 1.在xml布局内加入控件android.s ...

  5. ASP.NET ZERO 学习 事件总线

    用于注册和触发客户端的全局事件. 介绍 Pub/sub事件模型广泛用于客户端,ABP包含了一个简单的全局事件总线来 注册并 触发事件. 注册事件 可以使用abp.event.on来注册一个全局事件.一 ...

  6. 转:pack URI in WPF

    一开始看到WPF里面经常用如下语句来构造资源文件Uri: Uri uri = new Uri("/AssemblyName;component/image.png"); 我还以为这 ...

  7. Linux上安装php

    1.安装mysql  http://blog.csdn.net/wy3552128/article/details/8143686 2.安装配置Apache  http://blog.csdn.net ...

  8. Z - Fighting 和 Depth-bias

    Depth-bias操作在clipping之后进行实施,所以depth-bias对几何clipping没有影响. 另外需要注意的是:对一个给定体元(primitive),bias值是一个常量,在进行差 ...

  9. GATK使用说明-GRCh38(Genome Reference Consortium)(二)

    Reference Genome Components 1. GRCh38 is special because it has alternate contigs that represent pop ...

  10. ReferenceQueue的使用

    转:http://www.iflym.com/index.php/java-programe/201407140001.html 1 何为ReferenceQueue 在java的引用体系中,存在着强 ...