一種仿照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分支的服務邏輯實現。html

優化思路

若是咱們在webSocket協議之上提出一種請求和回覆的數據包的格式約定,正如http在tcp之上的協議約定同樣,那麼就能夠仿照Asp.net Mvc同樣,實現服務端的DependencyResolver、Controller、Filter等相似功能,將來業務功能的開發只要繼承Controller便可,輕鬆地實現業務功能代碼和基礎通信代碼徹底分開。固然這個格式約定能夠做很簡單化,而不是直接複製Http協議,咱們如今約定的格式能夠以下:git

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

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

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

 

 

設計之道

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

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

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

FastApiService的職責接口以下:c#

/// <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);api

 

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

相關文章
相關標籤/搜索