一个几近月份之后,由浅入好表达式系列之末段一篇终于使出版了。想对有关心之爱人说声:“对不起,我来后了!”
希望最后一篇之始末对得由当时一个月时间的等候。在念书了表达式树的创导同遍历之后,我们要采用其的特点来描写一个我们团结一心之Linq
Provider。人家还起Linq to Amazon为什么咱们无可知发生Linq to
cnblogs呢?今天我们就是来同样步一步之打好之Linq
Provider,文章未尾已附上源码下载地址。如果对表达式树的创同遍历还是熟悉的话,建议事先看前面两篇:

  创建表达式树
      http://www.cnblogs.com/jesse2013/p/expressiontree-part1.html

  遍历表达式树
    http://www.cnblogs.com/jesse2013/p/expressiontree-part2.html

  更新:前面从没描述清楚本篇博客的来意,导致群恋人的误会表示抱歉。本系列主要理解表达式目录树,以及Linq
Provider。最后一首是Linq
Provider的兑现,之备见面刻画这样多的代码去开同样项简单的转业(拉取博客园首页文章列表)完全是为闹一个鲜活的例子去展示什么促成自己的Linq
Provider。和咱们种蒙之老三重叠架构,或者直接序列化到当地是从未有过可比性的。

  当然,表达式目录树以及Linq
Provider的兵不血刃也尚未这个小小的Demo能体现得矣的,如果你实在理解Linq
Provider和表达式树目录树是呀,用来干啊的,也许你尽管能够亮本篇博客的意向了。如果非了解之,建议读毕前面两首之后重新举行评价。因为您以好未懂得的景象下就直接去评价别的圈子,你尽管错过了一个摸底它们的机。:)

目录

  • 实现目标
  • 数准备
    • 包博客园Service
  • 认识IQueryable和IQueryProvider接口
    • IQueryable
    • IQueryProvider
  • Linq to
    cnblogs的实现

    • 实现PostExpressionVisitor类型
    • 实现CnblogsQueryProvider
    • PostHelper请求数据并分析

实现目标

  我们实现的目标就是如Linq to
SQL一样,可以据此Linq查询语句来询问数据,我们立即其间的数目以了博客园官方的Service去查询到新型的颁发到首页的博客信息。看下面的代码:

var provider = new CnblogsQueryProvider();
var queryable = new Query<Post>(provider);

var query =
    from p in queryable
    where p.Diggs >= 10 &&
    p.Comments > 10 &&
    p.Views > 10 &&
    p.Comments < 20
    select p;

var list = query.ToList();

   作为实时访问远程的Service,我们还该切实以下几点要求:

  • 延迟加载,即到最终动用的时候才真的的失请数据
  • 止回需要之多少,不可知管持有的多寡都下充斥过来又至本地过滤,那即便没意义了

末了实现之结果:

XML 1

数码准备

  根据博客园公开的API显示,获取首页文章列表非常容易,大家好触发下的URL来体检一拿。我们最终吃的参数是100000,当然真实返回肯定是不曾那基本上之,我们是愿意把能获得回来的还获回来。

  http://wcf.open.cnblogs.com/blog/sitehome/recent/100000 

  XML 2

  点击了上面的URL之后吧,问题虽来了,它不过发一个参数。我并无能够传给它们查询条件,比如说根据题目来找,或者因评论数,浏览量来过滤。难道自己之计划虽这而泡汤了呢,刚开自己大无开心,为什么博客园就非能够提供灵活一点之Service呢?但是事实就是这般,咋是程序员呀,需求摆在当时,怎么在还得落实是休?没有章程,我深受其包裹了同一层。在它的基础及举行了一个团结之Service。

装进博客园Service

  我们什么当博客园公开Service的底子及加以相同层实现准查询也?主要思路是如此的:

  • 呢文章建立实体类(Post)
  • 用博客园Service返回的数解析成Post的汇聚,我们可添加自己之缓存机制,可以运用1分钟才到博客园取一不成数据
  • 管我们地方创建的post集合当作数据库,建立查询Service

  我们首先要举行的饶是吗博客园的博客建立实体类。

