• ASP.NET Web API中的依赖注入


    什么是依赖注入

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

    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返回数据

    QQ截图20140509112520 QQ截图20140509112507

  • 相关阅读:
    Treap 树堆 容易实现的平衡树
    (转)Maven实战(二)构建简单Maven项目
    (转)Maven实战(一)安装与配置
    根据请求头跳转判断Android&iOS
    (转)苹果消息推送服务器 php 证书生成
    (转)How to renew your Apple Push Notification Push SSL Certificate
    (转)How to build an Apple Push Notification provider server (tutorial)
    (转)pem, cer, p12 and the pains of iOS Push Notifications encryption
    (转)Apple Push Notification Services in iOS 6 Tutorial: Part 2/2
    (转)Apple Push Notification Services in iOS 6 Tutorial: Part 1/2
  • 原文地址:https://www.cnblogs.com/lyl6796910/p/3721951.html
Copyright © 2020-2023  润新知