精进不休 .NET 4.0 (6) - ADO.NET Data Services 1.5(WCF Data Services) 新特性

[索引页]
[源码下载]


精进不休 .NET 4.0 (6) - ADO.NET Data Services 1.5(WCF Data Services) 新特性


作者: webabcd


介绍
ADO.NET Data Services 1.5(WCF Data Services) 的新增功能
  • 支持服务端的 RowCount - 获取指定实体集合的成员数(只返回一个整型值,而不会返回实体集合) 
  • 支持服务端的分页 - 服务端可以返回分页后的数据,并且在其中还可以包含全部数据总数 
  • 支持服务端的 Select - 返回的结果只包括 Select 的字段 
  • 支持大数据传输 BLOB(binary large object)
  • 支持自定义数据服务 


示例
1、服务端 RowCount 的 Demo
MyDataService.svc.cs
代码
using  System;
using  System.Collections.Generic;
using  System.Data.Services;
using  System.Data.Services.Common;
using  System.Linq;
using  System.ServiceModel.Web;
using  System.Web;

namespace  DataAccess.DataServices.Service
{
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults 
=   true )]
    
public   class  MyDataService : DataService < MyEntity.AdventureWorksEntities >
    {
        
public   static   void  InitializeService(DataServiceConfiguration config)
        {
            config.DataServiceBehavior.MaxProtocolVersion 
=  DataServiceProtocolVersion.V2;
            config.SetEntitySetAccessRule(
" Products " , EntitySetRights.All);

            
//  SetEntitySetPageSize(string name, int size) - 新增的方法。用于提供分页后的数据
            
//      string name - 指定需要用于分页的实体集合
            
//      int size - 分页的页大小
            config.SetEntitySetPageSize( " Products " 5 );
        }
    }
}

RowCount.aspx.cs
代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Web;
using  System.Web.UI;
using  System.Web.UI.WebControls;

namespace  DataAccess.DataServices
{
    
public   partial   class  RowCount : System.Web.UI.Page
    {
        
protected   void  Page_Load( object  sender, EventArgs e)
        {
            MyDataServiceProxy.AdventureWorksEntities context 
=   new  MyDataServiceProxy.AdventureWorksEntities( new  Uri( " http://localhost:9046/DataServices/Service/MyDataService.svc/ " ));

            
//  支持服务端的 RowCount - 获取指定实体集合的成员数(只返回一个整型值,而不会返回实体集合)
            var productCount  =  context.Products.Count();
            Response.Write(productCount.ToString());
        }
    }
}

/*
$count - 返回 RowCount,即对应集合的成员数(只返回一个整型值,而不会返回实体集合)
http://localhost :9046/DataServices/Service/MyDataService.svc/Products/$count

$inlinecount=none - 只返回实体集合(分页后的数据)
http://localhost :9046/DataServices/Service/MyDataService.svc/Products?$inlinecount=none

$inlinecount=allpages - 在返回实体集合的基础上(分页后的数据),其中还会包括一个实体集合成员数(分页前的数据)的字段
http://localhost :9046/DataServices/Service/MyDataService.svc/Products?$inlinecount=allpages
*/


2、服务端分页的 Demo
MyDataService.svc.cs
代码
using  System;
using  System.Collections.Generic;
using  System.Data.Services;
using  System.Data.Services.Common;
using  System.Linq;
using  System.ServiceModel.Web;
using  System.Web;

namespace  DataAccess.DataServices.Service
{
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults 
=   true )]
    
public   class  MyDataService : DataService < MyEntity.AdventureWorksEntities >
    {
        
public   static   void  InitializeService(DataServiceConfiguration config)
        {
            config.DataServiceBehavior.MaxProtocolVersion 
=  DataServiceProtocolVersion.V2;
            config.SetEntitySetAccessRule(
" Products " , EntitySetRights.All);

            
//  SetEntitySetPageSize(string name, int size) - 新增的方法。用于提供分页后的数据
            
//      string name - 指定需要用于分页的实体集合
            
//      int size - 分页的页大小
            config.SetEntitySetPageSize( " Products " 5 );
        }
    }
}

Paging.aspx.cs
代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Web;
using  System.Web.UI;
using  System.Web.UI.WebControls;

