浅尝SignalR

摘要:
对WebSocket垂涎已久,我终于有机会学习了。对于ASP.NET,我尝试使用Fleck,这很方便,但有很多问题。一次绞刑意味着全部绞刑。我没有时间研究它。后来,我找到了SignalR,在阅读了大神的博客后发现它简单易用。首先,创建MVC项目SignalRDemo。然后,在SignalR的介绍:参考完成后,我们可以看到解决方案中有更多SignalR。此外,我们可以看到在添加新项目中有更多的SignalR。接下来,我们使用System创建SignalR永久连接类;使用System.Collections。通用的使用系统。Linq;使用System.Threading。任务;使用系统。网状物使用Microsoft.AspNet。信号R;namespaceSignalRDemo。SignalR{publicclassMySignalRConnection:持久连接{protectedoverrideTaskOnConnected{returnConnection.Send(connectionId,“Welcome!”);}protectedoverrideTaskOnReceived{returnConnection.Broadcast;}}如您所见,新创建的SignalR永久连接类继承PersistentConnection类,并覆盖OnConnected和OnReceived方法。

垂涎WebSocket已经很久了,终于有了学习的机会。

对于ASP.NET,试着用了下Fleck,比较方便,但是问题多多,一个挂则全挂,没时间去研究。

之后,找到了SignalR,看大神们的博客后感觉简单且好用。

原理神马的,后面再来贴,先记录下Demo小激动一下。

首先,创建一个MVC项目SignalRDemo。

接着,引入SignalR:

浅尝SignalR第1张

引用完成后,就可以看到解决方案中多了这些:

浅尝SignalR第2张

浅尝SignalR第3张

而且,在》添加》新建项,中会看到这里多了SignalR,

浅尝SignalR第4张

 接下来我们创建一个SignalR永久连接类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.SignalR;

namespace SignalRDemo.SignalR
{
    public class MySignalRConnection : PersistentConnection
    {
        protected override Task OnConnected(IRequest request, string connectionId)
        {
            return Connection.Send(connectionId, "Welcome!");
        }

        protected override Task OnReceived(IRequest request, string connectionId, string data)
        {
            return Connection.Broadcast(data);
        }
    }
}

可以看到,新建的SignalR永久性连接类继承了PersistentConnection类,并且重写了OnConnected和OnReceived方法。这两个方法一个是建立链接时触发,一个是客户端向服务器发消息时触发。

#region 程序集 Microsoft.AspNet.SignalR.Core, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// ...packagesMicrosoft.AspNet.SignalR.Core.2.4.0lib
et45Microsoft.AspNet.SignalR.Core.dll
#endregion

using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hosting;
using Microsoft.AspNet.SignalR.Infrastructure;
using Microsoft.AspNet.SignalR.Messaging;
using Microsoft.AspNet.SignalR.Tracing;
using Microsoft.AspNet.SignalR.Transports;
using Newtonsoft.Json;

namespace Microsoft.AspNet.SignalR
{
    //
    // 摘要:
    //     Represents a connection between client and server.
    public abstract class PersistentConnection
    {
        protected PersistentConnection();

        //
        // 摘要:
        //     Gets the Microsoft.AspNet.SignalR.IConnection for the Microsoft.AspNet.SignalR.PersistentConnection.
        public IConnection Connection { get; }
        //
        // 摘要:
        //     Gets the Microsoft.AspNet.SignalR.IConnectionGroupManager for the Microsoft.AspNet.SignalR.PersistentConnection.
        public IConnectionGroupManager Groups { get; }
        public IMemoryPool Pool { get; set; }
        protected IAckHandler AckHandler { get; }
        protected IPerformanceCounterManager Counters { get; }
        protected JsonSerializer JsonSerializer { get; }
        protected IMessageBus MessageBus { get; }
        protected IProtectedData ProtectedData { get; }
        protected virtual TraceSource Trace { get; }
        protected ITraceManager TraceManager { get; }
        protected ITransport Transport { get; }
        protected IUserIdProvider UserIdProvider { get; }

        public bool Authorize(IRequest request);
        public virtual void Initialize(IDependencyResolver resolver);
        //
        // 摘要:
        //     OWIN entry point.
        //
        // 参数:
        //   environment:
        public Task ProcessRequest(IDictionary<string, object> environment);
        //
        // 摘要:
        //     Handles all requests for Microsoft.AspNet.SignalR.PersistentConnections.
        //
        // 参数:
        //   context:
        //     The Microsoft.AspNet.SignalR.Hosting.HostContext for the current request.
        //
        // 返回结果:
        //     A System.Threading.Tasks.Task that completes when the Microsoft.AspNet.SignalR.PersistentConnection
        //     pipeline is complete.
        //
        // 异常:
        //   T:System.InvalidOperationException:
        //     Thrown if connection wasn't initialized. Thrown if the transport wasn't specified.
        //     Thrown if the connection id wasn't specified.
        public virtual Task ProcessRequest(HostContext context);
        //
        // 摘要:
        //     Called before every request and gives the user a authorize the user.
        //
        // 参数:
        //   request:
        //     The Microsoft.AspNet.SignalR.IRequest for the current connection.
        //
        // 返回结果:
        //     A boolean value that represents if the request is authorized.
        protected virtual bool AuthorizeRequest(IRequest request);
        //
        // 摘要:
        //     Returns the signals used in the Microsoft.AspNet.SignalR.PersistentConnection.
        //
        // 参数:
        //   userId:
        //     The user id for the current connection.
        //
        //   connectionId:
        //     The id of the incoming connection.
        //
        // 返回结果:
        //     The signals used for this Microsoft.AspNet.SignalR.PersistentConnection.
        protected virtual IList<string> GetSignals(string userId, string connectionId);
        //
        // 摘要:
        //     Called when a new connection is made.
        //
        // 参数:
        //   request:
        //     The Microsoft.AspNet.SignalR.IRequest for the current connection.
        //
        //   connectionId:
        //     The id of the connecting client.
        //
        // 返回结果:
        //     A System.Threading.Tasks.Task that completes when the connect operation is complete.
        protected virtual Task OnConnected(IRequest request, string connectionId);
        //
        // 摘要:
        //     Called when a connection disconnects gracefully or due to a timeout.
        //
        // 参数:
        //   request:
        //     The Microsoft.AspNet.SignalR.IRequest for the current connection.
        //
        //   connectionId:
        //     The id of the disconnected connection.
        //
        //   stopCalled:
        //     true, if stop was called on the client closing the connection gracefully; false,
        //     if the connection has been lost for longer than the Microsoft.AspNet.SignalR.Configuration.IConfigurationManager.DisconnectTimeout.
        //     Timeouts can occur in scaleout when clients reconnect with another server.
        //
        // 返回结果:
        //     A System.Threading.Tasks.Task that completes when the disconnect operation is
        //     complete.
        protected virtual Task OnDisconnected(IRequest request, string connectionId, bool stopCalled);
        //
        // 摘要:
        //     Called when data is received from a connection.
        //
        // 参数:
        //   request:
        //     The Microsoft.AspNet.SignalR.IRequest for the current connection.
        //
        //   connectionId:
        //     The id of the connection sending the data.
        //
        //   data:
        //     The payload sent to the connection.
        //
        // 返回结果:
        //     A System.Threading.Tasks.Task that completes when the receive operation is complete.
        protected virtual Task OnReceived(IRequest request, string connectionId, string data);
        //
        // 摘要:
        //     Called when a connection reconnects after a timeout.
        //
        // 参数:
        //   request:
        //     The Microsoft.AspNet.SignalR.IRequest for the current connection.
        //
        //   connectionId:
        //     The id of the re-connecting client.
        //
        // 返回结果:
        //     A System.Threading.Tasks.Task that completes when the re-connect operation is
        //     complete.
        protected virtual Task OnReconnected(IRequest request, string connectionId);
        //
        // 摘要:
        //     Called when a connection reconnects after a timeout to determine which groups
        //     should be rejoined.
        //
        // 参数:
        //   request:
        //     The Microsoft.AspNet.SignalR.IRequest for the current connection.
        //
        //   groups:
        //     The groups the calling connection claims to be part of.
        //
        //   connectionId:
        //     The id of the reconnecting client.
        //
        // 返回结果:
        //     A collection of group names that should be joined on reconnect
        protected virtual IList<string> OnRejoiningGroups(IRequest request, IList<string> groups, string connectionId);
        //
        // 摘要:
        //     Validates the connection token and extracts the connection ID from it.
        //
        // 参数:
        //   context:
        //     The Microsoft.AspNet.SignalR.Hosting.HostContext representing the request.
        //
        //   connectionToken:
        //     The connection token to validate.
        //
        //   connectionId:
        //     If this method returns true, this output parameter receives the connection ID
        //     contained within the token.
        //
        //   message:
        //     If this method returns false, this output parameter receives an error message
        //     to report.
        //
        //   statusCode:
        //     If this method returns false, this output parameter receives an HTTP status code
        //     to report.
        //
        // 返回结果:
        //     A boolean indicating if the connection token was valid.
        protected internal virtual bool TryGetConnectionId(HostContext context, string connectionToken, out string connectionId, out string message, out int statusCode);
    }
}

先不用MQ,就写个简单的List来存储链接吧

namespace SignalRDemo.App_Start
{
    public class AppHelper
    {
        private AppHelper()
        {
            ConnectionList = new List<string>();
        }
        public static List<string> ConnectionList { get; set; }
    }
}

修改MySignalRConnection类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.SignalR;
using SignalRDemo.App_Start;

namespace SignalRDemo.SignalR
{
    public class MySignalRConnection : PersistentConnection
    {
        protected override Task OnConnected(IRequest request, string connectionId)
        {
            if (!AppHelper.ConnectionList.Contains(connectionId))
            {
                AppHelper.ConnectionList.Add(connectionId);
            }
            Connection.Send(AppHelper.ConnectionList, "New In!");
            return Connection.Send(connectionId, "Welcome!");
        }

        protected override Task OnReceived(IRequest request, string connectionId, string data)
        {
            return Connection.Broadcast(data);
        }

        protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
        {
            if (AppHelper.ConnectionList.Contains(connectionId))
            {
                var oldList = new List<string>();
                oldList.AddRange(AppHelper.ConnectionList);
                AppHelper.ConnectionList.Remove(connectionId);
                return Connection.Send(oldList, "out_" + connectionId);
            }
            return null;
        }
    }
}

 在Startup.cs中添加

namespace SignalRDemo
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888

            app.MapSignalR<SignalR.MySignalRConnection>("/mc");
        }
    }
}

 测试页面

