首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

學習 Linq to SQL (十):分層架構實戰 — WCF 留言板範例

     編輯:關於.NET

專案架構

將「留言板」改為 WCF 多層架構,包含五個專案:

專案類型角色
WebSite網站表現層 (留言板 UI)
Contract類別庫定義資料存取服務契約 (介面)
Service類別庫實作資料存取服務
Entity類別庫留言板實體類別 (Linq to SQL 對應)
Host主控台承載 WCF 服務 (Self-host)

參考關係:A→B,D;B→D,System.ServiceModel;C→B,D,System.ServiceModel,System.Data.Linq;D→System.Data.Linq;E→C,System.ServiceModel。

產生實體與對應檔

使用 sqlmetal 命令列工具:

sqlmetal /conn:server=xxx;database=GuestBook;uid=xxx;pwd=xxx /map:c:\guestbook.map /code:c:\guestbook.cs /serialization:Unidirectional
  • /serialization:Unidirectional 自動加上 [DataContract]/[DataMember] 供 WCF 序列化。
  • 將產生的 guestbook.cs 加入 Entity 專案;guestbook.map 部署至服務端。

定義服務契約 (Contract 專案)

[ServiceContract]
public interface IDataAccess {
  [OperationContract] void SendMessage(TbGuestBook gb);
  [OperationContract] List<TbGuestBook> GetData();
  [OperationContract] void DeleteMessage(string ID);
  [OperationContract] void SendReply(TbGuestBook gb);
}

實作服務 (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=...;database=GuestBook;uid=sa;pwd=...", xms);
    ctx.Log = Console.Out; // 輸出 SQL 供除錯
  }
  public void SendMessage(TbGuestBook gb) { ctx.TbGuestBook.Add(gb); ctx.SubmitChanges(); }
  public List<TbGuestBook> GetData() {
    return (from gb in ctx.TbGuestBook orderby gb.PostTime descending select gb).ToList();
  }
  public void DeleteMessage(string ID) {
    var gb = ctx.TbGuestBook.Single(m => m.ID == new Guid(ID));
    ctx.TbGuestBook.Remove(gb); ctx.SubmitChanges();
  }
  public void SendReply(TbGuestBook gb) {
    var record = ctx.TbGuestBook.Single(m => m.ID == gb.ID);
    record.IsReplied = true; record.Reply = gb.Reply; ctx.SubmitChanges();
    /* 替代寫法:ctx.ExecuteCommand("update ...", gb.Reply, gb.ID); // 僅 UPDATE 不 SELECT */
  }
}

服務端啟動 (Host 專案)

static void Main() {
  Uri uri = new Uri("net.tcp://localhost:8080/DataAccessService");
  using (var sh = new ServiceHost(typeof(DataAccess), uri)) {
    sh.AddServiceEndpoint(typeof(IDataAccess), new NetTcpBinding(), "");
    sh.Opened += (s,e) => Console.WriteLine("服務已啟動");
    sh.Open(); Console.ReadLine();
  }
}

客戶端呼叫 (WebSite 專案)

App_Code/GetService.cs 建立 ChannelFactory 動態產生 Proxy:

public static IDataAccess GetDataAccessService() {
  var sep = new ServiceEndpoint(
    ContractDescription.GetContract(typeof(IDataAccess)),
    new NetTcpBinding(),
    new EndpointAddress("net.tcp://localhost:8080/DataAccessService"));
  return new ChannelFactory<IDataAccess>(sep).CreateChannel();
}

前台頁面 Default.aspx.cs:

protected void btn_SendMessage_Click(...) {
  var gb = new TbGuestBook { ID=Guid.NewGuid(), UserName=tb_UserName.Text, Message=tb_Message.Text, PostTime=DateTime.Now, IsReplied=false };
  GetService.GetDataAccessService().SendMessage(gb); SetBind();
}
private void SetBind() { rpt_Message.DataSource = GetService.GetDataAccessService().GetData(); rpt_Message.DataBind(); }

管理頁面 Admin.aspx.cs 處理刪除/回覆:

protected void rpt_Message_ItemCommand(...) {
  if (e.CommandName=="DeleteMessage") GetService.GetDataAccessService().DeleteMessage(e.CommandArgument.ToString());
  if (e.CommandName=="SendReply") {
    var gb = new TbGuestBook { ID=new Guid(e.CommandArgument.ToString()), Reply=((TextBox)e.Item.FindControl("tb_Reply")).Text };
    GetService.GetDataAccessService().SendReply(gb);
  }
  SetBind();
}

延伸資源

本系列至此結束。若需更完整範例 (Linq/WCF/MVC 結合),可下載對應原始碼 (框架示範,功能未完整)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved