WCF中的REST架构二 (支持AJAX的WCF服务 - 创建服务)

我在昨天  的文章WCF中的 REST架构一(REST 概述)谈了REST的基本概要,并提出了从HI REST (高REST)到 LO REST (REST) RESTFULnessREST度)的概念。在今天的文章中,我将详细介绍大家可能最为熟悉的REST风格的 WCF 服务:支持AJAX的服务。此类服务应属于LO REST的范畴。现在很多人直觉地将“好”等同于“高大全”,因而低估了这种LO REST实现的价值。本篇将告诉你这决非事实,支持AJAXWCF服务是足够强大的。

解决方案的背景信息

我有一个底层工作已基本完整的
初始解决方案,大部分代码是作为12AJAX 客户库Webcast 系列的组成部分。提供这个初始解决方案的目的是为了让我更好地展现支持AJAX的WCF服务的强大能力,避免现场创建一个这样的服务然后再与AJAX 客户应用集成所需的冗长步骤(如何你认为我创建的范例应用乏善可陈,请试一下Supersefer,这是一个基于这个范例的希伯来文网上商店)。在这个初始解决方案中请特别注意两个ASP.Net AJAX 控件: Catalog.jsShoppingCart.js. 下面的截图就是这两个控件的显示



Catalog
控件是本篇的重要操作对象,它的任务是接受一个特定的数据结构,显示一页产品信息,作绑定用途,并在用户选中某样产品或者点击浏览控件的时候出发消息,至于该控件是如何与宿主页(Catalog.aspx)交互,大家可以在前面提到的Webcast系列中找到。就本篇而言,我们只要关注Catalog.aspx(宿主页)中的下列代码片段,里面有一个GetData() 方法。等我们实现了WCF服务之后,就在这个方法里调用它。我们会给WCF服务传入诸如startIndex(起始索引)和pageSize(页的大小)之类的参数(服务的返回数据将是指定页数的产品信息), 以及几个回调方法(服务调用成功或失败后被回调)。下面也给出了调用成功的回调方法。该方法直接获取了指向catalog控件的引用($get asp.netAJAX中用来指向一个控件)。然后它将设定当前页的索引值,再用传入回调函数的数据,也就是我们的WCF有效荷载,来设定productInfo属性。最后,该函数调用控件的dataBind方法,这个方法直接基于存储在productInfo属性中的数据做了一些DOM注入。

 

添加服务

添加一个支持AJAX WCF 服务相当简单。第一步就是使用'AJAX-enabled WCF Service'模板添加服务。过程如下:在Solution Explorer里面选择”Add New Item’ > 选择'AJAX-enabled WCF Service' > 将其命名为 CatalogService.cs > 点击 ‘Add’.



模板看起来相当神奇,其实它不过是添加了一些特定的文件,并更改了另一些文件(通常是*.config文件)而已。如果你是按照我的步骤,那么这个模板做了下列事情:
1.       在项目根目录下添加CatalogService.svc文件
2.       app_code目录下添加CatalogService.cs文件
3.       web.config内配置服务

分析一下生成的文件

我们来看一下上面模板生成的文件并稍加讨论:

CatalogService.svc
<%@ ServiceHost     Language="C#"
                   
Debug="true"
                   
Service="CatalogService"
                    
CodeBehind="~/App_Code/CatalogService.cs" %>

*.svc文件可以类比于*.asmx文件。如果该服务在IIS或者WAS上运行,这个文件就作为服务的可定位资源。换句话说,*.svc 就是你服务的的基址。这个文件里我们只需注意两个属性:首先是Service属性,该属性被设为实现该服务的CLR类型名(你可以在app_code目录下的CatalogService.cs中找到该类型)。第二个就是指向实现文件的CodeBehind属性。

你无需修改svc 文件的内容,我只是为了向你展示该文件就是作为服务的base地址。

web.config
<system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="CatalogServiceAspNetAjaxBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <services>
      <service name="CatalogService">
        <endpoint   address="" 
                    behaviorConfiguration="CatalogServiceAspNetAjaxBehavior"
                    binding="webHttpBinding" 
                    contract="CatalogService" />
      </service>
    </services>
  </system.serviceModel>

