精进不休 .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 { getset; }
        
public string Customer { getset; }

        
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 { getset; }
        
public string ProductName { getset; }
        
public int Price { getset; }
    }
}

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
[源码下载]
posted @ 2010-06-11 09:29  webabcd  阅读(6651)  评论(6编辑  收藏  举报