public class Post
{
    // Id
    public int Id { get; set; }

    // 标题
    public string Title { get; set; }

    // 发布时间
    public DateTime Published { get; set; }

    // 推荐数据
    public int Diggs { get; set; }

    // 访问人数
    public int Views { get; set; }

    // 评论数据
    public int Comments { get; set; }

    // 作者
    public string Author { get; set; }

    // 博客链接
    public string Href { get; set; }

    // 摘要
    public string Summary { get; set; }
}

  就,我们只要将博客园返回给我们的XML数据易成我们若之post集合,所以我们要为此到Linq
to XML。

_list = new List<CnblogsLinqProvider.Post>();
var document = XDocument.Load(
    "http://wcf.open.cnblogs.com/blog/sitehome/recent/100000"
    );

var elements = document.Root.Elements();
var result = from entry in elements
                where entry.HasElements == true
                select new CnblogsLinqProvider.Post
                {
                    Id = Convert.ToInt32(entry.Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "id").Value),

                    Title = entry.Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "title").Value,

                    Published = Convert.ToDateTime(entry.Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "published").Value),

                    Diggs = Convert.ToInt32(entry.Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "diggs").Value),

                    Views = Convert.ToInt32(entry.Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "views").Value),

                    Comments = Convert.ToInt32(entry.Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "comments").Value),

                    Summary = entry.Elements()
                        .SingleOrDefault(x=>x.Name.LocalName=="summary").Value,

                    Href = entry.Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "link")
                        .Attribute("href").Value,

                    Author = entry.Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "author")
                        .Elements()
                        .SingleOrDefault(x => x.Name.LocalName == "name").Value
                };

_list.AddRange(result);

   然后即交了咱的询问了,实际上我们出了IEnumrable<Post>的多寡就可一直以该地用Linq去查询其了。但是及时不是咱纪念要之,因为我们地方的步子是管具有的数码一次性全部下载下来了,而休是冲我们的急需返回数据。另外我们顿时个中凡是当博客园Service的功底及做一样层封装,实现通过Url直接询问首页的章。为什么而由此Url来查询?因为我们最后见面经过我们好之LinqProvider将Linq查询语句直接翻译成Url这样尽管能够落实长途的回来数据了。来探视我们本着Url参数的概念:

  XML 3

  • 题中概括模式的文章:http://linqtocnblogs.cloudapp.net?Title=模式 
  • 访问人数逾5同时评论超过10的稿子
    http://linqtocnblogs.cloudapp.net?MinViews=5&MinComments=10

以JsonResult 返回json数据来创造我们的Service

  作为Service,我们返回Json或者XML格式的数都是可以的。当然实现这要求的措施来广大种植,我们就里面来选择了一样种最简便好又比较可我们需要方。不欲WCF
Service也无待Web API,直接用MVC里面的Action返回JsonResult就得了。

[HttpGet]
public JsonResult Index(SearchCriteria criteria = null)
{
    var result = PostManager.Posts;
    if (criteria != null)
    {
        if (!string.IsNullOrEmpty(criteria.Title))
            result = result.Where(
                p => p.Title.IndexOf(criteria.Title, StringComparison.OrdinalIgnoreCase) >= 0);

        if (!string.IsNullOrEmpty(criteria.Author))
            result = result.Where(p => p.Author.IndexOf(criteria.Author, StringComparison.OrdinalIgnoreCase) >= 0);

        if (criteria.Start.HasValue)
            result = result.Where(p => p.Published >= criteria.Start.Value);

        if (criteria.End.HasValue)
            result = result.Where(p => p.Published <= criteria.End.Value);

        if (criteria.MinComments > 0)
            result = result.Where(p => p.Comments >= criteria.MinComments);

        if (criteria.MinDiggs > 0)
            result = result.Where(p => p.Diggs >= criteria.MinDiggs);

        if (criteria.MinViews > 0)
            result = result.Where(p => p.Diggs >= criteria.MinViews);

        if (criteria.MaxComments > 0)
            result = result.Where(p => p.Comments <= criteria.MaxComments);

        if (criteria.MaxDiggs > 0)
            result = result.Where(p => p.Diggs <= criteria.MaxDiggs);

        if (criteria.MaxViews > 0)
            result = result.Where(p => p.Diggs <= criteria.MaxViews);
    }
    return Json(result, JsonRequestBehavior.AllowGet);
}

  用Action来做这种Service还有一个补就是是我们不需要一个一个之扬言查询参数,只待拿持有的参数放到一个model中虽可了。剩下的行即使交Model
