接上文【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(二)

  上文最后留下了一个问题,引起这个问题的操作是把原来通过硬编码字符串来设置的Expression参数改为接收用户输入。这是个非常正常的需求,可以说如果这个问题不解决,上文的Expression序列化的方法是无法应用到实际项目中的。下面来分析异常引起的原因。

  首先,来查看一下接收输入来组装的Expression与硬编码的方式生成有什么不同:

 1 private static void Method02()
 2 {
 3     Expression<Func<Member, bool>> predicate = m => m.UserName == "zhangsan";
 4     Console.WriteLine("硬编码生成的表达式:\n"+predicate);
 5     Console.WriteLine("------------------------华丽的分割线--------------------------");
 6
 7     var input = Console.ReadLine();
 8     predicate = m => m.UserName == input;
 9     Console.WriteLine("接收输入生成的表达式:\n"+predicate);
10 }

执行程序,输入“zhangsan”,运行的结果:

  可以看出,接收输入生成的Expression表达式确实长得很奇异,这也解释了为什么报异常的原因。因为“Liuliu.TestConsole.Program+<>c__DisplayClass0”这个类是客户端运行时生成的,而服务端在对传过去的XElement进行反序列化时,无法识别出这个类型,自然就报错了。

  怎么解决呢?通过上文中提到的KnownTypeExpressionXmlConverter类把这个类传给服务端让它变成已知类型?显然这是做不到的,因为Liuliu.TestConsole.Program+<>c__DisplayClass0这个类是运行时生成的,在运行之前根本不存在。看来此路不通。

  看来只有一条路了,那就是让输入参数input与客户端分离,解除对客户端程序的依赖。而NuGet上面正好有一个叫“Dynamic Expression API”的开源组件能解决这个问题,添加引用到项目中,把上面的测试代码修改如下:

 1 private static void Method02()
 2 {
 3     Expression<Func<Member, bool>> predicate = m => m.UserName == "zhangsan";
 4     Console.WriteLine("硬编码生成的表达式:\n"+predicate);
 5     Console.WriteLine("------------------------华丽的分割线--------------------------");
 6
 7     var input = Console.ReadLine();
 8     predicate = m => m.UserName == input;
 9     Console.WriteLine("接收输入生成的表达式:\n"+predicate);
10     Console.WriteLine("------------------------华丽的分割线--------------------------");
11
12     input = Console.ReadLine();
13     predicate = System.Linq.Dynamic.DynamicExpression.ParseLambda<Member, bool>("UserName=@0", input);
14     Console.WriteLine("Dynamic Expression API生成的表达式:\n" + predicate);
15 }

由13行可以看到,Dynamic Expression API 是使用字符串拼接的方式来生成Expression的,虽然看起来似乎是历史的倒退,但确实解除了input对客户端的依赖,看运行结果:

可以看到通过Dynamic Expression API生成的Expression与硬编码生成的完全一致,回到了原生的形式,这样,理论上把问题解决了。

  回到我们的WCF,把WCF客户端代码修改如下,只需要把原来的20行修改为21行:

 1 static void Main(string[] args)
 2 {
 3     Console.WriteLine("按任意建执行客户端调用:");
 4     Console.ReadLine();
 5     try
 6     {
 7         Expression<Func<Member, bool>> predicate = m => m.UserName == "zhangsan";
 8         Console.WriteLine(predicate);
 9         var assemblies = new List<Assembly> { typeof(Member).Assembly, typeof(ExpressionType).Assembly, typeof(IQueryable).Assembly };
10         var resolver = new TypeResolver(assemblies, new[] { typeof(Member) });
11         var knownTypeConverter = new KnownTypeExpressionXmlConverter(resolver);
12         var serializer = new ExpressionSerializer(resolver, new CustomExpressionXmlConverter[] { knownTypeConverter });
13         var xmlPredicate = serializer.Serialize(predicate);
14         var result = WcfHelper.InvokeService<IAccountContract, Member>(wcf => wcf.GetMember(xmlPredicate));
15         Console.WriteLine(result.Email);
16
17         var input = Console.ReadLine();
18         if (!string.IsNullOrEmpty(input))
19         {
20             //predicate = m => m.UserName == input;
21             predicate = System.Linq.Dynamic.DynamicExpression.ParseLambda<Member, bool>("UserName=@0", input);
22             Console.WriteLine(predicate);
23             xmlPredicate = serializer.Serialize(predicate);
24             result = WcfHelper.InvokeService<IAccountContract, Member>(wcf => wcf.GetMember(xmlPredicate));
25             Console.WriteLine(result.Email);
26         }
27     }
28     catch (Exception e)
29     {
30         Console.WriteLine(e);
31     }
32     Console.ReadLine();
33 }

