当前位置:首页 > 服务端 > 【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(四)——关于Guid的问题

【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(四)——关于Guid的问题

发了本系列的前三遍几天后,收到了若风云 同学的站内信,说如果Expression中包含Guid类型属性的查询时,会报异常,亲自验证了下,确实会有问题。原因是Dynamic Expression API 与 ExpressionSerialization 对Guid的支持不是很好。下面就来解决这个问题。

首先,给我们的DataContract(Member类)增加一个Guid类型的属性UserCode,同时Service的DataSource也作相应的修改:

WCF的DataContract:

 1 [DataContract]
 2 public class Member
 3 {
 4     [DataMember]
 5     public int MemberID { get; set; }
 6 
 7     [DataMember]
 8     public string UserName { get; set; }
 9 
10     [DataMember]
11     public string Email { get; set; }
12 
13     [DataMember]
14     public Guid UserCode { get; set; }
15 }

 

Service中的查询数据源DataSource:

1 private static readonly List<Member> DataSource = new List<Member>
2 {
3     new Member {MemberID = 3, UserName = "zhangsan", Email = "zhangsan@abc.com", UserCode = Guid.Parse("3DDE3E8D-D2A6-4185-9A73-37E5231C6DC1")},
4     new Member {MemberID = 4, UserName = "lisi", Email = "lisi@abc.com", UserCode = Guid.Parse("F2616B12-8966-4351-BE5A-047000C5BA7B")},
5     new Member {MemberID = 5, UserName = "wangwu", Email = "wangwu@abc.com", UserCode = Guid.Parse("EB37642C-A5A8-43F3-BA58-0D8A96327B9C")},
6     new Member {MemberID = 6, UserName = "zhaoliu", Email = "zhaoliu@abc.com", UserCode = Guid.Parse("868CC2E3-260D-4E6C-A5A6-3C4F7EFE2FF7")}
7 };

 

我们在客户端新建一个查询试试:

 1 Console.WriteLine("请输入要查询的UserCode的Guid字符串:");
 2 input = Console.ReadLine();
 3 if (!string.IsNullOrEmpty(input))
 4 {
 5     var guid = Guid.Parse(input);
 6     predicate = SerializeHelper.CreateExpression<Member, bool>("UserCode=@0", guid);
 7     xmlPredicate = SerializeHelper.SerializeExpression(predicate);
 8     result = WcfHelper.InvokeService<IAccountContract, Member>(wcf => wcf.GetMember(xmlPredicate));
 9     Console.WriteLine(result.Email);
10 }

 

运行程序,输入zhangsan的UserCode:3DDE3E8D-D2A6-4185-9A73-37E5231C6DC1,结果如下:

【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(四)——关于Guid的问题 _ JavaClub全栈架构师技术笔记

直接Google这条报错信息,直接就找到了 Operator '=' incompatible with operand types 'Guid' and 'Guid'

根据以上链接提供的解决办法,把 Dynamic.cs 文件的第 777 行修改成如下:

1 if (isEquality && ((!left.Type.IsValueType && !right.Type.IsValueType) || (left.Type == typeof(Guid) && right.Type == typeof(Guid))))

 

编译,运行,继续报了如下异常:

【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(四)——关于Guid的问题 _ JavaClub全栈架构师技术笔记 View Code
System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: 值不能为 null。
参数名: typeName (错误详细信息等于 很可能由 IncludeExceptionDetailInFaults=true创建的 ExceptionDetail,其值为:
System.ArgumentNullException: 值不能为 null。
参数名: typeName
   在 ExpressionSerialization.TypeResolver.GetType(String typeName) 位置 D:\我的文档\Visual Studio 2010\Projects\LambadaSerializeDemo\ExpressionSerialization\TypeResolver.cs:行号 150
   在 ExpressionSerialization.KnownTypeExpressionXmlConverter.TryDeserialize(XElement x, Expression& e) 位置 D:\我的文档\Visual Studio 2010\Projects\LambadaSerializeDemo\ExpressionSerialization\KnownTypeExpressionXmlConverter.cs:行号46
   在 ExpressionSerialization.ExpressionSerializer.TryCustomDeserializers(XElement xml, Expression& result) 位置 D:\我的文档\Visual Studio 2010\Projects\LambadaSerializeDemo\ExpressionSerialization\ExpressionSerializer(Deserialize).cs:行号122
   在 ExpressionSerialization.ExpressionSerializer.ParseExpressionFromXmlNonNull(XElement xml) 位置 D:\我的文档\Visual Studio 2010\Projects\LambadaSerializeDemo\ExpressionSerialization\ExpressionSerializer(Deserialize).cs:行号 63
   在 ExpressionSerialization.Expressi...)。

