使用WCF更新數據

        雖然基於Web Service 的SOAP和POST並不總是加載數據的理想機制,但它們仍然適合用於對方法的調用,特別是對複雜數據的輸入或修改。使用WCF時,並不真正需要作出一區分——同樣的WCF方法能夠像簡單XML終結點或SOAP終結點一樣發佈。服務層將完全由AJAX界面分開,既不需要改變服務中的代碼,也不需要對AJAX或者任何其他客戶端技術指定任何的約束。事實上,可以選擇在一些替代的傳輸機制上發佈WCF應用。例如MSMQ、TCP/IP,甚至SMTP。

        注意:
                 Wiki是爲了便於在Web上進行溝通而開發的一種記事本類應用程序,其設計宗旨是能夠高效、簡便地使用。下例中同時建立一個知識基礎應用來學習使用Wiki技術。更多                  關於Wiki的信息參見 http://en.wikipedia.org/wiki/Wiki

        建立簡單的Web Service來記錄應用狀態的消息。首先,定義一個名叫WikilData的數據類,這個類是WCF服務的起始點——它定義了服務返回的消息。可以使用DataContract和DataMember屬性來定義數據結構,在WikiData類中,使用DataContract屬性來定義元素的命名空間,使用DataMember屬性來定義XML序列元素(WikiData類的定義參見下面代碼)。定義這個協議後,就能夠編寫任何針對這種數據格式的客戶端應用。

    [DataContract(Name = "WikiData",
        Namespace = "ServiceOrientedAjax.Examples")]
    public class WikiData
    { 
        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string Body { get; set; }

    }

輸出的格式如下:
<WikiData xmlns="ServiceOrientedAjax.Examples" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Body>Hello WCF World!</Body> 
  <Title i:nil="true" /> 
  </WikiData>


        在定義了數據協議之後,下一步是實現服務。可以是用VS模板或者通過定義標有ServiceContract屬性的類來創建服務。ServiceContract屬性將這個類標記爲WCF的服務實現。每一個作爲Web Service終結點發布的方法都必須使用OperationContract屬性進行標識。OperationContract屬性與ASP.NET Web Service中使用的WebMethod相似,定義了一個通過WCF終結點發布的方法。
        由於定義具有DataContract屬性的數據類WikiData,因此能夠簡單使用WikiData作爲Get請求的返回類型以及Set操作的輸入參數。下列程序定義了一個簡單WCF服務,此服務使用上例中的wikiData數據協定。

  [ServiceContract(Namespace = "ServiceOrientedAjax.Examples")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service1 
    {
        [OperationContract]
        public void SetWiki(WikiData wiki)
        {
            HttpContext.Current.Application[wiki.Title] = wiki.Body;
        }

        [OperationContract]
        [WebGet]
        public WikiData GetWiki(string title)
        {
            WikiData wiki = new WikiData 
            { 
                Title=title,
                Body=(string)HttpContext.Current.Application[title] ?? "Hello WCF World!"
            };
            return wiki;
        }
    }

        在定義了WCF服務之後,需要在ASP.NET應用中通過服務文件(SVC文件)和web.config定義終結點。SVC文件時ASP.NET中用來激活WCF服務終結點的簡單文本文件,該文件中應當包含一下對 Service1 WCF終結點的引用:
<%@ ServiceHost  Service="WcfServiceLibrary1.Service1" %>

        除了在SVC文件中定義服務終結點之外,還必須在web.config中定義終結點和行爲。這些行爲可以影響多個終結點,並且能夠改變終端訪問WCF終結點的方式。在這個例子中,定義了POX終結點以及包括enableWebScript在內的JSON-enable終結點。這些增加的行爲可以通過behaviorConfiguration元素來啓用。
        爲了啓用ASP.NET AJAX來爲服務建立JavaScript代理類,可以指定能夠映射到多個WCF終結點的enableWebScript行爲。下面的例子定義了名爲JsonBehavior的行爲配置項(JsonBehavior 是隨意選擇的命名),其中包含着enableWebScript行爲:
 <behavior name="JsonBehavior">
          <enableWebScript />
        </behavior>

        enableWebScript行爲使用JavaScript對象符號來定義數據,將默認響應從XML格式轉換JSON格式。在手工處理數據並且不能使用XSLT轉換時,這種格式比較易於處理。由於WCF從實現中抽象出終結點行爲,因此可以在web.config內定義XML終結點和JSON終結點而不會導致服務的任何改變。非常重要的一點是:這種映射通過配置而不是服務來開發完成。
        爲了定義一個負載的提供JSON數據的終結點,可以使用web.config將終結點映射到行爲配置上。例如將一個附加的終結點(這是一個具備與Service.svc終結點同樣實現的JSON-enable終結點)映射到Service.svc/json上。要定義這個終結點,需要使用一個子終結點元素來創建服務元素,終結點元素爲服務定義了地址、行爲配置、綁定以及協定。終結點的地址與激活WCF服務的.svc文件相關,behaviorConfiguration定義了終結點的附加行爲。接下來的例子爲Service1定義了服務中金額的,同時含有一個映射到/json、使用JsonBehavior配置的附加終結點。
 <services>
      <service name="WcfServiceLibrary1.Service1" behaviorConfiguration="Global">
        <endpoint address="" behaviorConfiguration="PoxBehavior"
        binding="webHttpBinding" contract="WcfServiceLibrary1.Service1" />
        <endpoint address="json" behaviorConfiguration="JsonBehavior"
        binding="webHttpBinding" contract="WcfServiceLibrary1.Service1" />
      </service>
    </services>

         當通過具有enableClientScipt行爲的終結點訪問服務時,上面的數據協定會輸出如下的JSON數據類:
{"wiki":{"Title":"default","Body":"Hello WCF World!"}}

        這個JSON格式數據流包含着與數據協定定義的XML輸出相同的內容。由於在腳本中,JSON流比較容易使用,因此如果你不使用XSLT轉換器,Microsoft將選擇它作爲腳本激活的Web Service的默認行爲。
        由於已經具備了在web.config中爲/json終結點定義的enableWebScript行爲,ASP.NET AJAX運行環境會爲服務生產一個JavaScript代理,這個代理能夠調用WCF服務並獲取相應。爲了手工檢查JavaScript代理,要使用WCF終結點並在URL後面加上/jsdebug開工選項,例如: http://localhost/ajaxfundamentals/simpleservice.svc/json/jsdebug 。代理中會含有通過ASP.NET AJAX JavaScript框架調用Web Service的正確的JavaScript語法細節,包括用來調用和索引數據的序列化對象,此時,你所需要了解的就是直接調用的實例方法。對於每一個Web Service操作,在方法的參數中應當添加 onSuccess  、onFailed 以及 userContext。由於所有的網絡調用都是以異步方式的,因此必須爲響應傳遞迴調句柄。儘管能夠將任意對象作爲用戶上下文進行傳遞,但通常userContext對象是原樣傳遞給公共代理方法,包括GetWiki方法和SetWiki方法。實際的代理中包含更多的代碼,但通常你需要調用的方法是對於公共服務方法的JavaScript函數。

 
SetWiki:function(wiki,succeededCallback, failedCallback, userContext) {
/// <param name="wiki" type="ServiceOrientedAjax.Examples.WikiData">WcfServiceLibrary1.WikiData</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'SetWiki',false,{wiki:wiki},succeededCallback,failedCallback,userContext); },
GetWiki:function(title,succeededCallback, failedCallback, userContext) {
/// <param name="title" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'GetWiki',true,{title:title},succeededCallback,failedCallback,userContext); }


        在引用ASP.NET AJAX生成的JavaScript代理類後,才能在AJAX應用中使用這段代碼,這就需要在Service節點中使用ScriptManager控件,定義對Service.svc的引用。爲了增加ServiceReference,需要把帶有Path參數的ServiceReference加到WCF終結點中,如下所示:

 <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Services>
            <asp:ServiceReference Path="~/Service.svc/json" /></Services>
    </asp:ScriptManager>

下面是整體的程序清單:
HTML界面:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Services>
            <asp:ServiceReference Path="~/Service.svc/json" /></Services>
    </asp:ScriptManager>
    <div id="MainContent" onclick="editMessage">
        Loading....
    </div>
    <br />
    <span style="border:solid 1px silver;" id="editButton" onclick="editMessage();">
        Edit
    </span>
    <div id="EditorRegion" style="display:none;">
        <textarea id="TheEditor" rows="10" cols="10">
        </textarea>
        <br />
        <span style="border:solid 1px silver;" onclick="save();">
            Save
        </span>
    </div>
    </form>

    <script language="javascript" type="text/javascript">

        var wikiName = 'default';

        function OnAjaxLoad() {
            var userContext = new Object();
            ServiceOrientedAjax.Examples.Service1.GetWiki(wikiName, getMessageSuccess, onMessageFailure, userContext);
        }

        function editMessage() {
            $get('EditorRegion').style.display = '';
            $get('editButton').style.display = 'none';
            $get('MainContent').style.display = 'none';
            $get('TheEditor').value = $get('MainContent').innerHTML;
            $get('TheEditor').enabled = true;
        }

        function getMessageSuccess(wikiData, userContext) {
            var EditorRegion = $get('EditorRegion');
            EditorRegion.style.display = 'none';
            var content = $get('MainContent');
            content.innerHTML = wikiData.Body;
            content.style.display = '';
            $get('editButton').style.display = '';
        }

        function save() {
            var msg = $get('TheEditor').value;
            var userContext = new Object();
            userContext.msg = msg;
            userContext.title = wikiName;
            var wiki = new Object();
            wiki.Title = wikiName;
            wiki.Body = msg;
            ServiceOrientedAjax.Examples.Service1.SetWiki(wiki, onSaveSuccess, onMessageFailure, wiki);
            $get('TheEditor').enabled = false;
        }

        function onSaveSuccess(response, wiki) {
            getMessageSuccess(wiki, null);
        }

        function onMessageFailure(ex, userContext) {

            var EditorRegion = $get('EditorRegion');
            EditorRegion.style.display = 'none';
            var content = $get('MainContent');
            content.innerHTML = ex.get_message();
            content.style.display = '';
        }

        Sys.Application.add_load(OnAjaxLoad);
    </script>
</body>
</html>

WCF服務類:
using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Web;
using System.Runtime.Serialization;

namespace WcfServiceLibrary1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
    [ServiceContract(Namespace = "ServiceOrientedAjax.Examples")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service1 
    {
        [OperationContract]
        public void SetWiki(WikiData wiki)
        {
            HttpContext.Current.Application[wiki.Title] = wiki.Body;
        }

        [OperationContract]
        [WebGet]
        public WikiData GetWiki(string title)
        {
            WikiData wiki = new WikiData 
            { 
                Title=title,
                Body=(string)HttpContext.Current.Application[title] ?? "Hello WCF World!"
            };
            return wiki;
        }
    }

    [DataContract(Name = "WikiData",
        Namespace = "ServiceOrientedAjax.Examples")]
    public class WikiData
    { 
        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string Body { get; set; }

    }
}


Web.config 配置:
<system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="PoxBehavior">
          <webHttp />
        </behavior>
        <behavior name="JsonBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="Global">
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <!--   -->
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

    <services>
      <service name="WcfServiceLibrary1.Service1" behaviorConfiguration="Global">
        <endpoint address="" behaviorConfiguration="PoxBehavior"
        binding="webHttpBinding" contract="WcfServiceLibrary1.Service1" />
        <endpoint address="json" behaviorConfiguration="JsonBehavior"
        binding="webHttpBinding" contract="WcfServiceLibrary1.Service1" />
      </service>
    </services>
    
  </system.serviceModel>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章