@{
    ViewBag.Title = "SignalR Demo";
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/signalR");
}
<style type="text/css">
    .row{
        margin:20px;
    }

    .msgbox{
        margin:10px 0;
        height:400px;
        overflow-y:auto;
    }
</style>

<div class="row">
    <input id="ipt_text" type="text" class="" />
    <input id="submit" type="button" value="发送" />
    <div id="msgshow" class="msgbox">
</div> </div> <script type="text/javascript"> $(function () { var $ipt_text = $('#ipt_text'), $submit = $('#submit'), $msgshow = $('#msgshow'); var conn = $.connection("/mc"); conn.start().done(function (data) { conn.send('大家好,我是新来的,请多多关照'); }).fail(function (msg) { alert(msg); }); function log(msg) { $msgshow.append('<p>【' + new Date().Format("yyyy-MM-dd hh:mm:ss") + '' + msg + '</p>'); } conn.received(function (msg) { log(msg); }); $submit.on('click', function (e) { var txt = $ipt_text.val(); if (!txt || !txt.length) return; conn.send(txt); }); }); </script>

至此,整个Demo就写完了,下面是测试页面

浅尝SignalR第5张

需要注意的是,新建MVC项目的时候如果不是选的MVC模板,很多东西需要自己手动添加,比如 Startup.cs , BundleConfig等等。