Binder吧。

 public class SearchCriteria
    {
        public string Title { get; set; }
        public string Author { get; set; }

        public DateTime? Start { get; set; }
        public DateTime? End { get; set; }

        public int MinDiggs { get; set; }
        public int MaxDiggs { get; set; }
        public int MinViews { get; set; }
        public int MaxViews { get; set; }
        public int MinComments { get; set; }
        public int MaxComments { get; set; }
    }

  如果大家想重新熟识这Service的成效,可以参考上面的参数自己去体验一下(用IE会直接下载.json的文本,用Chrom是得一直以浏览器中看数量的)。但是自己没召开另外安全性的主意,希望大侠高抬贵手,别把网站整理挂了就实施。

认识IQueryable和IQueryProvider接口

   有矣上面的Service之后,我们如果开的事务就概括多矣,但是在我们的确开始下手写自己之Linq
Provider之前,先来探IQueryable和IQueryProvider这简单独基本点之接口。

IQueryable

  IQueryable本身并没包含多少之物,它仅仅生三独特性:

  XML 4

  • ElementType 代表本者Query所对应之路
  • Expression 包含了咱当然Query所行之兼具查询或者是其余的操作
  • IQueryProvider则是承受处理方面的Expression的实现

  更为重要的凡,在IQueryable这个接口之上,.net为咱提供了累累底恢弘方法:

  XML 5

  我们平常用到的Where,Select,Max,Any都包括在其中,具体的法子大家好到System.Linq.Queryable这个静态类下去看。大家小心一下,传于Where方法的难为我们今天修之Expression。

    在另外一个坏要紧之接口IEnumrable下,也存有同样的扩充方法:

  XML 6

  这些扩展方法来System.Linq.Enumrable这个静态类下。我们得以看到个别组扩展方法的不同之处在于IQueryable下传的Expression类型,而IEnumrable下传的凡托。这样做的用意是什么吗?您要接着向下看。

 

IQueryProvider

  我们地方讲到了Enumrable和Queryable这点儿独静态类下的壮大方法,对于Enumrable下之壮大方法吧他们传出的凡信托,对于信托而言直接实施就得了。

public static IEnumerable<T> Where<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
    var result = new List<T>();
    foreach (var element in list)
    { 
        // 调用委托是验证这个元素是否符合条件
        if(predicate(element))
            result.Add(element);
    }
    return result;
}

  上面的代码给大家发一个参照,相信不难理解,所以Enumrable下的静态方法都是操作本地数据的。而对Queryable下的静态方法而言,他们接收的凡表达式,还记表达式的无比酷特征呢?可以在运转时去遍历解释然后实施,那么如此便可以拿表达式转换成为各种其他的章程去获取数据,伟大的Linq
to SQL就是这样实现的。而这背后的良功臣就是我们的Linq
Provider了,而IQueryProvider就是LinqProvider的接口。

   XML 7

  IQueryProvider只出星星点点个操作,CreateQuery和Execute分别发泛型版本与非泛型版本。