namespace  DataAccess.DataServices
{
    
public   partial   class  Paging : System.Web.UI.Page
    {
        
protected   void  Page_Load( object  sender, EventArgs e)
        {
            MyDataServiceProxy.AdventureWorksEntities context 
=   new  MyDataServiceProxy.AdventureWorksEntities( new  Uri( " http://localhost:9046/DataServices/Service/MyDataService.svc/ " ));

            
//  支持服务端的分页 - 服务端可以返回分页后的数据,并且在其中还可以包含全部数据总数
            
//      服务端代码:config.SetEntitySetPageSize("Products", 5); 表示每页最多 5 条数据
            
//      客户端代码:通过 Skip() 方法来控制需要跳过的记录数
            var products  =  context.Products.Skip( 10 );

            
foreach  (var product  in  products)
            {
                Response.Write(product.ProductID.ToString() 
+   " <br /> " );
            }
        }
    }
}

/*
$skip=[int] - 指定需要跳过的记录数
http://localhost :9046/DataServices/Service/MyDataService.svc/Products?$skip=10

$inlinecount=none - 只返回实体集合(分页后的数据)
http://localhost :9046/DataServices/Service/MyDataService.svc/Products?$inlinecount=none

$inlinecount=allpages - 在返回实体集合的基础上(分页后的数据),其中还会包括一个实体集合成员数(分页前的数据)的字段
http://localhost :9046/DataServices/Service/MyDataService.svc/Products?$inlinecount=allpages
*/


3、服务端 Select 的 Demo
MyDataService.svc.cs
代码
using  System;
using  System.Collections.Generic;
using  System.Data.Services;
using  System.Data.Services.Common;
using  System.Linq;
using  System.ServiceModel.Web;
using  System.Web;

namespace  DataAccess.DataServices.Service
{
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults 
=   true )]
    
public   class  MyDataService : DataService < MyEntity.AdventureWorksEntities >
    {
        
public   static   void  InitializeService(DataServiceConfiguration config)
        {
            config.DataServiceBehavior.MaxProtocolVersion 
=  DataServiceProtocolVersion.V2;
            config.SetEntitySetAccessRule(
" Products " , EntitySetRights.All);

            
//  SetEntitySetPageSize(string name, int size) - 新增的方法。用于提供分页后的数据
            
//      string name - 指定需要用于分页的实体集合
            
//      int size - 分页的页大小
            config.SetEntitySetPageSize( " Products " 5 );
        }
    }
}

QueryProjection.aspx.cs
代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Web;
using  System.Web.UI;
using  System.Web.UI.WebControls;

namespace  DataAccess.DataServices
{
    
public   partial   class  QueryProjection : System.Web.UI.Page
    {
        
protected   void  Page_Load( object  sender, EventArgs e)
        {
            MyDataServiceProxy.AdventureWorksEntities context 
=   new  MyDataServiceProxy.AdventureWorksEntities( new  Uri( " http://localhost:9046/DataServices/Service/MyDataService.svc/ " ));

            
//  支持服务端的 Select - 返回的结果只包括 Select 的字段
            var products  =  context.Products.Select(p  =>   new  { ProductID  =  p.ProductID, Name  =  p.Name });

            
foreach  (var product  in  products)
            {
                Response.Write(product.ProductID.ToString() 
+   " "   +  product.Name  +   " <br /> " );
            }
        }
    }
}

/*
$select=[column1,column2,column3,...] - 返回的实体集合数据中只包括指定的字段
http://localhost :9046/DataServices/Service/MyDataService.svc/Products/?$select=ProductID,Name
*/


4、BLOB 的 Demo
BLOBService.svc.cs
代码
/*
ADO.NET Data Services 1.5 - 新增了对大数据传输 BLOB(binary large object)的支持
需要在概念模型(ConceptualModels)中的相关实体上增加属性“m:HasStream="true" xmlns:m="
http://schemas.microsoft.com/ado/2007/08/dataservices/metadata "”
*/

using  System;
using  System.Collections.Generic;
using  System.Data.Services;
using  System.Data.Services.Common;
using  System.Linq;
using  System.ServiceModel.Web;
using  System.Web;

using  System.IO;

namespace  DataAccess.DataServices.Service
{
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults 
=   true )]
    
