一种仿照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来获取

 

各部件执行流程

一种仿照Asp.net Mvc思维构建WebSocket服务器的方法_第1张图片

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

 

你可能感兴趣的:(websocket)