运行结果与预期一致:

我们的演示项目经过几次的大手术,已经变得面目全非了,作为一个完美主义的程序员,这是不可容忍的。所以,对项目进行重构是必然的步骤。

1.客户端Client与服务实现Services中都存在 ExpressionSerializer 对象实例化的相同代码,而客户端与服务实现的一个相同点就是都引用了服务契约Contracts

所以,应该把这部分重复代码重构进Contracts中。

2.为了避免每个使用到Dynamic Expression API的地方都要对其进行引用,也应该把Dynamic Expression API封装到Contracts中。

我们把以上两个重构点封装成一个SerializeHelper静态类,使用的时候就直接调用即可。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Linq.Expressions;
 5 using System.Reflection;
 6 using System.Xml.Linq;
 7
 8 using ExpressionSerialization;
 9
10
11 namespace Liuliu.Wcf.IContract.Helper
12 {
13     public static class SerializeHelper
14     {
15
16         public static Expression<Func<T, TS>> CreateExpression<T, TS>(string expression, params object[] values)
17         {
18             if (expression == null)
19             {
20                 throw new ArgumentNullException("expression");
21             }
22             return System.Linq.Dynamic.DynamicExpression.ParseLambda<T, TS>(expression, values);
23         }
24
25         public static XElement SerializeExpression(Expression predicate, IEnumerable<Type> knownTypes = null)
26         {
27             if (predicate == null)
28             {
29                 throw new ArgumentNullException("predicate");
30             }
31             var serializer = CreateSerializer(knownTypes);
32             return serializer.Serialize(predicate);
33         }
34
35         public static XElement SerializeExpression<T, TS>(Expression<Func<T, TS>> predicate)
36         {
37             if (predicate == null)
38             {
39                 throw new ArgumentNullException("predicate");
40             }
41             var knownTypes = new List<Type> { typeof(T) };
42             var serializer = CreateSerializer(knownTypes);
43             return serializer.Serialize(predicate);
44         }
45
46         public static Expression DeserializeExpression(XElement xmlExpression)
47         {
48             if (xmlExpression == null)
49             {
50                 throw new ArgumentNullException("xmlExpression");
51             }
52             var serializer = CreateSerializer();
53             return serializer.Deserialize(xmlExpression);
54         }
55
56         public static Expression<Func<T, TS>> DeserializeExpression<T, TS>(XElement xmlExpression)
57         {
58             if (xmlExpression == null)
59             {
60                 throw new ArgumentNullException("xmlExpression");
61             }
62             var knownTypes = new List<Type> { typeof(T) };
63             var serializer = CreateSerializer(knownTypes);
64             return serializer.Deserialize<Func<T, TS>>(xmlExpression);
65         }
66
67         public static Expression<Func<T, TS>> DeserializeExpression<T, TS>(XElement xmlExpression, IEnumerable<Type> knownTypes)
68         {
69             if (xmlExpression == null)
70             {
71                 throw new ArgumentNullException("xmlExpression");
72             }
73             var serializer = CreateSerializer(knownTypes);
74             return serializer.Deserialize<Func<T, TS>>(xmlExpression);
75         }
76
77         private static ExpressionSerializer CreateSerializer(IEnumerable<Type> knownTypes = null)
78         {
79             if (knownTypes == null || !knownTypes.Any())
80             {
81                 return new ExpressionSerializer();
82             }
83             var assemblies = new List<Assembly> { typeof(ExpressionType).Assembly, typeof(IQueryable).Assembly };
84             knownTypes.ToList().ForEach(type => assemblies.Add(type.Assembly));
85             var resolver = new TypeResolver(assemblies, knownTypes);
86             var knownTypeConverter = new KnownTypeExpressionXmlConverter(resolver);
87             var serializer = new ExpressionSerializer(resolver, new CustomExpressionXmlConverter[] { knownTypeConverter });
88             return serializer;
89         }
90     }
91 }

