Silverlight 2.0 資料庫應用程式開發(1)

Silverlight 2.0 資料庫應用程式開發(1),第1张

概述  Silverlight 2.0 資料庫應用程式開發 (1)     文 / 黃忠成   從 Silverlight 1.0 到 Silverlight 2.0      我想不用我贅言,相較於 Silverlight 1.0 的陽春, Silverlight 2.0 提供了更完整的資料庫支援,其最主要的部份在於提供了 WCF/HTTP 的網路機制及客戶端的控件 Binding 技術,有了這兩個

 

Silverlight 2.0 資料庫應用程式開發 (1)     / 黃忠成   Silverlight 1.0 Silverlight 2.0      我想不用我贅言,相較於 Silverlight 1.0 的陽春, Silverlight 2.0 提供了更完整的資料庫支援,其最主要的部份在於提供了 WCF/http 的網路機制及客戶端的控件 Binding 技術,有了這兩個機制,我們可以透過 WCF/http 網路機制連回 Server 端取得資料,然後以 Binding 技術將控件與資料結合在一起,設計出類似 windows Form/WPF UI 介面的強大網頁資料庫應用程式。   Silverlight 2.0 N-TIEr      對於部份的 ASP.NET 設計師而言,對 Silverlight 2.0 的資料庫應用程式的開發模式會有些陌生,在 ASP.NET 設計模式中,我們可以直接使用 ADO.NET 來取得資料,接著利用 GrIDVIEw 等資料控件將資料顯現於網頁上,此時的系統架構如圖 SL001 SL001

但在 Silverlight 2.0 中,並未提供 ADO.NET 這個機制,從網頁應用程式角度上看, Silverlight 2.0 是一種 ClIEnt Application 架構,運行於 IE 等瀏覽器平台之上,因此若要提供 ADO.NET 機制,那麼後端的資料庫必定得曝露於網際網路之上,而你肯定無法接受將 sql Server 曝露在網路上供人存取,因為這會帶來安全性、授權費等問題。所以,當使用 Silverlight 2.0 時,我們必須找一個相對於 ADO.NET 的機制來做為取得資料的中介層,這種設計模式就稱為 N-TIEr ,見圖 SL002 SL002