由上面的异常信息可知,问题出在KnownTypeExpressionXmlConverter.cs文件的46行,对比服务端接收的XElement可看出,接收字符串(UserName)与接收Guid类型(UserCode)时存在如下差异:

<ConstantExpression NodeType="System.String">
  <Type>System.String</Type>
  <Value>&lt;string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"&gt;zhangsan&lt;/string&gt;</Value>
</ConstantExpression>
<ConstantExpression NodeType="Constant" CanReduce="false">
  <Type>
    <Type Name="System.Guid"></Type>
  </Type>
  <Value>3dde3e8d-d2a6-4185-9a73-37e5231c6dc1</Value>
</ConstantExpression>

 

所以把KnownTypeExpressionXmlConverter.cs文件的46行

1 Type serializedType = resolver.GetType(element.Value);

 

修改为:

 1 Type serializedType;
 2 if (element.Elements().Count() == 1 )
 3 {
 4     var attribute = element.Elements().First().Attribute("Name");
 5     serializedType = attribute != null ? resolver.GetType(attribute.Value) : null;
 6 }
 7 else
 8 {
 9     serializedType = resolver.GetType(element.Value);                        
10 }

 

处理了接收Guid时的差异,再次运行,报异常如下:

【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(四)——关于Guid的问题 _ JavaClub全栈架构师技术笔记 View Code
System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: 从“System.String”到“System.Guid”的强制转换无效。 (错误详细信息等于 很可能由 Inclu
deExceptionDetailInFaults=true 创建的 ExceptionDetail,其值为:
System.InvalidCastException: 从“System.String”到“System.Guid”的强制转换无效。
   在 System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
   在 System.String.System.IConvertible.ToType(Type type, IFormatProvider provider)
   在 System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   在 ExpressionSerialization.ExpressionSerializer.ParseConstantFromElement(XElement xml, String elemName, Type expectedType) 位置 D:\我的文档\Visual Studio 2010\Projects\LambadaSerializeDemo\ExpressionSerialization\ExpressionSerializer(Deserialize).cs:行号 544
   在 ExpressionSerialization.ExpressionSerializer.ParseConstantExpressionFromXml(XElement xml) 位置 D:\我的文档\Visual Studio 2010\Projects\LambadaSerializeDemo\ExpressionSerialization\ExpressionSerializer(Deserialize).cs:行号 374
   在 ExpressionSerialization.ExpressionSerializer.ParseExpressionFromXmlNonNull(XElement xml) 位置 D:\我的文档\Visual Studio 2010\Projects\L...)。

 

在把Guid字符串转换为Guid类型时引起的异常,由ExpressionSerializer(Deserialize).cs的544行可知ExpressionSerializer使用Convert.ChangeType来进行类型转换的,而对于Guid,我们应该使用Guid.Parse来进行转换,所以添加Guid类型转换代码:

1 return Convert.ChangeType(objectStringValue, expectedType, default(IFormatProvider));

 

修改为:

1 return expectedType == typeof(Guid) ? Guid.Parse(objectStringValue) : Convert.ChangeType(objectStringValue, expectedType, default(IFormatProvider));

 

再次运行代码,结果与预期一致,问题解决:

【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(四)——关于Guid的问题 _ JavaClub全栈架构师技术笔记

总结:本次修改只为解决针对Guid的问题,以解决问题为目的,可能破坏了Dynamic Expression API与ExpressionSerialization的原有设计,如果哪位同学有更好的解决方案,希望不吝赐教。

本文源代码下载:

LambadaSerializeDemo04.rar

作者:郭明锋
来源链接:https://www.cnblogs.com/guomingfeng/archive/2012/04/22/2464589.html

版权声明:
1、Java侠(https://www.javaxia.com)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。





本文链接:https://www.javaxia.com/server/125282.html

分享给朋友:

“【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(四)——关于Guid的问题” 的相关文章