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
    评论
在 Visual Studio 创建 WCF 服务时,有两种项目类型可供选择:WCF 服务应用程序和 WCF 服务库。这两种项目类型有以下区别: 1. WCF 服务应用程序是一种可执行文件,它包含了一个独立的 WCF 服务宿主。这意味着您可以直接运行 WCF 服务应用程序,并使用其自带的服务宿主来运行和测试您的 WCF 服务。当您部署 WCF 服务时,您可以将 WCF 服务应用程序部署到 IIS 或自定义的 Windows 服务。 2. WCF 服务库是一种库项目,它包含了一个或多个 WCF 服务契约和实现类。这意味着您必须将 WCF 服务库引用到另一个托管应用程序,然后手动配置该应用程序的服务宿主来运行和测试您的 WCF 服务。当您部署 WCF 服务时,您可以将 WCF 服务库部署到 IIS ,但必须将其部署为 WCF 服务应用程序的一部分。 3. WCF 服务应用程序和 WCF 服务库的项目结构也不同。WCF 服务应用程序包含了一个 .svc 文件和一个 Web.config 配置文件,用于配置 WCF 服务宿主和服务终结点。而 WCF 服务库只包含 WCF 服务契约和实现类,这些类通常包含在一个或多个 .cs 文件。 4. 在使用 WCF 服务应用程序时,您可以使用 Visual Studio 自带的 WCF 测试客户端来测试您的 WCF 服务。而在使用 WCF 服务库时,您必须手动编写测试客户端或使用第三方测试工具来测试您的 WCF 服务。 总之,WCF 服务应用程序是一种独立的 WCF 服务宿主,适用于独立运行和测试 WCF 服务。而 WCF 服务库则是一种库项目,适用于将 WCF 服务集成到其他托管应用程序

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值