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;} }代码分析:
// GET api/valuespublic 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):http://www.lovexins.com:1001/api/values?task=6;咋们来想象一下,如果这个Get方法中还需要调用其他实现了接口 IBlogsReposity 的博客抓取类,那咋们又需要手动new一次来创建对应的对象;倘若除了在 ValuesController.cs 文件中调用了博客数据抓取,其他文件还需要这抓取数据的业务,那么又会不停的new,可能有朋友就会说那弄一个工厂模式怎么样,不错这是可行的一种方式,不过这里还有其他方法能处理这种问题,比如:ioc依赖注入;因此就有了下面的分享内容。
看起来很老了哈哈,不过咋们能用就行,安装起来可能需要点时间,毕竟比较大么也有可能是网络的问题吧;安装完后咋们创建一个自定义类 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 _repositypublic 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 iocUnityConfig.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获取数据绑定到页面上的效果:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!