public   class  BLOBService : DataService < MyEntity.AdventureWorksEntities > , IServiceProvider
    {
        
public   static   void  InitializeService(DataServiceConfiguration config)
        {
            config.DataServiceBehavior.MaxProtocolVersion 
=  DataServiceProtocolVersion.V2;
            config.SetEntitySetAccessRule(
" Products " , EntitySetRights.All);
        }

        
public   object  GetService(Type serviceType)
        {
            
if  (serviceType  !=   typeof (System.Data.Services.Providers.IDataServiceStreamProvider))
                
return   null ;

            
//  调用服务的时候,如果指定了需要流式传输大数据对象,则通过我们自定义的流式文件传输对象去处理
             return   new  ProductPhotoStreamProvider();
        }
    }

    
///   <summary>
    
///  自定义的一个流式文件传输类,需要实现 System.Data.Services.Providers.IDataServiceStreamProvider 接口
    
///   </summary>
     public   class  ProductPhotoStreamProvider : System.Data.Services.Providers.IDataServiceStreamProvider
    {
        
///   <summary>
        
///  获取流。将某个实体的某个属性以流类型的方式返回
        
///   </summary>
        
///   <param name="entity"> 相关的实体 </param>
        
///   <param name="operationContext"> 当前数据服务请求的上下文 </param>
        
///   <returns></returns>
         public  Stream GetReadStream( object  entity,  string  etag,  bool ?  checkETagForEquality, DataServiceOperationContext operationContext)
        {
            
if  (entity  as  MyEntity.Product  ==   null )
                
return   null ;

            
int  productId  =  (entity  as  MyEntity.Product).ProductID;

            
using  (var context  =   new  MyEntity.AdventureWorksEntities())
            {
                var product 
=  context.Products.First(p  =>  p.ProductID  ==  productId);
                var stream 
=   new  MemoryStream(product.ThumbNailPhoto);
                
return  stream;
            }
        }

        
public  Uri GetReadStreamUri( object  entity, DataServiceOperationContext operationContext)
        {
            
return   null ;
        }

        
//  流的内容类型
         public   string  GetStreamContentType( object  entity, DataServiceOperationContext operationContext)
        {
            
return   " image/jpeg " ;
        }

        
public   string  GetStreamETag( object  entity, DataServiceOperationContext operationContext)
        {
            
return   null ;
        }

        
//  流的缓冲区大小
         public   int  StreamBufferSize
        {
            
get  {  return   64 ; }
        }

        
public   void  DeleteStream( object  entity, DataServiceOperationContext operationContext)
        {
            
throw   new  NotImplementedException();
        }

        
public  System.IO.Stream GetWriteStream( object  entity,  string  etag,  bool ?  checkETagForEquality, DataServiceOperationContext operationContext)
        {
            
throw   new  NotImplementedException();
        }

        
public   string  ResolveType( string  entitySetName, DataServiceOperationContext operationContext)
        {
            
throw   new  NotImplementedException();
        }
    }
}

BLOB.aspx
代码
<% @ Page Title = ""  Language = " C# "  MasterPageFile = " ~/Site.Master "  AutoEventWireup = " true "
    CodeBehind
= " BLOB.aspx.cs "  Inherits = " DataAccess.DataServices.BLOB "   %>

< asp:Content  ID ="Content1"  ContentPlaceHolderID ="head"  runat ="server" >
</ asp:Content >
< asp:Content  ID ="Content2"  ContentPlaceHolderID ="ContentPlaceHolder1"  runat ="server" >

    
<!--
        查看元数据 - http://localhost:9046/DataServices/Service/BLOBService.svc/$metadata
    
-->

    
<!--
        Products(714) - 在 Products 集合中取主键为 714 的实体
        $value - 取流数据
    
-->
    
< img  src ="http://localhost:9046/DataServices/Service/BLOBService.svc/Products(714)/$value"  alt ="image"   />

</ asp:Content >


5、自定义数据服务的 Demo
CustomDataService.svc.cs
代码
/*
ADO.NET Data Services 1.5 - 新增了对自定义数据服务的支持 
*/

using  System;
using  System.Collections.Generic;
using  System.Data.Services;
using  System.Data.Services.Common;
using  System.Linq;
using  System.ServiceModel.Web;
using  System.Web;

