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

WCF Duplex 雙工通訊深度解析:以聊天室實例探討服務導向架構設計

     編輯:關於.NET

前言:從問題到架構思維

Duplex 實現客戶端與服務端雙向通訊。開發簡易聊天室時,常遇到「服務端如何向特定客戶端發送訊息」的問題。常見解法是用 Singleton 保存客戶端 Session,或維護 Dictionary 對應客戶資訊。但研讀 WCF 官方範例後發現,許多開發者忽略了 WCF 核心價值——「服務」導向設計。

正確與錯誤的用例圖對比

正確用例圖 圖 1:正確的用例圖——服務端提供聊天服務,不參與聊天內容

錯誤用例圖 圖 2:錯誤的用例圖——服務端直接參與聊天互動

關鍵差異:服務端應專注於提供穩定服務,而非成為業務參與者。這是 SOA 架構思維的體現——明確服務邊界、定義訊息格式、分清角色職責。

聊天室服務契約設計

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IChatCallback))]
interface IChat {
    [OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)]
    string[] Join(string name);
    
    [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
    void Say(string msg);
    
    [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
    void Whisper(string to, string msg);
    
    [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)]
    void Leave();
}

回呼契約定義

interface IChatCallback {
    [OperationContract(IsOneWay = true)]
    void Receive(string senderName, string message);
    
    [OperationContract(IsOneWay = true)]
    void ReceiveWhisper(string senderName, string message);
    
    [OperationContract(IsOneWay = true)]
    void UserEnter(string name);
    
    [OperationContract(IsOneWay = true)]
    void UserLeave(string name);
}

核心實作:多播委派與非同步廣播

服務類別 ChatService 定義委派與事件實現訊息廣播:

private void BroadcastMessage(ChatEventArgs e) {
    ChatEventHandler temp = ChatEvent;
    if (temp != null) {
        foreach (ChatEventHandler handler in temp.GetInvocationList()) {
            handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
        }
    }
}

客戶端加入邏輯關鍵點

myEventHandler = new ChatEventHandler(MyEventHandler);
callback = OperationContext.Current.GetCallbackChannel<IChatCallback>();
ChatEventArgs e = new ChatEventArgs { msgType = MessageType.UserEnter, name = name };
BroadcastMessage(e);           // 先廣播「使用者進入」
ChatEvent += myEventHandler;   // 再訂閱事件,避免自己收到自己的進入通知

事件處理器分派回呼

private void MyEventHandler(object sender, ChatEventArgs e) {
    try {
        switch (e.msgType) {
            case MessageType.Receive:
                callback.Receive(e.name, e.message); break;
            case MessageType.ReceiveWhisper:
                callback.ReceiveWhisper(e.name, e.message); break;
            case MessageType.UserEnter:
                callback.UserEnter(e.name); break;
            case MessageType.UserLeave:
                callback.UserLeave(e.name); break;
        }
    } catch { Leave(); }
}

私聊實現:Dictionary 精準路由

public void Whisper(string to, string msg) {
    ChatEventArgs e = new ChatEventArgs {
        msgType = MessageType.ReceiveWhisper,
        name = this.name,
        message = msg
    };
    try {
        ChatEventHandler chatterTo;
        lock (syncObj) {
            chatterTo = chatters[to];  // 從字典查找目標委派
        }
        chatterTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
    } catch (KeyNotFoundException) { /* 目標不存在 */ }
}

關鍵:維護 Dictionary<string, ChatEventHandler> chatters 對應使用者名稱與委派實例,實現精準單點傳遞。

客戶端非同步呼叫模式

proxy = new ChatProxy(site);
IAsyncResult iar = proxy.BeginJoin(myNick, new AsyncCallback(OnEndJoin), null);

服務端宿主程式碼

Uri uri = new Uri(ConfigurationManager.AppSettings["addr"]);
ServiceHost host = new ServiceHost(typeof(NikeSoftChat.ChatService), uri);
host.Open();
Console.WriteLine($"Chat service listen on endpoint {uri}");
Console.WriteLine("Press ENTER to stop chat service...");
Console.ReadLine();
host.Abort(); host.Close();

服務端僅提供穩定服務,聊天參與者皆為客戶端使用者。

架構啟示

聊天室雖小,卻完美展示 SOA 核心:服務定義邊界、契約優先、角色職責分離。正如學習 OOP 需建立物件思維,採用 WCF 必須建立服務導向思維。

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