CreatQuery用于组织一个IQueryable<T>的对象,这个类似其实并未其他实现,只是继承了IQueryable和IEnumrable接口。主要用以计算指定表达式目录树所代表的询问,返回的结果是一个可枚举的色。 而Execute会执行指定表达式目录树所表示的查询,返回指定的结果。所有的底细就当是Execute方法中,拿我们设进行的Linq
to
cnblogs方法来比喻,我们以将传播的表达式目录树翻译成一个URL就是依为我们封装好之Service的URL,通过发起web
request到此URL,拿到response进行辨析,最终获我们所设的多寡,这便是咱们Linq
to cnblogs的笔触。

Linq to cnblogs的实现

  有矣前面的数准备同有贯彻的大体思路下,我们尽管得入手开始兑现我们的CnblogsQueryProvider了。我们的笔触大致是如此的:

  1. 兑现协调之ExpressionVisitor类去拜谒表达式目录数,将那个翻译成可以看Service的Url
  2. 调用WebRequest去看这Url
  3. 将方返回的Response解析成我们如果的对象

实现PostExpressionVisitor

  关于发挥式树的顾,我们以其次篇被已发生了比详细的牵线。如果对发挥式树的遍历不亮堂的,可以错过次篇《遍历表达式》惨遭查。在此处,我们创建一个咱们团结一心的ExpressionVisitor类,去遍历表达式树。我们临时就待特别成一个SearchCriteria(我们地方就定义好了,对于查询条件建之范)对象即可。

XML 8XML 9

  1 public class PostExpressionVisitor
  2 {
  3 private SearchCriteria _criteria;
  4 
  5 // 入口方法
  6 public SearchCriteria ProcessExpression(Expression expression)
  7 {
  8     _criteria = new SearchCriteria();
  9     VisitExpression(expression);
 10     return _criteria;
 11 }
 12 
 13 private void VisitExpression(Expression expression)
 14 {
 15     switch (expression.NodeType)
 16     { 
 17         // 访问 &&
 18         case ExpressionType.AndAlso:
 19             VisitAndAlso((BinaryExpression)expression);
 20             break;
 21         // 访问 等于
 22         case ExpressionType.Equal:
 23             VisitEqual((BinaryExpression)expression);
 24             break;
 25         // 访问 小于和小于等于
 26         case ExpressionType.LessThan:
 27         case ExpressionType.LessThanOrEqual:
 28             VisitLessThanOrEqual((BinaryExpression)expression);
 29             break;
 30         // 访问大于和大于等于
 31         case ExpressionType.GreaterThan:
 32         case ExpressionType.GreaterThanOrEqual:
 33             GreaterThanOrEqual((BinaryExpression)expression);
 34             break;
 35         // 访问调用方法,主要有于解析Contains方法,我们的Title会用到
 36         case ExpressionType.Call:
 37             VisitMethodCall((MethodCallExpression)expression);
 38             break;
 39         // 访问Lambda表达式
 40         case ExpressionType.Lambda:
 41             VisitExpression(((LambdaExpression)expression).Body);
 42             break;
 43     }
 44 }
 45 
 46 // 访问  &&
 47 private void VisitAndAlso(BinaryExpression andAlso)
 48 {
 49     VisitExpression(andAlso.Left);
 50     VisitExpression(andAlso.Right);
 51 }
 52 
 53 // 访问 等于
 54 private void VisitEqual(BinaryExpression expression)
 55 {
 56     // 我们这里面只处理在Author上的等于操作
 57     // Views, Comments, 和 Diggs 我们都是用的大于等于,或者小于等于
 58     if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
 59         (((MemberExpression)expression.Left).Member.Name == "Author"))
 60     {
 61         if (expression.Right.NodeType == ExpressionType.Constant)
 62             _criteria.Author = 
 63                 (String)((ConstantExpression)expression.Right).Value;
 64 
 65         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
 66             _criteria.Author = 
 67                 (String)GetMemberValue((MemberExpression)expression.Right);
 68 
 69         else
 70             throw new NotSupportedException("Expression type not supported for author: " + 
 71                 expression.Right.NodeType.ToString());
 72     }
 73 }
 74 
 75 // 访问大于等于
 76 private void GreaterThanOrEqual(BinaryExpression expression)
 77 {
 78     // 处理 Diggs >= n  推荐人数
 79     if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
 80         (((MemberExpression)expression.Left).Member.Name == "Diggs"))
 81     {
 82         if (expression.Right.NodeType == ExpressionType.Constant)
 83             _criteria.MinDiggs = 
 84                 (int)((ConstantExpression)expression.Right).Value;
 85 
 86         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
 87             _criteria.MinDiggs =
 88                 (int)GetMemberValue((MemberExpression)expression.Right);
 89 
 90         else
 91             throw new NotSupportedException("Expression type not supported for Diggs:"
 92                 + expression.Right.NodeType.ToString());
 93     }
 94     // 处理 Views>= n   访问人数
 95     else if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
 96     (((MemberExpression)expression.Left).Member.Name == "Views"))
 97     {
 98         if (expression.Right.NodeType == ExpressionType.Constant)
 99             _criteria.MinViews = 
100                 (int)((ConstantExpression)expression.Right).Value;
101 
102         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
103             _criteria.MinViews =
104                 (int)GetMemberValue((MemberExpression)expression.Right);
105 
106         else
107             throw new NotSupportedException("Expression type not supported for Views: " 
108                 + expression.Right.NodeType.ToString());
109     }
110     // 处理 comments >= n   评论数
111     else if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
112     (((MemberExpression)expression.Left).Member.Name == "Comments"))
113     {
114         if (expression.Right.NodeType == ExpressionType.Constant)
115             _criteria.MinComments =
116                 (int)((ConstantExpression)expression.Right).Value;
117 
118         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
119             _criteria.MinComments = 
120                 (int)GetMemberValue((MemberExpression)expression.Right);
121 
122         else
123             throw new NotSupportedException("Expression type not supported for Comments: "
124                 + expression.Right.NodeType.ToString());
125     }
126     // 处理 发布时间>=
127     else if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
128     (((MemberExpression)expression.Left).Member.Name == "Published"))
129     {
130         if (expression.Right.NodeType == ExpressionType.Constant)
131             _criteria.Start = 
132                 (DateTime)((ConstantExpression)expression.Right).Value;
133 
134         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
135             _criteria.Start = 
136                 (DateTime)GetMemberValue((MemberExpression)expression.Right);
137 
138         else
139             throw new NotSupportedException("Expression type not supported for Published: " 
140                 + expression.Right.NodeType.ToString());
141     }
142 }
143 
144 // 访问 小于和小于等于
145 private void VisitLessThanOrEqual(BinaryExpression expression)
146 {
147     // 处理 Diggs <= n  推荐人数
148     if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
149         (((MemberExpression)expression.Left).Member.Name == "Diggs"))
150     {
151         if (expression.Right.NodeType == ExpressionType.Constant)
152             _criteria.MaxDiggs =
153                 (int)((ConstantExpression)expression.Right).Value;
154 
155         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
156             _criteria.MaxDiggs =
157                 (int)GetMemberValue((MemberExpression)expression.Right);
158 
159         else
160             throw new NotSupportedException("Expression type not supported for Diggs: " 
161                 + expression.Right.NodeType.ToString());
162     }
163     // 处理 Views<= n   访问人数
164     else if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
165     (((MemberExpression)expression.Left).Member.Name == "Views"))
166     {
167         if (expression.Right.NodeType == ExpressionType.Constant)
168             _criteria.MaxViews = 
169                 (int)((ConstantExpression)expression.Right).Value;
170 
171         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
172             _criteria.MaxViews =
173                 (int)GetMemberValue((MemberExpression)expression.Right);
174 
175         else
176             throw new NotSupportedException("Expression type not supported for Views: " 
177                 + expression.Right.NodeType.ToString());
178     }
179     // 处理 comments <= n   评论数
180     else if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
181     (((MemberExpression)expression.Left).Member.Name == "Comments"))
182     {
183         if (expression.Right.NodeType == ExpressionType.Constant)
184             _criteria.MaxComments =
185                 (int)((ConstantExpression)expression.Right).Value;
186 
187         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
188             _criteria.MaxComments = 
189                 (int)GetMemberValue((MemberExpression)expression.Right);
190 
191         else
192             throw new NotSupportedException("Expression type not supported for Comments: "
193                 + expression.Right.NodeType.ToString());
194     }
195 
196         // 处理发布时间 <= 
197     else if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
198     (((MemberExpression)expression.Left).Member.Name == "Published"))
199     {
200         if (expression.Right.NodeType == ExpressionType.Constant)
201             _criteria.End = 
202                 (DateTime)((ConstantExpression)expression.Right).Value;
203 
204         else if (expression.Right.NodeType == ExpressionType.MemberAccess)
205             _criteria.End =
206                 (DateTime)GetMemberValue((MemberExpression)expression.Right);
207 
208         else
209             throw new NotSupportedException("Expression type not supported for Published: " 
210                 + expression.Right.NodeType.ToString());
211     }
212 }
213 
214 // 访问 方法调用
215 private void VisitMethodCall(MethodCallExpression expression)
216 {
217     if ((expression.Method.DeclaringType == typeof(Queryable)) &&
218         (expression.Method.Name == "Where"))
219     {
220         VisitExpression(((UnaryExpression)expression.Arguments[1]).Operand);
221     }
222     else if ((expression.Method.DeclaringType == typeof(String)) &&
223         (expression.Method.Name == "Contains"))
224     {
225         // Handle Title.Contains("")
226         if (expression.Object.NodeType == ExpressionType.MemberAccess)
227         {
228             MemberExpression memberExpr = (MemberExpression)expression.Object;
229             if (memberExpr.Expression.Type == typeof(Post))
230             {
231                 if (memberExpr.Member.Name == "Title")
232                 {
233                     Expression argument;
234                     argument = expression.Arguments[0];
235                     if (argument.NodeType == ExpressionType.Constant)
236                     {
237                         _criteria.Title = 
238                             (String)((ConstantExpression)argument).Value;
239                     }
240                     else if (argument.NodeType == ExpressionType.MemberAccess)
241                     {
242                         _criteria.Title = 
243                             (String)GetMemberValue((MemberExpression)argument);
244                     }
245                     else
246                     {
247                         throw new NotSupportedException("Expression type not supported: " 
248                             + argument.NodeType.ToString());
249                     }
250                 }
251             }
252         }
253     }
254     else
255     {
256         throw new NotSupportedException("Method not supported: "
257             + expression.Method.Name);
258     }
259 }
260 
261 // 获取属性值
262 private Object GetMemberValue(MemberExpression memberExpression)
263 {
264     MemberInfo memberInfo;
265     Object obj;
266 
267     if (memberExpression == null)
268         throw new ArgumentNullException("memberExpression");
269 
270 
271     if (memberExpression.Expression is ConstantExpression)
272         obj = ((ConstantExpression)memberExpression.Expression).Value;
273     else if (memberExpression.Expression is MemberExpression)
274         obj = GetMemberValue((MemberExpression)memberExpression.Expression);
275     else
276         throw new NotSupportedException("Expression type not supported: "
277             + memberExpression.Expression.GetType().FullName);
278 
279     memberInfo = memberExpression.Member;
280     if (memberInfo is PropertyInfo)
281     {
282         PropertyInfo property = (PropertyInfo)memberInfo;
283         return property.GetValue(obj, null);
284     }
285     else if (memberInfo is FieldInfo)
286     {
287         FieldInfo field = (FieldInfo)memberInfo;
288         return field.GetValue(obj);
289     }
290     else
291     {
292         throw new NotSupportedException("MemberInfo type not supported: " 
293             + memberInfo.GetType().FullName);
294     }
295 }
296 }