如果熟悉WCF,你一定知道WCF的配置是位于system.serviceModel节点下。你会看到3个子节点:behaviors, serviceHostingEnvironmentserivces:
1.  Services: 文件内已经有一个名为CatalogService的服务,与实现服务的类名一致。在Service节点下,你可以看到Endpoint,它包含了服务的ABCsAddress(地址) binding (绑定)和contract (协定).
    a.  Address: 你会发现地址是空的 ,不必担心,因为svc文件会作为基
    b.  Binding: webHttpBindingWCF3.5提供的可以让服务以REST方式发布的新型绑定。这个绑定有两种模式,你可以通过特定的终结点行为来指定模式(通过设定behaviorConfiguration)
    c.  Contract: contract指定了WCF服务提供的功能。该属性被设为一个已经定义好的服务协定。要定义一个服务协定,你可以用ServiceContract修饰一个接口或者类。被ServiceContract修饰的接口或者类中,所有由OperationContract修饰的方法将被作为服务的操作暴露给客户。一般来说用接口做服务协定是更好的做法,这样做的好处是分离了协定与具体实现。 但在我们使用的模板中却使用了类的方法,也就是说,接口是从类自动推断出来的(接口推断)。 
    d.  BehaviorConfiguration: 对于webHttpBinding, 你需要将该属性设为一个拥有webHttpenableWebScript子节点的终结点行为。

2. 
Behaviors: behaviors加入到服务或者服务终结点的目的在于改变runtime的默认行为或者加入定制的扩展。你会发现我们使用的模板已经声明了一个名为CatalogServiceAspNetAjaxBehavior的终结点行为该行为有一个enableWebScript 元素。enableWebScript是两种可能的终结点行为之一,另一种就是webHttp。事实上enableWebScriptwebHttp用来提供AJAX 功能(比如生成客户端代理)的子类

3. 
ServiceHostingEnvironment:
ASP.Net运行的WCF服务的默认配置是让两者互不干扰 例如,ASP.NET runtime 不参与WCF请求的处理. WCF服务也不能使用ASP.NET context session 这样的功能. 而我们这里的配置是将aspNetCompatibilityEnabled 设为true, 在这种设置下WCF请求就会加到ASP.Net 的请求流水线里了

*要使WCF支持REST,只要在该配置文件中注意最重要的两点:1binding应设为webHttpBinding 2) endpoint behavior要设定为webHttpenableWebScript

CatalogService.cs
 
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class CatalogService
{
    // Add [WebGet] attribute to use HTTP GET
    [OperationContract]
   
public void DoWork()
    {
        // Add your operation implementation here
        return;
    }
    // Add more operations here and mark them with [OperationContract]
}

在这里我们就真得做点儿事儿了。如果已经读了上面的内容,你应该已经注意到我们已经用接口推断的方法定义了的服务协定,就是说用ServiceContract属性修饰了一个类而不是一个接口。
无论如何,我们要开始做一点儿实现了。第一件事儿是设定ServiceContract属性的NameSpace参数。这一点非常重要。客户端用于调用WCF服务的代理的名字空间就是从这里拿的。我就将名字空间设为urn:shopping/services.[ServiceContract(Namespace = "urn:shopping/services")]

接下来,我要添加一个操作(就是一个用
OperationContract修饰的方法)。这个操作使用LINQ to SQL到数据库获取一页产品信息。该实现返回一个包含ProductData类型的ProductGroupingData 类型。我这样做的原因在于我不仅需要返回产品信息(ProductData),还需要一些有助于分页的元数据(StartIndex PageSizebut ProductGroupingTotalCount)。 下面就是这些类型:

[DataContract]
public class ProductData
{
   [DataMember]
   public int ProductId;
   [DataMember]
   public string ProductName;
   [DataMember]
   public string Description;
   [DataMember]
   public decimal Price;
   [DataMember]
   public string ProductImage;
}

[DataContract]
public class ProductGroupingData
{
   [DataMember]
   public List<ProductData> Products;
   [DataMember]
   public int StartIndex;
   [DataMember]
   public int PageSize;
   [DataMember]
   public int TotalCount = 0;
}

以下是实现代码:
[OperationContract]
public ProductGroupingData GetProductGrouping(int startIndex, int pageSize)
{
    using (CatalogDataContext catalogCtx = new CatalogDataContext())
    {
        // Set up the query
        var products = from p in catalogCtx.Products
                       orderby p.ProductName
                       select new ProductData()
                       {
                           ProductId = p.ProductId,
                           ProductName = p.ProductName,
                           Description = p.ProductDescription,
                           Price = p.Price,
                           ProductImage = p.ProductImage
                       };
 
        // Use skip and take extension methods for server side paging 
        //  and call ToList to execute the query
        var productColl = products.Skip(startIndex).Take(pageSize).ToList();
       // Add the metadata 
        var package = new ProductGroupingData()
        {
            Products = productColl,
            StartIndex = startIndex,
            PageSize = pageSize,
            TotalCount = catalogCtx.Products.Count()
        }; 

       
return package;

}

到这里,我们已经创建好了一个支持AJAX的服务。一个服务支持AJAX,就是说该服务可以非常容易地被一个 AJAX 客户端调用。接下来的 WCF中的REST架构 三,我就讨论如何在客户端调用服务.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值