服务实现代码重构:

1 public Member GetMember(XElement xmlPredicate)
2 {
3     var predicate = SerializeHelper.DeserializeExpression<Member, bool>(xmlPredicate);
4     return DataSource.SingleOrDefault(predicate.Compile());
5 }

客户端代码重构:

 1 static void Main(string[] args)
 2 {
 3     Console.WriteLine("按任意建执行客户端调用:");
 4     Console.ReadLine();
 5     try
 6     {
 7         Expression<Func<Member, bool>> predicate = m => m.UserName == "zhangsan";
 8         Console.WriteLine(predicate);
 9         var xmlPredicate = SerializeHelper.SerializeExpression(predicate);
10         var result = WcfHelper.InvokeService<IAccountContract, Member>(wcf => wcf.GetMember(xmlPredicate));
11         Console.WriteLine(result.Email);
12
13         var input = Console.ReadLine();
14         if (!string.IsNullOrEmpty(input))
15         {
16             predicate = SerializeHelper.CreateExpression<Member, bool>("UserName=@0", input);
17             xmlPredicate = SerializeHelper.SerializeExpression(predicate);
18             result = WcfHelper.InvokeService<IAccountContract, Member>(wcf => wcf.GetMember(xmlPredicate));
19             Console.WriteLine(result.Email);
20         }
21     }
22     catch (Exception e)
23     {
24         Console.WriteLine(e);
25     }
26     Console.ReadLine();
27 }

服务端代码无变化。重构之后,一切都变得井然有序,生活多么美好。

至此,Expression表达式的远程传输中序列化的问题得到了比较圆满的解决,但是使用Dynamic Expression API生成表达式的步骤失去了原来Lambada表达式的优势,返祖了。

所以,这只是一个比较初级的解决方案,希望能有更优良的解决方案来保持Lambada表达式的优势。

第一次写博客,结构比较凌乱,基本上是按我解决问题的思路流水下来的,不够清晰,敬请大家谅解……

最后,奉上本文涉及的源代码:

LambadaSerializeDemo03(重构前).rar

LambadaSerializeDemo03(重构后).rar

转载于:https://www.cnblogs.com/guomingfeng/archive/2012/04/11/2441664.html

