Asp.Net Web API 2第十一课——在Web API中使用Dependency Resolver

前言

阅读本文之前,您也可以到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

时间: 2024-08-05 16:21:16

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

VB API 之 第十一课 绘制矩形

先来介绍几个画矩形的函数: DrawFocusRect():画一个焦点矩形:Rectangle():用当前选定的画笔描绘矩形,并用当前选定的画刷填充:DrawEdge():用指定的样式描绘一个矩形的边框:RoundRect():用当前选定的画笔画一个圆角矩形,并用当前选定的画刷填充. 今天用的是DrawFocusRect()函数,函数原型如下 Private Declare Function DrawFocusRect Lib "user32" Alias "DrawFocu

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

参考页面: http://www.yuanjiaocheng.net/webapi/web-api-gaisu.html http://www.yuanjiaocheng.net/webapi/create-web-api-proj.html http://www.yuanjiaocheng.net/webapi/test-webapi.html http://www.yuanjiaocheng.net/webapi/web-api-controller.html http://www.yuan

Asp.Net Web API 2第十课——使用OWIN自承载Web API

前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本教程主要来展示在控制台应用程序中如何通过OWIN来承载Web API. Open Web Interface for .NET (OWIN)在Web服务器和Web应用程序之间建立一个抽象层.OWIN将网页应用程序从网页服务器分离出来,然后将应用程序托管于OWIN的程序而离开IIS之外. 本文仍将使用VS2013. 本文的示

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

参考页面: http://www.yuanjiaocheng.net/CSharp/csharprumenshili.html http://www.yuanjiaocheng.net/entity/mode-first.html http://www.yuanjiaocheng.net/entity/database-first.html http://www.yuanjiaocheng.net/entity/choose-development-approach.html http://ww

【翻译】在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 expose services and data. HTTP is simple, flexible, and ubiquitous. Almost any platform that you can think of has an HTTP library, so HTTP services can re

水煮 ASP.NET Web API(1-2)在 WebForm 应用程序中添加 ASP.NET Web API

问题 怎么样将 Asp.Net Web Api 加入到 Asp.Net Web From 应用程序中 解决方案 在 Visual Studio 2013 中,创建新的 Web From,可以直接在"新建 ASP.NET 项目" 创建项目向导中,勾选 ASP.NET Web API ,将其加入进来.如图 1-2 所示. 图 1-2. 在Asp.NET 项目向导,同时选中 Web Form 和 Web API 因为可以通过 NuGet 添加 ASP.NET Web API ,所以使用&qu

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

Kali Linux Web 渗透测试视频教程—第十一课-扫描.sql注入.上传绕过 文/玄魂 原文链接:http://www.xuanhun521.com/Blog/2014/10/25/kali-linux-web-%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B%E7%AC%AC%E5%8D%81%E4%B8%80%E8%AF%BE-%E6%89%AB%E6%8F%8Fsql%E6%B3%A8%

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

注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 2.4 Creating a Help Page for a Web API2.4 创建Web API帮助页面 本文引自:http://www.asp.net/web-api/overview/creating-web-apis/creating-a-help-page-for-a-web-api By Mike Wasson | August 3, 2012作者:Mike Wasson

ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十一) 代码重构使用反射工厂解耦

前言 自从此博客发表以及代码开源以来,得到了许多人的关注.也没许多吧,反正在我意料之外的.包括几位大牛帮我做订阅号推广,真的很感谢他们.另外,还有几个高手给我提了一些架构上的问题.其实本身这个项目是没有做什么架构设计的.只是简单分了分层.不过我在经过仔细思考之后决定对项目架构做些调整,当然在我的技术范围之内,我相信还会有第二次,第三次甚至更多重构,我希望把他变得更加完美. 重构思路 对于重构思路,我首先想到的是,让程序能够支持多种数据库,比如我现在用的是SQLServer,而好多朋友用MySQL