namespace  DataAccess.DataServices.Service
{
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults 
=   true )]
    
public   class  CustomDataService : DataService < OrderContext >
    {
        
public   static   void  InitializeService(DataServiceConfiguration config)
        {
            config.DataServiceBehavior.MaxProtocolVersion 
=  DataServiceProtocolVersion.V2;
            config.SetEntitySetAccessRule(
" Orders " , EntitySetRights.All);
            config.SetEntitySetAccessRule(
" Products " , EntitySetRights.All);
        }
    }

    
///   <summary>
    
///  数据上下文
    
///   </summary>
     public   class  OrderContext
    {
        
static  List < Order >  _orders;
        
static  List < Product >  _products;
        
static  OrderContext()
        {
            _orders 
=   new  List < Order >
            {
                
new  Order { OrderId  =   0 , Customer = " webabcd " },
                
new  Order { OrderId  =   1 , Customer = " webabcdefg " }
            };

            _products 
=   new  List < Product >
            {
                
new  Product { ProductId  =   0 , ProductName = " wii " , Price = 100  }, 
                
new  Product { ProductId  =   1 , ProductName = " xbox360 " , Price = 200  }, 
                
new  Product { ProductId  =   2 , ProductName = " ps3 " , Price  =   300  }, 
                
new  Product { ProductId  =   3 , ProductName = " nds " , Price = 50  },
                
new  Product { ProductId  =   4 , ProductName = " psp " , Price = 100  }
            };

            _orders[
0 ].Items.Add(_products[ 0 ]);
            _orders[
0 ].Items.Add(_products[ 1 ]);

            _orders[
1 ].Items.Add(_products[ 2 ]);
            _orders[
1 ].Items.Add(_products[ 3 ]);
            _orders[
1 ].Items.Add(_products[ 4 ]);
        }


        
public  IQueryable < Order >  Orders
        {
            
get  {  return  _orders.AsQueryable < Order > (); }
        }

        
public  IQueryable < Product >  Products
        {
            
get  {  return  _products.AsQueryable < Product > (); }
        }
    }

    
/*
     * DataServiceKeyAttribute() - 指定主键字段
     * EntityPropertyMapping() - 实体属性到 ATOM 字段的映射,以便生成一个友好格式的 Feed 
     
*/
    [EntityPropertyMapping(
" Customer " , SyndicationItemProperty.AuthorName, SyndicationTextContentKind.Plaintext,  true )]
    [DataServiceKeyAttribute(
" OrderId " )]
    
public   class  Order
    {
        
public   int  OrderId {  get set ; }
        
public   string  Customer {  get set ; }

        
private  List < Product >  _items;
        
public  List < Product >  Items
        {
            
get
            {
                
if  (_items  ==   null )
                    _items 
=   new  List < Product > ();

                
return  _items;
            }
            
set
            {
                _items 
=  value;
            }
        }
    }

    [DataServiceKeyAttribute(
" ProductId " )]
    
public   class  Product
    {
        
public   int  ProductId {  get set ; }
        
public   string  ProductName {  get set ; }
        
public   int  Price {  get set ; }
    }
}

CustomDataService.aspx.cs
代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Web;
using  System.Web.UI;
using  System.Web.UI.WebControls;

namespace  DataAccess.DataServices
{
    
public   partial   class  CustomDataService : System.Web.UI.Page
    {
        
protected   void  Page_Load( object  sender, EventArgs e)
        {
            
//  使用自定义数据服务提供的服务
            CustomDataServiceProxy.OrderContext context  =   new  CustomDataServiceProxy.OrderContext( new  Uri( " http://localhost:9046/DataServices/Service/CustomDataService.svc/ " ));

            var orders 
=  context.Orders;

            
foreach  (var order  in  orders)
            {
                Response.Write(order.OrderId.ToString() 
+   " <br /> " );
            }
        }
    }
}


注:
以 URI 语法的方式查询 ADO.NET 数据服务的形式如下:
http://[Url]/[ServiceName]/[EntityName]/[NavigationOptions]?[QueryOptions]
详细语法参看 MSDN


OK
[源码下载]

你可能感兴趣的:(service)