• 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)


    一. 说在前面的话

      本节主要在前面章节的基础上补充了几个简单的知识点,比如:第三方调用通过 GlobalHost.ConnectionManager.GetHubContext<MySpecHub1>();来获取Hub对象,那么能不能封装一下不必每次都这么获取呢?再比如SignalR传输是否有大小限制,一下传输10w个字能否传输成功?最后着重整理一下跨域的各种使用情况,结合C/S程序充当客户端和服务器端。

      本节内容包括:

        ①. SignalR与MVC或者WebApi简单的整合。

        ②. 全局的几个配置。

        ③. 跨域的配置和应用。

        ④. C/S程序充当客户端或服务器端。

    二. SignalR与MVC的简单整合

       在前面的章节中我们已经知道,如果要通过控制器中的Action来实现通讯,需要通过 GlobalHost.ConnectionManager.GetHubContext<MySpecHub1>(); 来获取Hub类,但是每个Action中都这么获取,显得有点麻烦,这里简单封装一下,来便捷开发。

        分析:实质在我们在Action中用到的对象无非也就这两个,IHubConnectionContext<dynamic> Clients  和  IGroupManager Groups ,所以这里利用继承的关系简单的封装一下,声明BaseController类,在里面获取这两个对象,然后其它控制器继承BaseController,并传入对应的Hub类,这样在Action中就可以直接使用 Clients和Groups了。

      PS:WepAPI程序可以采用下面类似方式进行封装。

      BaseController代码展示:

     1     /// <summary>
     2     /// 整合MVC和SignalR
     3     /// </summary>
     4     public class BaseController<T> : Controller where T : Hub
     5     {
     6         public IHubConnectionContext<dynamic> Clients { get; set; }
     7 
     8         public IGroupManager Groups { get; set; }
     9 
    10         public BaseController()
    11         {
    12             var hub = GlobalHost.ConnectionManager.GetHubContext<T>();
    13             Clients = hub.Clients;
    14             Groups = hub.Groups;
    15         }
    16     }

      继承BaseController的代码展示:

     1  public class HubController : BaseController<MySpecHub1>
     2     {
     3        
     4         /// <summary>
     5         /// 向所有人发送消息
     6         /// </summary>
     7         /// <param name="myConnectionId">当前用户的登录标记</param>
     8         /// <param name="msg">发送的信息</param>
     9         public string MySendAll(string myConnectionId, string msg)
    10         {
    11             //Hub模式
    12             Clients.AllExcept(myConnectionId).receiveMsg($"用户【{myConnectionId}】发来消息:{msg}");
    13             return "ok";
    14         }
    15 
    16     }

       

    三. 全局的几个配置

       这里的全局配置主要包括:传输超时时间、强制关闭时间、WebSocket模式下允许传输的数据最大值等等,以下配置代码可以在Configuration方法中进行配置,可以根据实际业务情况自行选择配置。

      1. 表示客户端在转而使用其他传输或连接失败之前应允许连接的时间。默认值为 5 秒。(传输超时时间)

        GlobalHost.Configuration.TransportConnectTimeout = TimeSpan.FromSeconds(5);

      2. 表示连接在超时之前保持打开状态的时间

        GlobalHost.Configuration.ConnectionTimeout= TimeSpan.FromSeconds(5);

      3. 用于表示在连接停止之后引发断开连接事件之前要等待的时间。 (强制关闭时间)

        GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(5);

      4. 表示两次发送保持活动消息之间的时间长度。如果启用,此值必须至少为两秒。设置为 null 可禁用。

        GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(2);

      5. Websocket模式下允许传输数据的最大值,默认为64kb

        GlobalHost.Configuration.MaxIncomingWebSocketMessageSize = 64;

    PS:设置消息缓冲区大小

      GlobalHost.Configuration.DefaultMessageBufferSize = 500;

    (默认情况下,SignalR 将保留在内存中的每个中心的每个连接的 1000 条消息。 如果使用大型消息时,这可能会造成内存问题,这可以通过减小此值来缓解压力) 

    四. 跨域的应用

       在很多情况下,前后端是分离,客户端和服务器端并不在一个地址下,比如APP(这里指混合开发能使用JS的情况下),这个时候服务器的SignalR就需要配置允许跨域,这里有两种允许跨域的策略,一种是JSONP模式,另外一种是Cors模式。

      在Startup类中的Configuration方法中进行配置,代码如下

     1   public class Startup
     2     {
     3         public void Configuration(IAppBuilder app)
     4         {
     5           //配置允许跨域
     6             //1. JSONP模式
     7             //app.MapSignalR(new HubConfiguration() { EnableJSONP = true });
     8 
     9             //2. Cors模式(需要安装Microsoft.Owin.Cors程序集)
    10             app.UseCors(CorsOptions.AllowAll).MapSignalR();
    11         }
    12     }

      注:采用Cors模式的跨域需要安装:Microsoft.Owin.Cors 程序集,并且上述代码没有单独配置模型路径,所以采用的是默认路径“/signalr”。

      当然前端代码也需要进行相应的改写:

    (1). 代理模式的改写形式:

       a. 自动生成代理类代码需要改写为 <script src="http://localhost:7080/signalr/hubs"></script> ,localhost:7080,根据实际情况改为实际地址。

          b. 需要单独配置一下Hub的连接路径, conn.url = "http://localhost:7080/signalr";

     以上两步即为全部改变,其余位置不需变化。

    (2). 非代理模式下的代码:

       非代理模式下就更容易,只需要在hubConnection方法中传入路径即可。如下图:

    五. C/S程序充当客户端

       C/S程序(这里采用控制台)充当客户端,当然服务器端必须已经配置了允许跨域,且C/S程序是没有JS的,所以只能采用非代理模式。

     步骤如下:

      1:安装程序集 Microsoft.AspNet.SignalR.Client

      2:代码配置

        a. 与服务器路径匹配的时候要注意,默认路径的话,要加上signalr/

        b. 如果定义的方法大于一个参数的时候,需要声明一个类来接收

        eg:Proxy.On<Person>("方法名", Person=>

          Console.WriteLine("ID{0} Name{1}", Person.ID, Person.Name));

     代码如下:

     1   class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5 
     6             //一. 基础信息配置
     7             //1. 与服务器路径进行匹配
     8             var conn = new HubConnection("http://localhost:8099/signalr/");
     9             //2. 创建代理类
    10             var proxy = conn.CreateHubProxy("MySpecHub1");
    11 
    12 
    13             //二. 定义客户端的方法
    14             //特别注意,如果定义的方法大于一个参数的时候,msg的位置需要声明一个类来接受
    15             //1 接受用户登录成功后的提示
    16 
    17             proxy.On("LoginSuccessNotice", (msg) =>
    18             {
    19                 Console.WriteLine(msg);
    20             });
    21 
    22             //2  接收自己的connectionId
    23             proxy.On("ReceiveOwnCid", (msg) =>
    24             {
    25                 Console.WriteLine(msg);
    26             });
    27 
    28             //三. 启动
    29             conn.Start().Wait();
    30 
    31             Console.ReadKey();
    32 
    33         }
    34     }

    六. C/S程序充当服务器端

       在很多情况下,我们需要避免使用IIS的性能开销,或者要将SignalR部署成Windows服务,这个使用就需要使用C/S程序作为服务器端了。

     配置步骤比较简单,如下: 

    1. 安装程序集:Microsoft.AspNet.SignalR.SelfHost 和 Microsoft.Owin.Cors(跨域使用)

    2. 添加集线器类MySpecHub1

    3. 在Startup中配置允许跨域

    4. 编写启动代码

     PS:以上步骤2和步骤3在前面章节中已经多次提到过了,这里指展示一下启动代码:

     1       static void Main(string[] args)
     2         {
     3             try
     4             {
     5                 string url = "http://localhost:7080";
     6                 using (WebApp.Start<Startup>(url))
     7                 {
     8                     Console.WriteLine("Server running on {0}", url);
     9                     Console.ReadLine();
    10                 }
    11             }
    12             catch (Exception ex)
    13             {
    14                 Console.WriteLine(ex.Message);
    15             }
    16             Console.ReadKey();
    17         }

      特别注意:如果报System.Reflection.TargetInvocationException was unhandled,直接去bin文件里以管理员身份运行exe程序即可或者以管理员身份运行VS程序然后启动即可。

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    关于 Kubernetes 中的 Volume 与 GlusterFS 分布式存储
    使用 Kubeadm 升级 Kubernetes 版本
    Kubernetes 中的核心组件与基本对象概述
    使用 Kubeadm 安装部署 Kubernetes 1.12.1 集群
    比较 Spring AOP 与 AspectJ
    关于 Spring Security OAuth2 中 CORS 跨域问题
    Prometheus 入门与实践
    MySQL 分支的选择:Percona 还是 MariaDB
    Spring Boot 集成 Swagger2 与配置 OAuth2.0 授权
    关于 Spring Security 5 默认使用 Password Hash 算法
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/9327321.html
Copyright © 2020-2023  润新知