webapi - 使用依赖注入

简介:

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

 View Code

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

复制代码

1   public interface IBlogsReposity2     {3         /// <summary>4         /// 获取博客信息5         /// </summary>6         /// <param name="nTask"></param>7         /// <returns></returns>8         Task<IEnumerable<MoBlog>> GetBlogs(int nTask);9     }

复制代码

注意这里定义的返回类型是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方法接口来调用咋们上面实现的博客抓取方法,代码如下:

复制代码

1  // GET api/values2         public async Task<IEnumerable<MoBlog>> Get(int task = 6)3         {4             task = task <= 0 ? 6 : task;5             task = task > 50 ? 50 : task;6 7             IBlogsReposity _reposity = new BoKeYuan();8             return await _reposity.GetBlogs(task);9         }

复制代码

这里使用 IBlogsReposity _reposity = new BoKeYuan(); 来创建和调用具体的实现类,这里贴出一个线上抓取博客首页信息的地址(不要告诉dudu):http://www.lovexins.com:1001/api/values?task=6;咋们来想象一下,如果这个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 实现代码:

复制代码

 1 /// <summary> 2     ///  解析 3     /// </summary> 4     public class NinjectResolverScope : IDependencyScope 5     { 6  7         private IResolutionRoot root; 8  9         public NinjectResolverScope() { }10 11         public NinjectResolverScope(IResolutionRoot root)12         {13             this.root = root;14         }15 16         public object GetService(Type serviceType)17         {18             try19             {20                 return root.TryGet(serviceType);21             }22             catch (Exception ex)23             {24 25                 return null;26             }27 28         }29 30         public IEnumerable<object> GetServices(Type serviceType)31         {32             try33             {34                 return this.root.GetAll(serviceType);35             }36             catch (Exception ex)37             {38                 return new List<object>();39             }40         }41 42         public void Dispose()43         {44             var disposable = this.root as IDisposable;45             if (disposable != null)46                 disposable.Dispose();47 48             this.root = null;49         }50     }

复制代码

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

复制代码

 1 public class NinjectResolverContainer : NinjectResolverScope, IDependencyResolver 2     { 3  4         private IKernel kernel; 5  6         public static NinjectResolverContainer Current 7         { 8             get 9             {10 11                 var container = new NinjectResolverContainer();12 13                 //初始化14                 container.Initing();15                 //绑定16                 container.Binding();17 18                 return container;19             }20         }21 22         /// <summary>23         /// 初始化kernel24         /// </summary>25         void Initing()26         {27 28             kernel = new StandardKernel();29         }30 31         /// <summary>32         /// 绑定33         /// </summary>34         void Binding()35         {36 37             kernel.Bind<IBlogsReposity>().To<BoKeYuan>();38         }39 40         /// <summary>41         /// 开始执行42         /// </summary>43         /// <returns></returns>44         public IDependencyScope BeginScope()45         {46 47             return new NinjectResolverScope(this.kernel.BeginBlock());48         }49     }

复制代码

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

复制代码

 1 private readonly IBlogsReposity _reposity; 2  3         public ValuesController(IBlogsReposity reposity) 4         { 5             _reposity = reposity; 6         } 7  8         // GET api/values   9         public async Task<IEnumerable<MoBlog>> Get(int task = 6)10         {11             task = task <= 0 ? 6 : task;12             task = task > 50 ? 50 : task;13             return await _reposity.GetBlogs(task);14         }

复制代码

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

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

1 //Ninject ioc2    config.DependencyResolver = NinjectResolverContainer.Current;

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

 

 IOC框架Unity的使用

 

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

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

复制代码

 1 public class UnityResolverContainer : IDependencyResolver 2     { 3         private IUnityContainer _container; 4  5         public UnityResolverContainer(IUnityContainer container) 6         { 7             this._container = container; 8         } 9 10         public IDependencyScope BeginScope()11         {12             var scopeContainer = this._container.CreateChildContainer();13             return new UnityResolverContainer(scopeContainer);14         }15 16         /// <summary>17         /// 获取对应类型的实例,注意try...catch...不能够少18         /// </summary>19         /// <param name="serviceType"></param>20         /// <returns></returns>21         public object GetService(Type serviceType)22         {23             try24             {25                 //if (!this._container.IsRegistered(serviceType)) { return null; }26                 return this._container.Resolve(serviceType);27             }28             catch29             {30                 return null;31             }32         }33 34         public IEnumerable<object> GetServices(Type serviceType)35         {36             try37             {38                 return this._container.ResolveAll(serviceType);39             }40             catch41             {42                 return new List<object>();43             }44         }45 46         public void Dispose()47         {48             if (_container != null)49             {50                 this._container.Dispose();51                 this._container = null;52             }53         }54     }

复制代码

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

1 //Unity ioc2      UnityConfig.RegisterComponents();

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

复制代码

 1 public static class UnityConfig 2     { 3         public static void RegisterComponents() 4         { 5             var container = new UnityContainer(); 6             container.RegisterType<IBlogsReposity, BoKeYuan>(); 7  8            // var lifeTimeOption = new ContainerControlledLifetimeManager(); 9             //container.RegisterInstance<IBlogsReposity>(new BoKeYuan(), lifeTimeOption);10 11             GlobalConfiguration.Configuration.DependencyResolver = new UnityResolverContainer(container);12         }13     }

复制代码

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

复制代码

 1  public class ValuesController : ApiController 2     { 3  4         private readonly IBlogsReposity _reposity; 5  6         public ValuesController(IBlogsReposity reposity) 7         { 8             _reposity = reposity; 9         }10 11         // GET api/values  12         public async Task<IEnumerable<MoBlog>> Get(int task = 6)13         {14             task = task <= 0 ? 6 : task;15             task = task > 50 ? 50 : task;16             return await _reposity.GetBlogs(task);17         }18 }

复制代码

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






      本文转自zsdnr  51CTO博客,原文链接:http://blog.51cto.com/12942149/1932710,如需转载请自行联系原作者



相关文章
|
6月前
|
Java 测试技术 Spring
Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成(二)
Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成
|
6月前
|
SQL Java 关系型数据库
Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成(一)
Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成
|
11月前
|
前端开发 Java Spring
Spring MVC-02循序渐进之解耦控制器和校验器
Spring MVC-02循序渐进之解耦控制器和校验器
59 0
|
JSON 前端开发 JavaScript
【Spring MVC】(六)RESTFUL 的设计风格、Spring MVC 拦截器、文件上传和下载
【Spring MVC】(六)RESTFUL 的设计风格、Spring MVC 拦截器、文件上传和下载
148 0
【Spring MVC】(六)RESTFUL 的设计风格、Spring MVC 拦截器、文件上传和下载
|
开发框架 .NET 数据库连接
Autofac依赖注入
Autofac 是一款超赞的.NET IoC 容器 . 它管理类之间的依赖关系, 从而使 应用在规模及复杂性增长的情况下依然可以轻易地修改 .它的实现方式是将常规的.net类当做 组件 处理.
148 0
Autofac依赖注入
|
设计模式 缓存 Shell
Hyperf 的依赖注入
Hyperf 默认采用 hyperf/di 作为框架的依赖注入管理容器,尽管从设计上我们允许您更换其它的依赖注入管理容器,但我们强烈不建议您更换该组件。hyperf/di 是一个强大的用于管理类的依赖关系并完成自动注入的组件,与传统依赖注入容器的区别在于更符合长生命周期的应用使用、提供了注解及注解注入的支持、提供了无比强大的AOP 面向切面编程能力,这些能力及易用性是 Hyperf 的核心输出
867 0
|
前端开发 JavaScript 容器
|
XML 前端开发 数据格式

热门文章

最新文章