【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(三)...相关推荐

  1. SharePoint 2013 调用WCF服务简单示例

    内容比较简单,主要记录自己使用SharePoint 2013WCF服务遇到的小问题和小经验,分享给大家,希望能够给需要的人有所帮助.好吧,进入正题! 第一部分 SharePoint 2013调用自带W ...

  2. 用ExtJs+Linq+Wcf打造简单grid

    本系列文章列表 1)Ajax访问Xml Web Service的安全问题以及解决方案 2)Ajax与WCF交互-WCF之美 3) Ajax与Wcf交互-JSON 4) ExtJs与WCF交互:生成树 ...

  3. sed: -e expression #1, char 0: no previous regular expression

    sed执行替换操作,单独执行不存在问题,但是脚本中执行报上述信息: ###手工执行############# [root@k8s-t01 tmp]# a=88888888 [root@k8s-t01 ...

  4. 简单介绍实体类或对象序列化时,忽略为空属性的操作

    这篇文章主要介绍了实体类或对象序列化时,忽略为空属性的操作,具有很好的参考价值,希望对大家有所帮助.如有错误或未考虑完全的地方,望不吝赐教 第一种,在配置文件配置 在application.xml直接 ...

  5. 职业发展鉴定方法:第一行:自己行 第二行:大家说你行 第三行:领导行 就这么简单,去努力吧,如果你做到了这三个行,那么你肯定行...

    [Thinking]三个行 昨天跟同事聊职业发展,同事给我讲了个道理,虽然类似的道理自己也知道很多并且坚持奉行着,但是同事总结的特别好!我反复思量这简单的几句话,感觉真的真的很精辟! 三个行 第一行: ...

  6. 序列化(串行化)- 使用BinaryFormatter进行序列化

    注:原书上翻译为串行化,MSDN翻译为序列化,我以MSDN为准,写为序列化. 可以使用属性(Attribute)将类的元素标为可序列化的(Serializable)和不可被序列化的(NonSerial ...

  7. NumPy实现简单的神经网络分析Mnist手写数字库(三)之划分迷你批(mini-batch)

    NumPy实现简单的神经网络分析Mnist手写数字库(三)之划分迷你批(mini-batch) 划分迷你批(mini-batch) 引言 迷你批(mini-batch)简介 经典梯度下降 随机梯度下降 ...

  8. Java序列化是什么?你知道什么时候需要序列化吗?

    Java序列化是什么?你知道什么时候需要序列化吗? 什么是 java 序列化?什么情况下需要序列化? 序列化:将 Java 对象转换成字节流的过程. 反序列化:将字节流转换成 Java 对象的过程. ...

  9. WCF,简单而又复杂的东西

    WCF初始使用的时候比较简单, 将我们常用的普通的代码写法可以转换为 WebService服务. 对于一些简单的接口的发布可以说是轻而易举的事情了. 但是这是这种简单迷惑了我们的双眼. 当我们需要将整 ...

最新文章

  1. mysql最高权限超级用户是_MySQL中,预设的、拥有最高权限超级用户的用户名为( )...
  2. airpods固件更新方法_苹果AirPods 2 和 AirPods Pro固件升级
  3. 这 5 个能挣钱的 SpringBoot 项目,真TMD香!
  4. 一个设计元素很多的网站
  5. node、npm、vue安装 -- VUE 项目 demo 实例
  6. vs2010调试-尝试调试dll源码。
  7. CISCO路由器的备份与还原(1)
  8. unity, 欧拉角(euler angle)
  9. 关于 Apache 2.4 配置PHP时的错误记录
  10. 机器学习基础:概率论基础
  11. 几个免费IP地址查询API接口
  12. 【python初级】os.listdir返回目录中包含的文件以及文件夹的列表
  13. LwIP+ STM32+HTTP例程参考
  14. redit mysql_从 Reddit 学到的经验,互联网营销
  15. Photoshop 制作水晶按钮
  16. 涨薪 50%,从小厂逆袭,坐上美团 L8 技术专家(面经 + 心得)
  17. 知乎高赞:拼多多和国家电网,选哪个?
  18. C - Monthly Expense
  19. 翻译连载 | JavaScript轻量级函数式编程-第4章:组合函数 |《你不知道的JS》姊妹篇... 1
  20. clip python_Python pandas.DataFrame.clip函数方法的使用

热门文章

  1. [python]python jieba 模块
  2. 4、根据前序和中序,重建二叉树
  3. redis的安装和常用命令
  4. Ubuntu增加Swap分区大小
  5. js 给json添加新的字段,或者添加一组数据,在JS数组指定位置删除、插入、替换元素...
  6. 文件管理类函数(1)
  7. Abstract class 与Interface 抽象类和接口
  8. Godot 2D 和 3D 游戏引擎
  9. 操作日志和系统日志分类记录
  10. VS2017控制台打印问题