項目介紹
這節將要把《學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到這裡就結束了,看到這裡應該已經算師父領進門了,後續的提高還要靠大家自己去琢磨。