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在控制器中如何注入依赖。

前言

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

目录
相关文章
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
53 4
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
147 3
|
3天前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
22 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
|
15天前
|
开发框架 .NET 程序员
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
Autofac 是一个轻量级的依赖注入框架,专门为 .NET 应用程序量身定做,它就像是你代码中的 "魔法师",用它来管理对象的生命周期,让你的代码更加模块化、易于测试和维护
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
|
12天前
|
开发框架 .NET PHP
ASP.NET Web Pages - 添加 Razor 代码
ASP.NET Web Pages 使用 Razor 标记添加服务器端代码,支持 C# 和 Visual Basic。Razor 语法简洁易学,类似于 ASP 和 PHP。例如,在网页中加入 `@DateTime.Now` 可以实时显示当前时间。
|
1月前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
46 1
|
1月前
|
JSON API 数据格式
如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架
本文介绍了如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架,适合小型项目和微服务。文章从环境准备、创建基本Flask应用、定义资源和路由、请求和响应处理、错误处理等方面进行了详细说明,并提供了示例代码。通过这些步骤,读者可以快速上手构建自己的RESTful API。
39 2
|
2月前
|
监控 负载均衡 API
Web、RESTful API 在微服务中有哪些作用?
在微服务架构中,Web 和 RESTful API 扮演着至关重要的角色。它们帮助实现服务之间的通信、数据交换和系统的可扩展性。
51 2
|
2月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
103 9
|
2月前
|
存储 开发框架 .NET
.NET 8 实现无实体库表 API 部署服务
【10月更文挑战第12天】在.NET 8中,可通过以下步骤实现无实体库表的API部署:首先安装.NET 8 SDK及开发工具,并选用轻量级Web API框架如ASP.NET Core;接着创建新项目并设计API,利用内存数据结构模拟数据存储;最后配置项目设置并进行测试与部署。此方法适用于小型项目或临时解决方案,但对于大规模应用仍需考虑持久化存储以确保数据可靠性与可扩展性。