如圖 SL002 所示, Silverlight 應用程式是內嵌於 HTML 中下載,她可以透過 WCF/httpWebRequest 網路機制連回來源的 Web Site 取得資料,問題在於後端的 Web Site 如何接收來自 Silverlight 的網路要求?在 Silverlight 2.0 中,你有兩種選擇,一是在 Web Site 端建立一個簡單的網頁,收取來自 Silverlight 的網路要求,接著輸出 XML 或是 JsON 格式的資料。二是透過 .NET WCF 機制,於 Web Site 端建立一個 WCF Service ,於 Silverlight 中透過此 WCF Service 來取得資料。兩種機制各有其優缺點,方法一可以適用於所有網頁平台,例如 ASP PHP JsP 皆可,而方法二則是僅限於支援 Web Service 的網頁平台。     在開始設計實際應用程式之時,你必須先了解所謂 N-TIEr 架構的定義,所謂的 N-TIEr 指的是將整個程式架構切分為三個層面,第一層是展現層,也就是你的 Silverlight 應用程式,用來顯示資料及接受使用者 *** 作,第二層指的服務層,用來提供資料及回應來自展示層的要求,第三層則是資料層,用來由資料庫取得資料或是更新資料。 N-TIEr 早期的發展是為了分擔資料庫系統的繁重工作,以 [ 偶而連線 ] [ 負載平衡 ] 等技巧,減輕本來必須全部交與資料庫處理的工作。舉個例來說,一系統擁有 10000 個使用者,當使用傳統的 ClIEnt/Server 架構時,這 10000 個使用者會握有 10000 個資料連線,當這些使用者發出要求資料的 SELECT 需求時,資料庫系統就得負擔產生 10000 個資料集的工作,但這 10000 個需求中,很有可能有一半以上是要求同一份資料。當使用 N-TIEr 架構時,我們就可以在服務層中快取已取過的資料,當有同樣要求來臨時,直接以回傳快取資料的方式取代由資料庫系統取得的動作,這樣自然就減輕了資料庫的負擔,提高系統所能承載的用戶數量。     在早期網際網路頻寬不足的環境下, N-TIEr 架構原始設計中每個動作都要透過連結服務層的模式顯得有些不切實際,因為使用者可能處於一個低頻寬的環境、甚至是無網路可用的窘境,在這種模式下,存取服務層是種奢侈。因此, N-TIEr 發展出一種名為 [ 偶爾連線 ] 的模式,展示層在有網路的情況下,將資料由服務層取回後快取於客戶端,此時使用者可以自由的 *** 作展示層來新增、修改、刪除及查詢資料,這些動作全以客戶端的快取為主,待有網路時,再將異動資料整批傳回服務層更新回資料庫。    [ 偶爾連線 ] 的架構很完美,也很符合當年的需求,但隨著網路的普遍化及高覆蓋率,設計 [ 偶而連線 ] 架構所需付出的代價就顯得有些累贅了, [ 偶爾連線 ] 的架構建立在完善的客戶端快取機制及客戶端查詢機制下,而這些機制並不容易建構。所以,現在的 N-TIEr 轉變為以 [ 連線模式 ] 為主。    Silverlight 2.0 的架構趨近於 [ 連線模式 ] ,這意味著 Silverlight 2.0 的應用程式將運行在一個可存取網站的環境下,當這個網站存在於本機時,程式不需要網路便可執行,當網站不存在於本機時,則需要網路方能運行。

註:多數瀏覽器都有一種以離線模式執行網頁的設定,將離線模式打開,你依舊能在離線模式下運行 Silverlight 程式,在適當的設計下,其實也能做出 [ 偶爾連線 ] 模式。

    使用 httpWebRequest     在大略了解 Silverlight 2.0 N-TIEr 架構後,我們便可以開始撰寫 Silverlight 2.0 的資料庫應用程式,請建立一個 Silverlight 2.0 專案,接著於 Web 結尾之 Project 添加一資料庫。 SL003

SL004

然後添加一資料表至資料庫中。 SL005

建立結構。 SL006

添加資料列。 SL007

SL008

完成資料庫準備工作後,現在便可開始實作服務層,在這小節中,我們以傳統網頁模式來建立服務層,請於 Web 結尾之專案中添加一 Generic Handler( 你也可以使用 .aspx) SL009

DBProvIDer.ashx.cs
using System; using System.Collections.Generic; using System.linq; using System.Web; using System.Data; using System.Data.sqlClIEnt; using System.Configuration; using System.Xml.linq;   namespace DBDemo1.Web {     ///<summary>     /// Summary description for $codebehindclassname$     ///</summary>     public class DBProvIDer : IhttpHandler     {           public voID ProcessRequest(httpContext context)         {             context.Response.ContentType = "text/xml";             using (sqlConnection conn = new sqlConnection(@"Data Source=./sqlEXPRESS;AttachDbfilename=|DataDirectory|/MyDatabase.mdf;Integrated Security=True;User Instance=True"))             {                 Xdocument doc = new Xdocument(new XElement("Root"));                 using (sqlCommand cmd = new sqlCommand("SELECT * FROM CUSTOMERS",conn))                 {                     conn.open();                     using (sqlDataReader reader = cmd.ExecuteReader(                                          CommandBehavior.CloseConnection))                     {                         while (reader.Read())                         {                             XElement elem = new XElement("Customer");                             elem.Add(new XAttribute("CUSTOMER_ID",                                reader.GetString(reader.Getordinal("CUSTOMER_ID"))));                             elem.Add(new XAttribute("CUSTOMER_name",                                reader.GetString(reader.Getordinal("CUSTOMER_name"))));                             doc.Root.Add(elem);                         }                     }                     context.Response.Write(doc.ToString());                     context.Response.Flush();                     context.Response.End();                 }             }         }           public bool IsReusable         {             get             {                 return false;             }         }     } }

透過 IE 來測試此服務層是否運作正常。 SL010

由於本例將使用 DataGrID 控件,因此你必須透過 Add Reference( 加入參考 ) 來添加 DataGrID 所需要的 Assembly Silverlight 專案 ( 沒有 Web 結尾的那一個 ) SL011

SL012

另外,由於服務層使用 XML ,我們可以利用 Silverlight 2.0 所提供的 liNQ To XML 來簡化解譯 XML 的工作, liNQ To XML 需要添加 System.XML.linq.dll 為參考,請透過 Add Reference 來添加 System.XML.linq.dll Silverlight 專案中 ( 沒有 Web 結尾的那一個 ) SL013

接著在 Page.xaml 中鍵入以下的 XAML

Page.xaml
< UserControl x : Class ="DBDemo1.Page"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:data="clr-namespace:System.windows.Controls;assembly=System.windows.Controls.Data"     WIDth="400" Height="300" Loaded="UserControl_Loaded">     < GrID x : name ="LayoutRoot" Background ="White" Height ="300" WIDth ="400">         < data : DataGrID x : name ="grID" autoGenerateColumns ="True">         </ data : DataGrID >     </ GrID > </ UserControl >

最後在 Page.xaml.cs 中鍵入以下的程式碼。

Page.xaml.cs
using System; using System.Collections.Generic; using System.linq; using System.Net; using System.windows; using System.windows.Controls; using System.windows.documents; using System.windows.input; using System.windows.Media; using System.windows.Media.Animation; using System.windows.Shapes; using System.IO; using System.Xml; using System.Xml.linq;   namespace DBDemo1 {     public partial class Page : UserControl     {         public Page()         {             InitializeComponent();         }           private voID UserControl_Loaded(object sender,RoutedEventArgs e)         {             httpWebRequest request = (httpWebRequest)WebRequest.Create(                 new Uri("http://localhost:40419/DBProvIDer.ashx",UriKind.absolute));             request.Method = "POST";             request.BeginGetRequestStream(new AsyncCallback(ReadCallback),request);         }           private voID ReadCallback(IAsyncResult state)         {             httpWebRequest request = (httpWebRequest)state.AsyncState;                        Stream poststream = request.EndGetRequestStream(state);             //byte[] buff = System.Text.EnCoding.Unicode.GetBytes("TEST");             //poststream.Write(buff,buff.Length);             poststream.Close(); // the request stream must closed before             request.BeginGetResponse(new AsyncCallback(GetResponse),request);         }           private voID GetResponse(IAsyncResult state)         {             httpWebRequest request = (httpWebRequest)state.AsyncState;             httpWebResponse response = (httpWebResponse)request.EndGetResponse(state);             using (Stream stream = response.GetResponseStream())             {                 Xdocument doc = Xdocument.Load(stream);                 dispatcher.BeginInvoke(                   new System.Threading.ParameterizedThreadStart(UpdateUI), doc);             }         }          private voID UpdateUI(object state)         {             Xdocument doc = (Xdocument)state;             grID.ItemsSource = (from s1 in doc.Elements("Root").Descendants("Customer")                                 select new Customer()                                     {                                        ID = s1.Attribute("CUSTOMER_ID").Value,                                        name = s1.Attribute("CUSTOMER_name").Value                                     }).ToList();         }     }       public class Customer     {         public string ID { get; set; }         public string name { get; set; }     } }

SL014 是此例執行結果。 SL014

透過 httpWebRequest 的模式,我們可以用傳統網頁來扮演服務層,這可應用於多數網頁平台如 PHP ASP JsP 之上。   使用 WCF      使用 httpWebRequest 的方式雖然簡單,但缺點是我們得自訂其間資料傳送的格式,最大化相容性的結果也限縮了結構性,所幸在現今網路世界中早已定義了多數網頁平台都支援的資料格式,那就是 SOAP/Web Service Silverlight 2.0 除了允許我們撰寫 Web Service 的客戶端外,同時也支援了 .NET Framework 3.0 中所新增的 WCF Service ,本例就以 WCF Service 做為服務層,請添加一個 Web Service Web 結尾的專案中。 SL015

然後添加一個 liNQ To sql Classes Web 結尾的專案中,做為取代 ADO.NET 的資料存取機制。 SL016

添加資料表至 .DBML 中。 SL017

刪除自動產生的 IDBService.cs ,然後於 DBService.svc.cs 中鍵入以下程式碼。

DBService.svc.cs
using System; using System.Collections.Generic; using System.linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text;   namespace DBDemo1.Web {     [ServiceContract]     public interface IDBService     {         [OperationContract]         CUSTOMERS[] GetData();     }         public class DBService : IDBService     {                public CUSTOMERS[] GetData()         {             using (MyDBDataContext context = new MyDBDataContext())             {                 return (from s1 in context.CUSTOMERS select s1).ToArray();             }         }     } }

修改 web.config serviceModel 區段的設定。

web.config
............ < services >    < service behaviorConfiguration = "DBDemo1.Web.DBServiceBehavior"                name = "DBDemo1.Web.DBService">     < endpoint address = ""binding="basichttpBinding"contract="DBDemo1.Web.IDBService">      < IDentity >       < dns value = "localhost" />      </ IDentity >     </ endpoint >     < endpoint address = "mex"binding="mexhttpBinding"contract="IMetadataExchange" />    </ service >  </ services > ............

Silverlight 專案中,添加一 Service Reference( 服務參考 ) SL018

SL019

添加一 Silverlight UserControl SL020

程式碼如下所示。

Page2.xaml
< UserControl x : Class ="DBDemo1.Page2"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:data="clr-namespace:System.windows.Controls;assembly=System.windows.Controls.Data"     WIDth="400" Height="300" Loaded="UserControl_Loaded">     < GrID x : name ="LayoutRoot" Background ="White" Height ="300" WIDth ="400">         < data : DataGrID x : name ="grID" autoGenerateColumns ="True">         </ data : DataGrID >     </ GrID > </ UserControl >
Page2.xaml.cs
using System; using System.Collections.Generic; using System.linq; using System.Net; using System.windows; using System.windows.Controls; using System.windows.documents; using System.windows.input; using System.windows.Media; using System.windows.Media.Animation; using System.windows.Shapes;   namespace DBDemo1 {     public partial class Page2 : UserControl     {         public Page2()         {             InitializeComponent();         }           private voID UserControl_Loaded(object sender,RoutedEventArgs e)         {                        ServiceReference1.DBServiceClIEnt clIEnt =                  new DBDemo1.ServiceReference1.DBServiceClIEnt();             clIEnt.GetDataCompleted +=              new EventHandler<DBDemo1.ServiceReference1.GetDataCompletedEventArgs>(                clIEnt_GetDataCompleted);             clIEnt.GetDataAsync();         }           voID clIEnt_GetDataCompleted(object sender,                      DBDemo1.ServiceReference1.GetDataCompletedEventArgs e)         {             grID.ItemsSource = e.Result;         }     } }

此例執行結果同前例。   使用 ADO.NET Data Service Framework      WCF/Web Service 做為服務層雖然很完美,但設計師仍然得自行定義取得資料、查詢資料、更新資料的函式,在 .NET Framework 3.5 中,這些工作可以交給 ADO.NET Data Service Framework 來負責,這樣可以減輕設計師自行架構服務層規格的負擔,也能統一個別服務層的規格,避免不同設計師設計出不同的規格。預設情況下, ADO.NET Data Service Framework 的資料層必須是 ADO.NET Entity Framework ,所以請於 Web 結尾的專案中添加一 ADO.NET Entity Data Model 項目。 SL021

SL022

SL023

  SL024

完成後,在 Web 結尾的專案中添加一個 ADO.NET Data Service 項目。 SL025

WebDataService1.svc.cs 中鍵入以下程式碼。

WebDataService1.svc.cs
using System; using System.Collections.Generic; using System.Data.Services; using System.linq; using System.ServiceModel.Web; using System.Web;   namespace DBDemo1.Web {     public class WebDataService1 : DataService< EntityData.MyDatabaseEntitIEs>     {         // This method is called only once to initialize service-wIDe policIEs.         public static voID InitializeService(IDataServiceConfiguration config)         {             config.SetEntitySetAccessRule("*",EntitySetRights.All);             config.SetServiceOperationAccessRule("*",ServiceOperationRights.All);         }     } }

完成後編譯專案,接著於 Silverlight 2.0 添加一 Service Reference SL026

然後於 Silverlight 專案中添加一新的 Silverlight User Control

Page3.xaml
< UserControl x : Class ="DBDemo1.Page3"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:data="clr-namespace:System.windows.Controls;assembly=System.windows.Controls.Data"     WIDth="400" Height="300" Loaded="UserControl_Loaded">     < GrID x : name ="LayoutRoot" Background ="White" Height ="300" WIDth ="400">         < data : DataGrID x : name ="grID" autoGenerateColumns ="True">         </ data : DataGrID >     </ GrID > </ UserControl >
Page3.xaml.cs
using System; using System.Collections.Generic; using System.linq; using System.Net; using System.windows; using System.windows.Controls; using System.windows.documents; using System.windows.input; using System.windows.Media; using System.windows.Media.Animation; using System.windows.Shapes; using System.Data.Services.ClIEnt;   namespace DBDemo1 {     public partial class Page3 : UserControl     {         public Page3()         {             InitializeComponent();         }           private voID UserControl_Loaded(object sender,RoutedEventArgs e)         {             ServiceReference2.MyDatabaseEntitIEs3 entitIEs =             new DBDemo1.ServiceReference2.MyDatabaseEntitIEs3(                new Uri("WebDataService1.svc",UriKind.relative));             var result = from s1 in entitIEs.CUSTOMERS select s1;             ((DataServicequery<ServiceReference2.CUSTOMERS>)result).BeginExecute(                       new AsyncCallback(ReadCallback),result);         }           private voID ReadCallback(IAsyncResult state)         {             DataServicequery<ServiceReference2.CUSTOMERS> svcCtx =                 (DataServicequery<ServiceReference2.CUSTOMERS>)state.AsyncState;             //remember,you must call toList,toarray before set to itemsource.             grID.ItemsSource = svcCtx.EndExecute(state).ToList();         }     } }

此例執行結果如前例。使用 ADO.NET Data Service 的好處在於能統一存取資料時的服務端規格,尤其在 Silverlight 2.0 所提供的 ADO.NET Data Service ClIEnt Framework 的幫助下,設計師還能輕鬆的更新資料庫,其間資料傳遞及異動機制都不需要設計師 *** 心。   實作 [ 偶而連線 ] 模式      或許你曾經聽過, Sivlerlight 不支援離線 *** 作這檔事,事實的確是如此,但這指的是 Silverlight 不能像 Flash 般,包成一單一的執行檔來執行,透過 IE 等瀏覽器提供的離線模式,在沒有網路的情況下運行 Silverlight 程式依舊是可行的,前提是你的程式必須運用 Silverlight 2.0 中的 Isolate Storage 機制來儲存快取資料,而使用者至少需連線一次,讓相關的 Silverlight 程式下載到客戶端,下面的程式是一個可離線 *** 作的簡單例子。

Page4.xaml
< UserControl x : Class ="DBDemo1.Page4"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:data="clr-namespace:System.windows.Controls;assembly=System.windows.Controls.Data"     WIDth="400" Height="300" Loaded="UserControl_Loaded">     < GrID x : name ="LayoutRoot" Background ="White" Height ="300" WIDth ="400">         < data : DataGrID x : name ="grID" autoGenerateColumns ="True">         </ data : DataGrID >     </ GrID > </ UserControl >
Page4.xaml.cs
using System; using System.Collections.Generic; using System.linq; using System.Net; using System.windows; using System.windows.Controls; using System.windows.documents; using System.windows.input; using System.windows.Media; using System.windows.Media.Animation; using System.windows.Shapes; using System.IO; using System.IO.IsolatedStorage; using System.Xml.linq;     namespace DBDemo1 {     public partial class Page4 : UserControl     {         public Page4()         {             InitializeComponent();         }           private voID UserControl_Loaded(object sender,RoutedEventArgs e)         {             httpWebRequest request = (httpWebRequest)WebRequest.Create(                  new Uri("http://localhost:40419/DBProvIDer.ashx",request);         }           private voID ReadCallback(IAsyncResult state)         {             httpWebRequest request = (httpWebRequest)state.AsyncState;             Stream poststream = request.EndGetRequestStream(state);             //byte[] buff = System.Text.EnCoding.Unicode.GetBytes("TEST");             //poststream.Write(buff,request);         }           private voID GetResponse(IAsyncResult state)         {             try             {                 httpWebRequest request = (httpWebRequest)state.AsyncState;                 httpWebResponse response = (httpWebResponse)request.EndGetResponse(state);                 using (Stream stream = response.GetResponseStream())                 {                     using (var store = IsolatedStoragefile.GetUserStoreForApplication())                     {                         store.CreateDirectory("Data");                         IsolatedStoragefileStream subDirfile =                           store.Createfile(System.IO.Path.Combine("Data","dbdata.txt"));                         using (StreamWriter sw = new StreamWriter(subDirfile))                         {                             using(StreamReader sr = new StreamReader(stream))                             {                                 sw.Write(sr.ReadToEnd());                             }                         }                       }                     Xdocument doc = Xdocument.Load(stream);                     dispatcher.BeginInvoke(                        new System.Threading.ParameterizedThreadStart(UpdateUI),doc);                 }             }             catch (Exception ex)             {                 using (var store = IsolatedStoragefile.GetUserStoreForApplication())                 {                     IsolatedStoragefileStream subDirfile =                 store.Openfile(System.IO.Path.Combine("Data","dbdata.txt"),fileMode.Open);                     Xdocument doc = Xdocument.Load(subDirfile);                     subDirfile.Close();                     dispatcher.BeginInvoke(                   new System.Threading.ParameterizedThreadStart(UpdateUI),doc);                 }             }         }           private voID UpdateUI(object state)         {             Xdocument doc = (Xdocument)state;             grID.ItemsSource = (from s1 in doc.Elements("Root").Descendants("Customer")                                 select new Customer()                                 {                                     ID = s1.Attribute("CUSTOMER_ID").Value,                                     name = s1.Attribute("CUSTOMER_name").Value                                 }).ToList();         }     } }

適當使用 Isolate Storage 來儲存資料快取,可以讓應用程式減少網路流量,達到提升效率的目的。 SL027

  Next Time...     下次有機會的話,我們再來討論較進階的資料庫應用程式撰寫技巧,例如異動資料、查詢及處理關聯等等。   本文範例下載 总结

以上是内存溢出为你收集整理的Silverlight 2.0 資料庫應用程式開發(1)全部内容,希望文章能够帮你解决Silverlight 2.0 資料庫應用程式開發(1)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1053072.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存