話說上回介紹了ASP.NET AJAX Client Templates,資料的來源需為Javascript物件陣列的形式,為了簡化起見,我是以Javascript [ { ... }, { ... } ]的方式Hard-Coding產生物件陣列。而在實務上,我們多半會另外撰寫一個Web Page、Web Service或WCF作為資料來源。

在微軟構築的藍圖中,WCF已內建Client Script支援功能,整合的緊密度讓人驚豔,算是建構AJAX後端的王道。更進一步,若資料來源更直接地映對到資料庫DataTable時,則ADO.NET Data Service還能提供更密切的整合,甚至還有前端的MicrosoftAjaxAdoNet.js提供一缸子的Javascript Function協助,寫起Code來更加得心應手。關於ADO.NET Data Service的部分留到之後再談,今天我們先將焦點集中在WCF上。

我們延續先前的範例,目標是要產生一個有Id, Name, Score, RecTime的人員資料陣列,但這回我們要用WCF來實作。

首先,用VS2008在ASP.NET專案中新增一個WCF Service,命名為PeopleSource.svc,VS2008會幫你產生PeopleSource.svc, App_Code\IPeopleSource.cs, App_Code\PeopleSource.cs。

接著,我們把它修改成我們要的樣子:

IPeopleSource.cs:

[ServiceContract(Namespace="Darkthread")]
public interface IPeopleSource
{
    [OperationContract]
    List<Person> GetPeople(bool hideScore);
}
 
[DataContract]
public class Person
{
    [DataMember]
    public string Id { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public double Score { get; set; }
    [DataMember]
    public DateTime RecTime { get; set; }
}

PeopleSource.cs: (記得要using System.ServiceModel.Activation)

[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(
    RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class PeopleSource : IPeopleSource
{
    public List<Person> GetPeople(bool hideScore)
    {
        List<Person> people = new List<Person>();
        people.Add(new Person { Id="A01", Name="Jeffrey", 
            Score=(hideScore) ? -1 : 32767, RecTime = DateTime.Now });
        people.Add(new Person { Id="A02", Name="Fox Mulder",  
            Score=(hideScore)?-1:6242.25, 
            RecTime = DateTime.ParseExact("2008-11-05 12:00:50", 
            "yyyy-MM-dd HH:mm:ss", null) });
        people.Add(new Person { Id="A03", Name="Dana Scully", 
            Score=(hideScore)?-1:8391.66, RecTime= new DateTime(2008, 6, 15) });
        return people;
 
    }
}

另外,web.config裡要做一些設定,好開啟內建WCF支援Client Script的功能,MSDN上有詳細的介紹,這裡只列出修改後的樣子:

  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="default"></binding>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="webScriptEnablingBehavior">
          <enableWebScript/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="PeopleSourceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <services>
      <service behaviorConfiguration="PeopleSourceBehavior" name="PeopleSource">
        <endpoint address="" binding="webHttpBinding" 
                  contract="IPeopleSource"
                  bindingConfiguration="default"
                  behaviorConfiguration="webScriptEnablingBehavior">
        </endpoint>
      </service>
    </services>
  </system.serviceModel>

[Updated 2008-12-02] 以上的調整動作,在VS2008裡改建立AJAX-enabled WCF Service就可省略,請多利用。

接著,我們修改先前的ASPX,在ScriptManager中加入
<Services>
  <asp:ServiceReference Path="~/PeopleSource.svc" />
</Services>

神奇的事發生了,打入Darkthread(在IPeopleSource.cs裡宣告的ServiceContract Namespace),VS2008自動提示可用的Interface、Method名稱、呼叫參數,酷斃了!

我們將上回的ASPX內容稍作修改,主要是加入ServiceReference及呼叫Darkthread.IPeopleSource.GetPeople。WCF自動產生的Javascript端函數,第二參數onSuccess要宣告一個Function接收WCF傳回的結果。函數只有一個呼叫參數data,即為WCF端所return的物件。由於GetPeople宣告的傳回物件是List<Person>,在Javascript端,會透過JSON自動轉成有物件陣列,而物件有哪些屬性,則以先前在IPeopleSource.cs裡Person有宣告[DataMemeber]的屬性為準,也就是Id, Name, Score, RecTime。

如此一來,data跟上回Hard-Coding建出的物件陣列完全相同,我們直接dv.set_data(data)即可完成Client Side Binding,輕鬆愉快。

<asp:ScriptManager ID="ScriptManager1" runat="server">
  <Scripts>
    <asp:ScriptReference Path="~/js/jquery-1.2.6.js" />
    <asp:ScriptReference Path="~/js/MicrosoftAjaxTemplates.debug.js" />    
  </Scripts>
  <Services>
    <asp:ServiceReference Path="~/PeopleSource.svc" />
  </Services>
</asp:ScriptManager>
<script type="text/javascript">
    $(function() {
        var dv = $create(Sys.UI.DataView, {}, {}, {}, $get("tbTemplate"));
        Darkthread.IPeopleSource.GetPeople(false, function(data) {
            dv.set_data(data); 
            $("#tbTemplate").show();
        });
        
    });        
</script>
<table border="1" cellspacing="0" cellpadding="0"  style="font-size: 9pt; width: 300px;">
  <thead>
  <tr><th>Id</th><th>Name</th><th>Score</th><th>Record Time</th></tr>
  </thead>
  <tbody id="tbTemplate" style="display:none; padding: 3px;">
  <tr>
    <td style="text-align: center;">{{Id}}</td>
    <td>{{Name}}</td>
    <td style="text-align: right;">{{Score.format("N2")}}</td>
    <td style="text-align: center;">
    {{RecTime.format("yyyy/MM/dd HH:mm:ss")}}
    </td>    
  </tr>
  </tbody>            
</table>

執行網頁,我們得到與上回一模一樣的結果,不同的是,資料來源已改由WCF提供。

WCF函數傳回的List<T>可以當場轉成立即可用的Javascript Object Array,直接做為ASP.NET AJAX Client Templates的資料來源,非常簡便(尤其是VS2008還提供Javascript呼叫WCF時的Intellisense,讓人感動)。

講到這裡,有沒有聯想到什麼?

Yes! LINQ查詢的結果不就可以轉成List<T>? 大家知道可以怎麼玩了吧!


Comments

Be the first to post a comment

Post a comment