WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF

我们知道发布REST WCF服务时,为了跨语言要求服务的参数和返回值都是简单对象(POCO类)。但当结合ADO.NET Entities Framework时,这些EntityObject 却不是我们想要的简单对象。有没有别的办法发布一个简单对象?好在ADO.NET团队发布了一个ADO.NET POCO Entity Generator项目模板利用T4代码生成可以将EF的相对复杂的EntityObject转换成一个POCO类。使用方法可以看这里:http://blogs.msdn.com/b/adonet/archive/2010/01/25/walkthrough-poco-template-for-the-entity-framework.aspx

先看看不使用POCO Entity发布的REST WCF服务是怎样的情况。创建一个WCF Rest Application工程:
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF
1. 准备:
创建一个 Northwind DB EF,并对应的创建一个REST服务:
[WebGet(UriTemplate = "Shippers", ResponseFormat=WebMessageFormat.Xml)] public List<Shippers> GetShippers() { using (var db = new NorthwindEntities()) { db.ContextOptions.LazyLoadingEnabled = false; db.ContextOptions.ProxyCreationEnabled = false; return db.Shippers.Take(10).ToList(); } }
注意必须将 EF 的 LazyLoadingEnabled 和 ProxyCreationEnabled 都设为false,否则调用会出错。

2. 运行并查看一下返回的内容(使用Fiddler发起一个Http请求,查看Response(XML格式)):
明显在xml中多了很多EF定义的序列化信息。这对于客户端反序列化带来一定的难度,尤其是作为参数传递对象的时候,拼接这样格式的XML非常的麻烦。
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF

再看看把上面的 ResponseFormat 改为 WebMessageFormat.Json 的结果:
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF
Oh,NO~ 直接就挂了。服务端对于 EntityObject 无法序列化成Json格式?

---------------- POCO分界线 ------------------

接下来请出 ADO.NET POCO Entity Generator 进行野猪大改造,剥离一些多余的属性:
1. 切换到 Northwind.edmx 的Model Browser中,右击Model项目:(在edmx视图的空白处右键也可以)
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF
2. 选择 "ADO.NET POCO Entity Generator" 模板:
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF
3. 将会有安全提示问是否要在本地生成代码,按下OK后就生成了POCO的代码,并将原来EF Design.cs里的原来的代码都删除了。
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF
改造后的EntityObject,属性变成只有 get; set;, Navigation Property 也由EntityCollection<T>变为ICollection<T>:
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF
再次运行,可以和未使用POCO类型的返回结果比较下看看是不是清爽了很多?
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF

现在再来看看修改为 Json 格式,OK这次没问题了。
WCF 实例 —— 基于ADO.NET POCO Entity Framework的REST WCF

话说回来既然连 ObjectContext 也是用 T4 重新生成的,那么下面两句代码也通过 T4 生成就不用每个服务方法里都去设定了。

db.ContextOptions.LazyLoadingEnabled = false;

db.ContextOptions.ProxyCreationEnabled = false;


查看 Northwind.context.tt 的代码,在最后可以看到下面的代码:
private void WriteLazyLoadingEnabled(EntityContainer container) { string lazyLoadingAttributeValue = null; string lazyLoadingAttributeName = MetadataConstants.EDM_ANNOTATION_09_02 + ":LazyLoadingEnabled"; if(MetadataTools.TryGetStringMetadataPropertySetting(container, lazyLoadingAttributeName, out lazyLoadingAttributeValue)) { bool isLazyLoading = false; if(bool.TryParse(lazyLoadingAttributeValue, out isLazyLoading)) { #> this.ContextOptions.LazyLoadingEnabled = <#=isLazyLoading.ToString().ToLowerInvariant()#>; <#+ } } } #>
把上面第11行:
this.ContextOptions.LazyLoadingEnabled = <#=isLazyLoading.ToString().ToLowerInvariant()#>
修改为:
this.ContextOptions.LazyLoadingEnabled = false;
this.ContextOptions.ProxyCreationEnabled = false;
生成的ObjectContext的构造函数中就会添加上面的两句代码,所有服务方法就不用设定上面属性了。
public NorthwindEntities() : base(ConnectionString, ContainerName) { this.ContextOptions.LazyLoadingEnabled = false; this.ContextOptions.ProxyCreationEnabled = false; }

使用 ADO.NET POCO Entity Generator 进行改造的EF,使得我们可以在服务端可以使用Linq2EF的ORM良好支持,又使得客户端不必为复杂的数据格式而烦恼,是在REST WCF应用中的一大利器。