一種仿照Asp.net Mvc思維構建WebSocket服務器的方法


問題場景

Asp.net Mvc提供了DependencyResolver、Routing、Filter、 Modelbinder等webForm所沒有新概念,提高Web服務編寫的便利性,記得很久之前寫的ashx處理程序,由於沒有Routing和Modelbinder,代碼里寫了很多switch case,還有很多參數類型轉換,寫得滿頭大汗。現在,開發WebSocket服務端時,同樣遇到和ashx差不多的狀況:解析數據包,分析Command值,switch(command),然后一個case一個case分支的服務邏輯實現。

優化思路

如果我們在webSocket協議之上提出一種請求和回復的數據包的格式約定,正如http在tcp之上的協議約定一樣,那么就可以仿照Asp.net Mvc一樣,實現服務端的DependencyResolver、Controller、Filter等類似功能,未來業務功能的開發只要繼承Controller即可,輕松地實現業務功能代碼和基礎通訊代碼完全分開。當然這個格式約定可以作很簡單化,而不是直接復制Http協議,我們現在約定的格式可以如下:

{"api":"Login","id":2,"body":["name","password"]}
  • 請求和回復的內容都為Json文本;
  • api指明請求到遠程端的哪個api方法;
  • id為本數據包的唯一標識符;
  • body為請求的遠程端api的參數值,為數組;如果是回復,則為回復的對象的json文本 

客戶端請求如上的數據到服務器,服務器就自行調用它里面的Login方法,然后將返回值放到請求json的body字段返回給客戶端:

public bool Login(string theName, string thePassword)
{
     return theName == "name" && thePassword == "password";
}

 

 

設計之道

Api服務基礎類(FastApiService)的設計

上面的Login方法是一個具體的業務Api,其所在的class派生於FastApiService,FastApiService的職責是反射調用其Login成員方法。

關於反射性能,可以對Login方法先生成一個調用的委托,緩存起來供下次調用,可以參考asp.net Mvc的ActionMethodDispatcher:http://www.projky.com/asp.netmvc/4.0/System/Web/Mvc/ActionMethodDispatcher.cs.html

FastApiService的職責接口如下:

/// <summary>
/// 定義Api服務的執行
/// </summary>
public interface IFastApiService : IDisposable
{
     /// <summary>
     /// 執行Api行為
     /// </summary>              
     /// <param name="actionContext">Api行為上下文</param>      
     void Execute(ActionContext actionContext);
}

 

Routing的設計

這里我們偷工減料了,不作那么強大,分析請求數據包的api鍵的字符串值,查找哪個FastApiService定義了相關的成員方法,從而New出這個FastApiService實例,再調用Execute(ActionContext actionContext);

 

DependencyResolver的設計

Asp.netMvc+Autofac管理EF的Context對象非常方便,這得利於Asp.netMvc提供了DependencyResolver,可以把Controller的創建給IOC組件來管理,DependencyResolver接口很簡單,傳入對象類型,返回對象實例,中間過程由IOC來處理。

查找哪個FastApiService定義了相關的成員方法,從而New出這個FastApiService實例

這里獲取FastApiService的實例,改為DependencyResolver來獲取

 

各部件執行流程

Filter哪里去了

Filter實際是附屬的一種東西,在FastApiService的Execute前和后各執行各種Filter就可以了,不管是全局的Filter,還是打特性的,終究都是Filter,約定好他們的執行順序就OK!有了Filter,媽媽再也不擔心別人還未登錄就請求我的其它Api服務了。

 

 

成果展示

服務器c#代碼片斷

    /// <summary>
    /// Cpu性能檢測控制服務
    /// </summary>   
    public class CpuCounterService : FastApiService
    {
        /// <summary>
        /// 獲取版本號
        /// </summary>
        /// <returns></returns>
        [Api]
        [LogFilter("獲取版本號")]
        public string GetVersion()
        {
            return this.GetType().Assembly.GetName().Version.ToString();
        }

        /// <summary>
        /// 訂閱/取消Cpu變化通知
        /// </summary>       
        /// <returns></returns>
        [Api]
        [LogFilter("訂閱/取消Cpu變化通知")]
        public bool SubscribeCpuChangeNotify(bool subscribe)
        {
            this.CurrentContext.Session.TagData.Set("NotifyFlag", subscribe);
            return true;
        }
    }

 

客戶端js代碼片斷

        document.title = '正在連接到服務器 ..';
        var ws = new fastWebSocket('ws://localhost:8282/');

        // 注冊api
        ws.bindApi("CpuTimeChanged", function (data) {
            lineChart.addData(data);
        });

        ws.onclose = function (e) {
            document.title = '連接已斷開:' + e.code + '' + e.reason;
        };

        ws.onopen = function (e) {
            ws.invkeApi('getVersion', [], function (version) {
                document.title = '服務器版本號:' + version;
            }, function (ex) {
                alert('異常:' + ex);
            });
        };

 

 

栗子下載

https://github.com/xljiulang/NetworkSocket

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM