How to use dependency injection in webapi

高洛峰
Release: 2017-02-10 17:26:27
Original
2084 people have browsed it

本篇将要和大家分享的是How to use dependency injection in webapi,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity。下面跟着小编一起来看下吧

本篇将要和大家分享的是How to use dependency injection in webapi,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity;由于快过年这段时间打算了解下vue.js,所以后面对webapi的分享文章可能会慢点更新,希望支持的朋友们多多谅解,毕竟只有不断充电学习,才能更好的适应it行业吧;本章内容希望大家喜欢,也希望各位多多扫码支持和推荐谢谢:

» Task并行任务抓取博客园首页信息

» IOC框架Ninject的使用

» IOC框架Unity的使用

下面一步一个脚印的来分享:

» Task并行任务抓取博客园首页信息

首先,咋们需要创建一个博客信息实体类 MoBlog ,实体类代码如下:

public class MoBlog
 {
  public MoBlog() { }
  /// <summary>
  /// 作者昵称
  /// </summary>
  public string NickName { get; set; }
  /// <summary>
  /// 标题
  /// </summary>
  public string Title { get; set; }
  /// <summary>
  ///该篇文字地址
  /// </summary>
  public string Url { get; set; }
  /// <summary>
  /// 描述
  /// </summary>
  public string Des { get; set; }
  /// <summary>
  /// 头像图片地址
  /// </summary>
  public string HeadUrl { get; set; }
  /// <summary>
  /// 博客地址
  /// </summary>
  public string BlogUrl { get; set; }
  /// <summary>
  /// 点赞次数
  /// </summary>
  public int ZanNum { get; set; }
  /// <summary>
  /// 阅读次数
  /// </summary>
  public int ReadNum { get; set; }
  /// <summary>
  /// 评论次数
  /// </summary>
  public int CommiteNum { get; set; }
  /// <summary>
  /// 创建时间
  /// </summary>
  public DateTime CreateTime { get; set; }
 }
Copy after login

然后,需要创建一个接口 IBlogsReposity ,并且定义一个如下代码的方法:

public interface IBlogsReposity
 {
  /// <summary>
  /// 获取博客信息
  /// </summary>
  /// <param>
  /// <returns></returns>
  Task<ienumerable>> GetBlogs(int nTask);
 }</ienumerable>
Copy after login

注意这里定义的返回类型是Task,主要作用是async异步返回博客信息,并且方便使用并行方式抓取不同页数的数据,因此这里传递了一个int类型的参数nTask(表示任务数量);好了咋们来一起看下具体实现接口的 BoKeYuan 类里面的代码:

public class BoKeYuan : IBlogsReposity
 {
  public async Task<ienumerable>> GetBlogs(int nTask)
  {
   var blogs = new List<moblog>();
   try
   {
    //开启nTask个任务,读取前nTask页信息
    Task<ienumerable>>[] tasks = new Task<ienumerable>>[nTask];
    for (int i = 1; i >>((page) =>
      {
       return GetBlogsByPage(Convert.ToInt32(page));
      }, i);
    }
    //30s等待
    Task.WaitAll(tasks, TimeSpan.FromSeconds(30));
    foreach (var item in tasks.Where(b => b.IsCompleted))
    {
     blogs.AddRange(item.Result);
    }
   }
   catch (Exception ex)
   {
   }
   return blogs.OrderByDescending(b => b.CreateTime);
  }
  /// <summary>
  /// 
  /// </summary>
  /// <param>页数
  /// <returns></returns>
  async Task<ienumerable>> GetBlogsByPage(int nPage)
  {
   var blogs = new List<moblog>();
   try
   {
    var strBlogs = string.Empty;
    using (HttpClient client = new HttpClient())
    {
     strBlogs = await client.GetStringAsync("http://www.cnblogs.com/sitehome/p/" + nPage);
    }
    if (string.IsNullOrWhiteSpace(strBlogs)) { return blogs; }
    var matches = Regex.Matches(strBlogs, "diggnum\"[^>]+>(?<hzan>\\d+)[^:]+(?<burl>http[^\"]+)[^>]+>(?<title>[^[^=]+=[^=]+=\"(?<hurl>http://(\\w|\\.|\\/)+)[^>]+>[^\\/]+\\/\\/(?<hphoto>[^\"]+)[^(?<bdes>[^]+>(?<hname>[^[^\\d+)[^\\(]+\\((?<bread>\\d+)");
    if (matches.Count <p></p>
<p>代码分析:</p>
<p>1. Task<ienumerable>>[] tasks = new Task<ienumerable>>[nTask]作为并行任务的容器;</ienumerable></ienumerable></p>
<p>2. Task.Factory.StartNew创建对应的任务</p>
<p>3. Task.WaitAll(tasks, TimeSpan.FromSeconds(30));等待容器里面任务完成30秒后超时</p>
<p>4. 最后通过把item.Result任务结果添加到集合中,返回我们需要的数据</p>
<p>这里解析博客内容信息用的正则表达式,这种方式在抓取一定内容上很方便;群里面有些朋友对正则有点反感,刚接触的时候觉得挺不好写的,所以一般都采用更复杂或者其他的解析方式来获取想要的内容,这里提出来主要是和这些朋友分享下正则获取数据是多么方便,很有必要学习下并且掌握常规的用法,这也是一种苦尽甘来的体验吧哈哈;</p>
<p>好了咋们创建一个webapi项目取名为 Stage.Api ,使用她自动生成的 ValuesController 文件里面的Get方法接口来调用咋们上面实现的博客抓取方法,代码如下:</p>
<p></p>
<pre class="brush:php;toolbar:false">// GET api/values
  public async Task<ienumerable>> Get(int task = 6)
  {
   task = task  50 ? 50 : task;
   IBlogsReposity _reposity = new BoKeYuan();
   return await _reposity.GetBlogs(task);
  }</ienumerable>
Copy after login

这里使用 IBlogsReposity _reposity = new BoKeYuan(); 来创建和调用具体的实现类,这里贴出一个线上抓取博客首页信息的地址(不要告诉dudu):http://www.php.cn/:1001/api/values?task=6;咋们来想象一下,如果这个Get方法中还需要调用其他实现了接口 IBlogsReposity 的博客抓取类,那咋们又需要手动new一次来创建对应的对象;倘若除了在 ValuesController.cs 文件中调用了博客数据抓取,其他文件还需要这抓取数据的业务,那么又会不停的new,可能有朋友就会说那弄一个工厂模式怎么样,不错这是可行的一种方式,不过这里还有其他方法能处理这种问题,比如:ioc依赖注入;因此就有了下面的分享内容。

» IOC框架Ninject的使用

首先,我们要使用ninject需要使用nuget下载安装包,这里要注意的是Ninject版本比较多,需要选择合适自己webapi的版本,我这里选择的是:

How to use dependency injection in webapi

看起来很老了哈哈,不过咋们能用就行,安装起来可能需要点时间,毕竟比较大么也有可能是网络的问题吧;安装完后咋们创建一个自定义类 NinjectResolverScope 并实现接口 IDependencyScope , IDependencyScope 对应的类库是 System.Web.Http.dll (注:由于webapi2项目自动生成时候可能勾选了mvc,mvc框架里面也包含了一个IDependencyScope,所以大家需要注意区分下),好了咋们来直接看下 NinjectResolverScope 实现代码:

/// <summary>
 /// 解析
 /// </summary>
 public class NinjectResolverScope : IDependencyScope
 {
  private IResolutionRoot root;
  public NinjectResolverScope() { }
  public NinjectResolverScope(IResolutionRoot root)
  {
   this.root = root;
  }
  public object GetService(Type serviceType)
  {
   try
   {
    return root.TryGet(serviceType);
   }
   catch (Exception ex)
   {
    return null;
   }
  }
  public IEnumerable<object> GetServices(Type serviceType)
  {
   try
   {
    return this.root.GetAll(serviceType);
   }
   catch (Exception ex)
   {
    return new List<object>();
   }
  }
  public void Dispose()
  {
   var disposable = this.root as IDisposable;
   if (disposable != null)
    disposable.Dispose();

   this.root = null;
  }
 }</object></object>
Copy after login

这里要注意的是GetService和GetServices方法必须使用  try...catch() 包住,经过多方调试和测试,这里面会执行除手动bind绑定外的依赖,还会执行几个其他非手动绑定的实例对象,这里使用try避免抛异常影响到程序(其实咋们可以在这里用代码过滤掉非手动绑定的几个实例);这里也简单说下这个 NinjectResolverScope 中方法执行的先后顺序:GetService=》GetServices=》Dispose,GetService主要用来获取依赖注入对象的实例;好了到这里咋们还需要一个自定义容器类 NinjectResolverContainer ,该类继承自上面的 NinjectResolverScope 和实现 IDependencyResolver 接口(其实细心的朋友能发现这个 IDependencyResolver 同样也继承了 IDependencyScope ),具体代码如下:

public class NinjectResolverContainer : NinjectResolverScope, IDependencyResolver
 {
  private IKernel kernel;
  public static NinjectResolverContainer Current
  {
   get
   {
    var container = new NinjectResolverContainer();
    //初始化
    container.Initing();
    //绑定
    container.Binding();
    return container;
   }
  }
  /// <summary>
  /// 初始化kernel
  /// </summary>
  void Initing()
  {
   kernel = new StandardKernel();
  }
  /// <summary>
  /// 绑定
  /// </summary>
  void Binding()
  {
   kernel.Bind<iblogsreposity>().To<bokeyuan>();
  }
  /// <summary>
  /// 开始执行
  /// </summary>
  /// <returns></returns>
  public IDependencyScope BeginScope()
  {
   return new NinjectResolverScope(this.kernel.BeginBlock());
  }
 }</bokeyuan></iblogsreposity>
Copy after login

这里能够看到 IKernel kernel = new StandardKernel(); 这代码,她们引用都来源于我们安装的Ninject包,通过调用初始化Initing()后,我们需要在Binding()方法中手动绑定我们对应需要依赖注入的实例,Ninject绑定方式有很多种这里我用的格式是: kernel.Bind().To(); 如此简单就实现了依赖注入,每次我们需要添加不同的依赖项的时候只需要在这个Binding()中使用Bind.To()即可绑定成功;好了为了验证咋们测试成功性,我们需要在apiController中使用这个依赖关系,这里我使用构造函数依赖注入的方式:

private readonly IBlogsReposity _reposity
  public ValuesController(IBlogsReposity reposity)
  {
   _reposity = reposity;
  }
  // GET api/values 
  public async Task<ienumerable>> Get(int task = 6)
  {
   task = task  50 ? 50 : task;
   return await _reposity.GetBlogs(task);
  }</ienumerable>
Copy after login

代码如上所示,我们运行下程序看下效果:

How to use dependency injection in webapi

这个时候提示了个错误“没有默认构造函数”;我们刚才使用的构造函数是带有参数的,而自定义继承的 ApiController 中有一个无参数的构造函数,根据错误提示内容完全无解;不用担心,解决这个问题只需要在 WebApiConfig.cs 中Register方法中增加如下代码:

 //Ninject ioc
 config.DependencyResolver = NinjectResolverContainer.Current;
Copy after login

这句代码意思就是让程序执行上面咋们创建的容器 NinjectResolverContainer ,这样才能执行到我能刚才写的ioc程序,才能实现依赖注入;值得注意的是 config.DependencyResolver 是webapi自带的提供的,mvc项目也有同样提供了 DependencyResolver  给我们使用方便做依赖解析;好了这次我们在运行项目可以得到如图效果:

How to use dependency injection in webapi

» IOC框架Unity的使用

首先,安装Unity和Unity.WebAPI的nuget包,我这里的版本是:

How to use dependency injection in webapi

我们再同样创建个自定义容器类 UnityResolverContainer ,实现接口 IDependencyResolver (这里和上面Ninject一样);然后这里贴上具体使用Unity实现的方法:

public class UnityResolverContainer : IDependencyResolver
 {
  private IUnityContainer _container;
  public UnityResolverContainer(IUnityContainer container)
  {
   this._container = container;
  }
  public IDependencyScope BeginScope()
  {
   var scopeContainer = this._container.CreateChildContainer();
   return new UnityResolverContainer(scopeContainer);
  }
  /// <summary>
  /// 获取对应类型的实例,注意try...catch...不能够少
  /// </summary>
  /// <param>
  /// <returns></returns>
  public object GetService(Type serviceType)
  {
   try
   {
    //if (!this._container.IsRegistered(serviceType)) { return null; }
    return this._container.Resolve(serviceType);
   }
   catch
   {
    return null;
   }
  }
  public IEnumerable<object> GetServices(Type serviceType)
  {
   try
   {
    return this._container.ResolveAll(serviceType);
   }
   catch
   {
    return new List<object>();
   }
  }
  public void Dispose()
  {
   if (_container != null)
   {
    this._container.Dispose();
    this._container = null;
   }
  }
 }</object></object>
Copy after login

 这里和使用Ninject的方式很类似,需要注意的是我们在安装Unity包的时候会自动在 WebApiConfig.cs 增加如下代码:

 //Unity ioc
UnityConfig.RegisterComponents();
Copy after login

然后同时在 App_Start 文件夹中增加 UnityConfig.cs 文件,我们打开此文件能看到一些自动生成的代码,这里我们就可以注册绑定我们的依赖,代码如:

public static class UnityConfig
 {
  public static void RegisterComponents()
  {
   var container = new UnityContainer();
   container.RegisterType<iblogsreposity>();
   // var lifeTimeOption = new ContainerControlledLifetimeManager();
   //container.RegisterInstance<iblogsreposity>(new BoKeYuan(), lifeTimeOption);
   GlobalConfiguration.Configuration.DependencyResolver = new UnityResolverContainer(container);
  }
 }</iblogsreposity></iblogsreposity>
Copy after login

这里展示了两种注册依赖的方式: container.RegisterType(); 和 container.RegisterInstance(new BoKeYuan(), lifeTimeOption); ,当然还有其他的扩展方法这里就不举例了;最后一句代码: GlobalConfiguration.Configuration.DependencyResolver = new UnityResolverContainer(container); 和我们之前Ninject代码一样,只是换了一个地方和实例化写法方式而已,各位可以仔细对比下;其实 UnityConfig.cs 里面的内容都可以移到 WebApiConfig.cs 中去,unity自动分开应该是考虑到代码内容分块来管理吧,好了同样我们使用自定义的 ValuesController 的构造函数来添加依赖:

public class ValuesController : ApiController
 {
  private readonly IBlogsReposity _reposity;
  public ValuesController(IBlogsReposity reposity)
  {
   _reposity = reposity;
  }
  // GET api/values 
  public async Task<ienumerable>> Get(int task = 6)
  {
   task = task  50 ? 50 : task;
   return await _reposity.GetBlogs(task);
  }
}</ienumerable>
Copy after login

从代码上来看,这里面Ninject和Unity的注入方式没有差异,这样能就让我们开发程序的时候两种注入方式可以随便切换了,最后来我这里提供一个使用这个webapi获取数据绑定到页面上的效果:

How to use dependency injection in webapi

For more articles related to how to use dependency injection in webapi, please pay attention to the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template