还是记录下添加过程吧

Startup.cs

浅尝SignalR第6张

BundleConfig类需要引用System.Web.Optimization.dll,这个需要在Nuget中下载

浅尝SignalR第7张

搜索Optimization,然后安装

浅尝SignalR第8张

还需注意的是,如果要使用 @Styles.Render 和@Scripts.Render,还需要在View/Web.config中配置System.Web.Optimization.dll域名

浅尝SignalR第9张

浅尝SignalR第10张

后续要做的事情还很多哦

连接认证

权限控制

消息队列

消息过滤

等等

免责声明:文章转载自《浅尝SignalR》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇CentOS 6.3下配置LVM(逻辑卷管理)[Unity] Unity 2019.1.14f 在Terrain中使用Paint Texture的方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

DevExpress WPF让创建绑定到数据的3D图表控件变得更容易(Part 1)

下载DevExpress v20.1完整版 富文本控件难上手?这堂公开课你一定不能错过,不同视图不同应用场景全解! 通过DevExpress WPF Controls,您能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 在本教程中,您将完成可视化数据源所需的步骤。 应该执行以下步骤,本文我们将...

浅析Android动画(二),属性动画高级实例探究

转载请注明出处!http://www.cnblogs.com/wondertwo/p/5312482.html ObjectAnimator实现属性动画 为了写好Android动画这几篇博客,在动笔之前我是下过很大决心的,我对自己的要求是尽量把一个小知识点写清楚写明白,说白了就是相对于大而全的长篇大论,我更倾向于去写小而美的博客!为了保证在高产的同时能坚...

android黑科技系列——实现静态的默认安装和卸载应用

一、访问隐藏的API方式进行静态的默认安装和卸载 1.系统安装程序 android自带了一个安装程序—/system/app/PackageInstaller.apk.大多数情况下,我们手机上安装应用都是通过这个apk来安装 的。代码使用也非常简单: /*安装apk */ public static voidinstallApk(Context conte...

Delphi XE4 TStringHelper用法详解

原文地址:DelphiXE4TStringHelper用法详解作者:天下为公 Delphi XE4的TStringHelper,对操作字符串进一步带来更多的方法,估计XE5还能继续用到。System.SysUtils.TStringHelper大小写转换:-------------------------------------------------...

scala 学习笔记(07) 一等公民的函数

在scala中一切皆对象,一切皆函数,函数跟Int,String、Class等其它类型是处于同等的地位,换句话说,使用函数跟使用普通的类型一样,没什么区别,因此: 1、函数可以赋值给变量,可以当参数传递 def helloWorld(msg: String): Unit = { println("Hello," + msg) }...

token解决前后端分离认证和跨域问题和JWT的使用

二、使用token解决前端后端分离用户认证问题 2.1 用户提交帐号和密码到服务器的认证接口 login.html doSubmit:function(){ console.log("~~~~~~~~~~~~~doSubmit"); axios.get("http://localhost:8080/user/login",{...