項目介紹
這節將要把《一步一步學 Linq to sql (三):增刪改》中留言簿的例子修改爲使用 WCF 的多層構架。我們將會建立以下項目:
l A ,網站項目 WebSite :留言簿表現層
l B ,類庫項目 Contract :定義數據訪問服務的契約
l C ,類庫項目 Service :定義數據訪問服務
l D ,類庫項目 Entity :留言簿實體
l E ,控制檯項目 Host :承載數據訪問服務
項目之間的引用如下:
l A 引用 B 和 D ;
l B 引用 D 和 System.ServiceModel 程序集
l C 引用 B 、 D 、 System.ServiceModel 以及 System.Data.Linq 程序集
l D 引用 System.Data.Linq 程序集
l E 引用 C 和 System.ServiceModel 程序集
生成映射文件和實體
打開 VS2008 命令行提示,執行以下命令:
sqlmetal /conn:server=xxx;database=GuestBook;uid=xxx;pwd=xxx /map:c:/guestbook.map /code:c:/guestbook.cs /serialization:Unidirectional |
注意到,這裏我們使用了 serialization 開關,告知 sqlmetal 在生成實體的時候自動把它們標記爲 WCF 數據對象。生成結束後把 C:/GUESTBOOK.CS 添加到 Entity 項目中。
編寫數據訪問服務
首先我們可以定義出留言簿數據訪問服務的契約(接口),把如下的代碼保存爲 IDataAccess.cs 放在 Contract 類庫項目中:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel;
namespace Contract { [ServiceContract ] public interface IDataAccess { [OperationContract ] void SendMessage(TbGuestBook gb);
[OperationContract ] List <TbGuestBook > GetData();
[OperationContract ] void DeleteMessage(string ID);
[OperationContract ] void SendReply(TbGuestBook gb); } } |
在這裏定義了四個方法:
l 創建留言
l 獲取所有留言
l 刪除留言
l 管理員發表回覆
然後,我們來實現這個契約,把如下代碼保存爲 DataAccess.cs 放在 Service 類庫項目中:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Contract; using System.Data.Linq.Mapping; using System.IO; using System.ServiceModel;
namespace Service { [ServiceBehavior (IncludeExceptionDetailInFaults = true )] public class DataAccess : IDataAccess { GuestBook ctx;
public DataAccess() { XmlMappingSource xms = XmlMappingSource .FromXml(File .ReadAllText("c://guestbook.map" )); ctx = new GuestBook ("server=srv-devdbhost;database=GuestBook;uid=sa;pwd=Abcd1234" , xms); ctx.Log = Console .Out; }
public void SendMessage(TbGuestBook gb) { ctx.TbGuestBook.Add(gb); ctx.SubmitChanges(); }
public List <TbGuestBook > GetData() { var query = from gb in ctx.TbGuestBook orderby gb.PostTime descending select gb; return query.ToList();
}
public void DeleteMessage(string ID) { TbGuestBook gb = ctx.TbGuestBook.Single(message => message.ID == new Guid (ID)); ctx.TbGuestBook.Remove(gb); ctx.SubmitChanges(); }
public void SendReply(TbGuestBook gb) { //ctx.ExecuteCommand("update tbGuestBook set reply={0},isreplied=1 where ID={1}", gb.Reply, gb.ID); TbGuestBook record = ctx.TbGuestBook.Single(message => message.ID == gb.ID); record.IsReplied = true ; record.Reply = gb.Reply; ctx.SubmitChanges(); } } } |
這裏需要注意幾點:
l 我們把 DataContext 的操作在控制檯輸出
l 在進行發表回覆(更新操作)的時候,註釋的代碼和沒有註釋的代碼雖然都能完成更新操作,但是前者更合理,因爲後者會先進行 SELECT 再進行 UPDATE
WCF 服務端與客戶端
打開 Host 項目中的 Program.cs ,使用下面的代碼來實現 WCF 的服務端:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using Service; using Contract;
namespace Host { class Program { static void Main(string [] args) {
Uri uri = new Uri ("net.tcp://localhost:8080/DataAccessService" ); using (ServiceHost sh = new ServiceHost (typeof (DataAccess ), uri)) { NetTcpBinding ctb = new NetTcpBinding (); sh.AddServiceEndpoint(typeof (IDataAccess ), ctb, string .Empty); sh.Opened += delegate { Console .WriteLine(" 服務已經啓動 " ); }; sh.Open(); Console .ReadLine(); } } } } |
在 WebSite 項目中的 App_Code 文件夾下創建一個用戶調用服務的類, GetService.cs :
using System; using System.Data; using System.Configuration; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Xml.Linq; using Contract; using System.ServiceModel.Description; using System.ServiceModel;
public class GetService { public static IDataAccess GetDataAccessService() { ServiceEndpoint sep = new ServiceEndpoint (ContractDescription .GetContract(typeof (IDataAccess )), new NetTcpBinding (), new EndpointAddress ("net.tcp://localhost:8080/DataAccessService" ));
ChannelFactory <IDataAccess > cf = new ChannelFactory <IDataAccess >(sep);
return cf.CreateChannel(); } } |
調用服務
最後,就可以調用數據訪問服務來進行留言、回覆、刪除留言等操作了。頁面的代碼不再貼了,大家可以看第三篇或者下載源代碼。我們把 Default.cs 修改成如下:
public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { SetBind(); } } protected void btn_SendMessage_Click(object sender, EventArgs e) { TbGuestBook gb = new TbGuestBook (); gb.ID = Guid .NewGuid(); gb.IsReplied = false ; gb.PostTime = DateTime .Now; gb.UserName = tb_UserName.Text; gb.Message = tb_Message.Text; GetService .GetDataAccessService().SendMessage(gb); SetBind(); } private void SetBind() { rpt_Message.DataSource = GetService .GetDataAccessService().GetData(); rpt_Message.DataBind(); } } |
Admin.cs 代碼修改成如下:
public partial class Admin : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { SetBind(); } }
private void SetBind() { rpt_Message.DataSource = GetService .GetDataAccessService().GetData(); rpt_Message.DataBind(); } protected void rpt_Message_ItemCommand(object source, RepeaterCommandEventArgs e) { if (e.CommandName == "DeleteMessage" ) { GetService .GetDataAccessService().DeleteMessage(e.CommandArgument.ToString()); SetBind(); } if (e.CommandName == "SendReply" ) { TbGuestBook gb = new TbGuestBook (); gb.ID = new Guid (e.CommandArgument.ToString()); gb.Reply = ((TextBox )e.Item.FindControl("tb_Reply" )).Text; GetService .GetDataAccessService().SendReply(gb); SetBind(); } } } |
就這樣實現了一個多層構架的留言簿程序。對於
WCF
的一些內容本文不多作解釋了
。點擊
這裏
下載本篇代碼。
如果您覺得這個例子太簡單,還可以在這裏
下載一個Linq/WCF/MVC結合使用更復雜的例子,此例的目的主要演示一個框架,實現不完整。
一步一步學 Linq to sql 到這裏就結束了,看到這裏應該已經算師父領進門了,後續的提高還要靠大家自己去琢磨。