View Code

 实现CnblogsQueryProvider

  有矣端的访问类之后,我们的CnblogsQueryProvider就非常简单了。

XML 10XML 11

 1 public class CnblogsQueryProvider:QueryProvider
 2 {
 3     public override String GetQueryText(Expression expression)
 4     {
 5         SearchCriteria criteria;
 6 
 7         // 翻译查询条件
 8         criteria = new PostExpressionVisitor().ProcessExpression(expression);
 9 
10         // 生成URL
11         String url = PostHelper.BuildUrl(criteria);
12 
13         return url;
14     }
15 
16     public override object Execute(Expression expression)
17     {
18         String url = GetQueryText(expression);
19         IEnumerable<Post> results = PostHelper.PerformWebQuery(url);
20         return results;
21     }
22 }

View Code

  我们其中就覆盖了基类的有限只措施,GetQueryText和Execute。

  • GetQueryText根据访问类得到的SearchCriteria去跟成为访问Service的Url
  • Execute看则负责夺要是Url拿到数码返回即可

PostHelper请求数据

  我们当下其中有一个扶类似PostHelper,就承受了根据criteria生成Url以及呼吁Url获取数据的效用。

XML 12XML 13

 1 static internal string BuildUrl(SearchCriteria criteria,string url=null)
 2 {
 3     if (criteria == null)
 4         throw new ArgumentNullException("criteria");
 5 
 6     var sbUrl = new StringBuilder(url ?? "http://linqtocnblogs.cloudapp.net/");
 7     var sbParameter = new StringBuilder();
 8 
 9     if (!String.IsNullOrEmpty(criteria.Title))
10         AppendParameter(sbParameter, "Title", criteria.Title);
11                 
12     if (!String.IsNullOrEmpty(criteria.Author))
13         AppendParameter(sbParameter, "Author", criteria.Author);
14 
15     if (criteria.Start.HasValue)
16         AppendParameter(sbParameter, "Start", criteria.Start.Value.ToString());
17 
18     if (criteria.End.HasValue)
19         AppendParameter(sbParameter, "End", criteria.End.Value.ToString());
20 
21     if (criteria.MinDiggs > 0)
22         AppendParameter(sbParameter, "MinDiggs", criteria.MinDiggs.ToString());
23 
24     if (criteria.MinViews > 0)
25         AppendParameter(sbParameter, "MinViews", criteria.MinViews.ToString());
26 
27     if (criteria.MinComments> 0)
28         AppendParameter(sbParameter, "MinComments",
29             criteria.MinComments.ToString());
30 
31     if (criteria.MaxDiggs > 0)
32         AppendParameter(sbParameter, "MaxDiggs", criteria.MaxDiggs.ToString());
33 
34     if (criteria.MaxViews > 0)
35         AppendParameter(sbParameter, "MaxViews", criteria.MaxViews.ToString());
36 
37     if (criteria.MaxComments > 0)
38         AppendParameter(sbParameter, "MaxComments",
39             criteria.MaxComments.ToString());
40 
41     if (sbParameter.Length > 0)
42         sbUrl.AppendFormat("?{0}", sbParameter.ToString());
43 
44     return sbUrl.ToString();
45 }
46 
47 static internal void AppendParameter(StringBuilder sb,string name,string value)
48 {
49     if (sb.Length > 0)
50         sb.Append("&");
51 
52     sb.AppendFormat("{0}={1}",name,value);
53 }
54 
55 static internal IEnumerable<Post> PerformWebQuery(string url)
56 {
57     var request = WebRequest.Create(url);
58     request.Credentials = CredentialCache.DefaultCredentials;
59 
60     var response = (HttpWebResponse)request.GetResponse();
61     using(var reader= new StreamReader(response.GetResponseStream()))
62     {
63         var body = reader.ReadToEnd();
64         return JsonConvert.DeserializeObject<List<Post>>(body);
65     }
66 }
67 }

View Code

  以我们的Service是返的Json数据,所以这边,我们赖以了Json.Net将其反成为我们所而之List<Post>的数量。

  就是这么简单,我们的Linq to
cnblogs就特别功告成了。

  
 点击这里下充斥源码:http://pan.baidu.com/s/1gd85l1T 

相关文章

网站地图xml地图