65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 JSONP 和 SOAP 端点调用 WCF 服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (15投票s)

2012年7月26日

CPOL

4分钟阅读

viewsIcon

90431

downloadIcon

2908

一个简单的应用程序,使用 jQuery/JSONP 和 XML/SOAP 实现来消费 WCF 服务。

介绍  

几个月前,我开始研究从 Web 服务消费 JSON 对象的一些功能。我决定实现 WCF 来测试与 JSON 数据的良好集成。

Gary Stafford 杰出的文章 帮助我配置了第一个跨域 JSON 应用程序,该应用程序消费 REST/JSONP WCF 服务。这包括在服务中设置跨域“JSONP 终结点”。

该示例满足了一部分需求,但为了配置相同的 WCF 服务以通过常规的服务引用 SOAP 代理进行消费,我花了一周的时间进行研究。在此阶段,我需要第二个“终结点”配置。

背景 

首先请记住,JSONP 或“带填充的 JSON”是对 JSON 数据格式的补充。它用于从部署在不同域中的服务器请求数据,这被许多 Web 浏览器禁止。

WCF 服务用于企业应用程序开发。除许多优点外,WCF 还可以在同一服务上提供多个终结点(HTTP、TCP 等)。

通过配置具有 JSONP 和 SOAP 终结点的 WCF 服务,您可以使其可供不同类型的客户端访问。这对于能够消费 WCF 代理的客户端以及进行 JSONP 数据 HTTP 通信的客户端很有用。

REST(Representational State Transfer,表述性状态转移)以几种纯文本格式提供来自服务的直接响应。如果 WCF 服务使用的是 REST/JSONP,那么客户端就不需要消费 WCF 服务代理了。

REST/JSONP 在需要 JSON 数据来处理前端显示的 Ajax 应用程序中性能非常重要。现在,只需通过简单的 HTTP 通信即可获取该数据。

示例

此示例基本上是一个服务器应用程序 MyService,它运行一个 WCF 服务,该服务具有两个不同的终结点供 Web 客户端应用程序 MyClient 消费。

  • SOAP 终结点从客户端方法 loadDropDownSOAP() 使用,该方法填充 ASP 下拉列表服务器控件。
  • 第二个 REST/JSONP 终结点也由 JavaScript 方法 loadDropDownJSONP() 使用,该方法尝试填充另一个下拉列表。这次,该方法只需要一次 HTTP 调用即可从服务中获取数据。

客户端应用程序的外观和感觉非常简单。只需点击“使用 JSONP 调用加载”和“使用 SOAP 调用加载”即可启动这两个操作。

使用代码

zip 文件夹包含在 Visual Studio 2010(框架 4.0)中实现的两个网站应用程序。MyServiceMyClient 已准备好在本地环境中进行编译和测试:

  • MyClient。您可以构建并运行该应用程序。客户端应用程序将在 https://:7726/ 上执行。
  • MyService。也已准备好执行。该服务将在 https://:6573/Service.svc 上运行。

下面您可以阅读有关最相关文件的更多实现细节。

MyService - Web.config

请查看终结点和绑定配置。SOAP 请求将需要处理 address="soap" 终结点设置。

对于 REST/JSONP 终结点,重要的是使用 binding="webHttpBinding";对于 SOAP 终结点,则使用 binding="basicHttpBinding"

<?xml version="1.0"?>
<configuration>

  <appSettings>
  </appSettings>
  <system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="false" />

    <services>
      <service behaviorConfiguration="WebServiceBehavior" name="MyService.Service">
        <endpoint address="" behaviorConfiguration="jsonBehavior" binding="webHttpBinding"
          bindingConfiguration="webHttpBindingWithJsonP" contract="MyService.IService" />
        <endpoint address="soap" binding="basicHttpBinding" contract="MyService.IService" />
      </service>
    </services>

    <behaviors>
      <endpointBehaviors>
        <behavior name="jsonBehavior">
          <webHttp helpEnabled="true"/>
        </behavior>
      </endpointBehaviors>

      <serviceBehaviors>
        <behavior name="WebServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <bindings>
      <webHttpBinding>
        <binding name="webHttpBindingWithJsonP"
                 crossDomainScriptAccessEnabled="true" />
      </webHttpBinding>
    </bindings>
  </system.serviceModel>

  <system.web>
    <compilation debug="false" targetFramework="4.0" />
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

MyService - Iservice.cs(服务合同)

响应的格式在两个操作合同中都已设置。可以是 WebMessageFormat.JsonWebMessageFormat.Xml

[ServiceContract]
public interface IService
{
    [OperationContract]     
    [WebGet(BodyStyle = WebMessageBodyStyle.Bare,
    RequestFormat = WebMessageFormat.Json,
    ResponseFormat = WebMessageFormat.Json,
    UriTemplate = "/GetTourListJSONP/")]
    cTourList GetTourListJSONP();
             
    [OperationContract]       
    [WebGet(BodyStyle = WebMessageBodyStyle.Bare,
    RequestFormat = WebMessageFormat.Xml,
    ResponseFormat = WebMessageFormat.Xml,
    UriTemplate = "/GetTourListXML/")]
    cTourList GetTourListXML();
}

MyService - Service.scv.cs(IService 接口的实现)

两个服务方法都返回一个基于 cTour 对象集合实现的 tours 列表,该列表包含在 cTourList 类中。

public class Service : IService
{
    public cTourList GetTourListJSONP()
    {
        return CreateTourList();
    }

    public cTourList GetTourListXML()
    {
        return CreateTourList();
    }
    
    private cTourList CreateTourList()
    {
        cTourList oTourList = new cTourList();
        oTourList.Add(new cTour() { ID = 1, description = "Barcelona" });
        oTourList.Add(new cTour() { ID = 2, description = "Paris" });
        oTourList.Add(new cTour() { ID = 3, description = "Rome" });
        oTourList.Add(new cTour() { ID = 4, description = "London" });
        oTourList.Add(new cTour() { ID = 5, description = "Moscow" });

        return oTourList;
    }
}

一旦服务在 Visual Studio 中运行,就可以使用 WCF 测试客户端测试两个终结点。建议在最终使用客户端应用程序之前进行此操作。

MyClient - Web.config

来自客户端应用程序的 SOAP 调用需要在项目中进行服务引用设置。您可以通过打开 Visual Studio 2010 -> Project -> Add Service Reference  来进行处理。

添加服务引用后,请确保“address”的“soap”文本包含在终结点中:address="https://:6573/Service.svc/soap"。否则,SOAP 调用将不成功。

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="false" targetFramework="4.0" />
  </system.web>

  <system.webServer>
     <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>  
  
  <system.serviceModel>
    
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
              realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://:6573/Service.svc/soap" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IService" contract="WCFReference.IService"
        name="BasicHttpBinding_IService" />
    </client>
    
  </system.serviceModel>
  
</configuration>

MyClient - Default.aspx.cs

方法 loadDropDownSOAP() 使用我们上面注释的 SOAP 终结点。调用返回一个在 WCFReference.cTourList 中实现的结构。

public partial class _Default : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        // sets dropdown list empty
        DropDownListSOAP.Items.Clear();
        loadDropDownSOAP();
    }

    private void loadDropDownSOAP()
    {
        // XML-SOAP CALL TO WCF SERVICE
        WCFReference.ServiceClient oWebservice = new WCFReference.ServiceClient();
        WCFReference.cTourList oTourList = oWebservice.GetTourListXML();

        foreach (WCFReference.cTour oTour in oTourList)
        {
            DropDownListSOAP.Items.Add(new ListItem(oTour.description, Convert.ToString(oTour.ID)));
        }
    }
}

MyClient - Scripts/base.js

此文件包含 $.ajax 调用,该调用将使用 WCF 服务上配置的一个特定终结点以 REST/JSONP 模式从 WCF 服务检索数据。变量 wcfServiceUrl 包含服务的默认 HTTP 地址。

请注意,JavaScript 方法使用 jQuery 填充下拉列表。$.ajax 调用返回包含在 jsonpCallback: "tourList" 结构中的 tours 列表。

var wcfServiceUrl, populateDropdown;
 
// default URL WCF service
wcfServiceUrl = "https://:6573/Service.svc/";


populateDropdown = function () {
    var ID, description;
    ID = this.ID;
    description = this.description;

    $("#selectJSON")
        .append($("<option></option>")
        .val(ID)
        .html(description));    
};

function loadDropDownJSONP(idDropdownJson, idDropdownSoap) {

    // sets both dropdown lists empty
    $("#" + idDropdownSoap + "").html("");
    $("#" + idDropdownJson + "").html("");

    // JSONP CALL TO WCF SERVICE
    $.ajax({
        cache: false,
        url: wcfServiceUrl + "GetTourListJSONP",
        data: "{}",
        type: "GET",
        jsonpCallback: "tourList",
        contentType: "application/javascript",
        dataType: "jsonp",
        error: function () {
            alert("list failed!");
        },
        success: function (list) {
            $.each(list, populateDropdown); // must call function as var
        }
   });
}

历史 

  • 2012/04/26:文章初次发布。
© . All rights reserved.