zoukankan      html  css  js  c++  java
  • 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

    原文地址:http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

  • 相关阅读:
    ef unitofwork 主从表更新
    自己写的enum转换的一个扩展,
    最近在做政务项目,此种项目,本来并不大,主要原因呢,就是要理好业务需要。
    sql server创建外键,子母表,级联删除。
    js querySelector与getElementById
    写一个system.data.entity的simpledatarepo,实现crudq这些功能,不需要引入entityframework,直接可以使用,用到objectset
    无法更新 EntitySet“W_ReceiveData”,因为它有一个 DefiningQuery,而 <ModificationFunctionMapping> 元素中没有支持当前操作的 <InsertFunction> 元素。
    Kubernetes v1.17 版本解读 | 云原生生态周报 Vol. 31
    开放下载 | 《Knative 云原生应用开发指南》开启云原生时代 Serverless 之门
    有了 serverless,前端也可以快速开发一个 Puppeteer 网页截图服务
  • 原文地址:https://www.cnblogs.com/xiaoyaojian/p/3718537.html
Copyright © 2011-2022 走看看