当前位置: 移动技术网 > IT编程>开发语言>.net > webapi中如何使用依赖注入

webapi中如何使用依赖注入

2017年12月08日  | 移动技术网IT编程  | 我要评论

将军大人非礼勿靠近,不能分手的分手歌词,泉州金改

本篇将要和大家分享的是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; }
 }

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

public interface iblogsreposity
 {
  /// <summary>
  /// 获取博客信息
  /// </summary>
  /// <param name="ntask"></param>
  /// <returns></returns>
  task<ienumerable<moblog>> getblogs(int ntask);
 }

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

public class bokeyuan : iblogsreposity
 {
  public async task<ienumerable<moblog>> getblogs(int ntask)
  {
   var blogs = new list<moblog>();
   try
   {
    //开启ntask个任务,读取前ntask页信息
    task<ienumerable<moblog>>[] tasks = new task<ienumerable<moblog>>[ntask];
    for (int i = 1; i <= tasks.length; i++)
    {
     tasks[i - 1] = await task.factory.startnew<task<ienumerable<moblog>>>((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 name="npage">页数</param>
  /// <returns></returns>
  async task<ienumerable<moblog>> 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>[^<]+)<\\/a>[^=]+=[^=]+=\"(?<hurl>http://(\\w|\\.|\\/)+)[^>]+>[^\\/]+\\/\\/(?<hphoto>[^\"]+)[^<]+<\\/a>(?<bdes>[^<]+)[^\"]+[^=]+=[^>]+>(?<hname>[^<]+)[^2]+(?<bcreatetime>[^<]+)[^\\(]+\\((?<bcomment>\\d+)[^\\(]+\\((?<bread>\\d+)");
    if (matches.count <= 0) { return blogs; }
    foreach (match item in matches)
    {
     blogs.add(new moblog
     {
      title = item.groups["title"].value.trim(),
      nickname = item.groups["hname"].value.trim(),
      des = item.groups["bdes"].value.trim(),
      zannum = convert.toint32(item.groups["hzan"].value.trim()),
      readnum = convert.toint32(item.groups["bread"].value.trim()),
      commitenum = convert.toint32(item.groups["bcomment"].value.trim()),
      createtime = convert.todatetime(item.groups["bcreatetime"].value.trim()),
      headurl = "http://" + item.groups["hphoto"].value.trim(),
      blogurl = item.groups["hurl"].value.trim(),
      url = item.groups["burl"].value.trim(),
     });
    }
   }
   catch (exception ex)
   {
   }
   return blogs;
  }
 }

代码分析:

1. task<ienumerable<moblog>>[] tasks = new task<ienumerable<moblog>>[ntask]作为并行任务的容器;

2. task.factory.startnew创建对应的任务

3. task.waitall(tasks, timespan.fromseconds(30));等待容器里面任务完成30秒后超时

4. 最后通过把item.result任务结果添加到集合中,返回我们需要的数据

这里解析博客内容信息用的正则表达式,这种方式在抓取一定内容上很方便;群里面有些朋友对正则有点反感,刚接触的时候觉得挺不好写的,所以一般都采用更复杂或者其他的解析方式来获取想要的内容,这里提出来主要是和这些朋友分享下正则获取数据是多么方便,很有必要学习下并且掌握常规的用法,这也是一种苦尽甘来的体验吧哈哈;

好了咋们创建一个webapi项目取名为 stage.api ,使用她自动生成的 valuescontroller 文件里面的get方法接口来调用咋们上面实现的博客抓取方法,代码如下:

// get api/values
  public async task<ienumerable<moblog>> get(int task = 6)
  {
   task = task <= 0 ? 6 : task;
   task = task > 50 ? 50 : task;
   iblogsreposity _reposity = new bokeyuan();
   return await _reposity.getblogs(task);
  }

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

» ioc框架ninject的使用

首先,我们要使用ninject需要使用nuget下载安装包,这里要注意的是ninject版本比较多,需要选择合适自己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;
  }
 }

这里要注意的是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());
  }
 }

这里能够看到 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<moblog>> get(int task = 6)
  {
   task = task <= 0 ? 6 : task;
   task = task > 50 ? 50 : task;
   return await _reposity.getblogs(task);
  }

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

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

 //ninject ioc
 config.dependencyresolver = ninjectresolvercontainer.current;

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

» ioc框架unity的使用

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

我们再同样创建个自定义容器类 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 name="servicetype"></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;
   }
  }
 }

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

 //unity ioc
unityconfig.registercomponents();

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

public static class unityconfig
 {
  public static void registercomponents()
  {
   var container = new unitycontainer();
   container.registertype<iblogsreposity, bokeyuan>();
   // var lifetimeoption = new containercontrolledlifetimemanager();
   //container.registerinstance<iblogsreposity>(new bokeyuan(), lifetimeoption);
   globalconfiguration.configuration.dependencyresolver = new unityresolvercontainer(container);
  }
 }

这里展示了两种注册依赖的方式: container.registertype<iblogsreposity, bokeyuan>(); 和 container.registerinstance<iblogsreposity>(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<moblog>> get(int task = 6)
  {
   task = task <= 0 ? 6 : task;
   task = task > 50 ? 50 : task;
   return await _reposity.getblogs(task);
  }
}

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

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持移动技术网!

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网