>  기사  >  백엔드 개발  >  SignalR을 사용하여 실시간 웹 채팅을 구현하기 위한 예제 코드

SignalR을 사용하여 실시간 웹 채팅을 구현하기 위한 예제 코드

零下一度
零下一度원래의
2018-05-25 16:12:293275검색

이 글은 실시간 웹 채팅을 위한 Asp.net SignalR의 예제 코드를 주로 소개합니다. 관심 있는 친구들이 참고할 수 있습니다.

이 장에서 공유하는 내용은 Signal R 프레임워크를 사용하는 것입니다. 간단한 만들기 그룹 채팅 기능은 주로 .Net의 MVC에서 이 프레임워크를 사용하는 방법을 설명합니다. 이 프로젝트에는 공식 문서(물론 모두 영어로 작성됨)가 있으므로 나중에 공유 글을 작성하지 않겠습니다. 필요할 때 실시간으로 웹을 사용하기 위해 통신할 때 더 많은 솔루션이 있습니다. 결국 이것은 Microsoft에서 홍보하는 솔루션 중 하나입니다.

SignalR 온라인 소개

ASP.NET SignalR은 애플리케이션에 실시간 웹 기능을 추가하는 프로세스를 단순화하는 ASP.NET 개발자용 라이브러리입니다. 실시간 웹 기능은 클라이언트가 새 데이터를 요청할 때까지 서버가 기다리지 않고 서버 코드가 연결된 클라이언트에 콘텐츠가 제공되는 즉시 콘텐츠를 푸시할 수 있는 기능입니다.

SignalR은 물론 매우 간단하고 사용하기 쉬운 고급 API도 제공하는데, 이를 통해 서버는 클라이언트의 JavaScript 함수를 개별적으로 또는 일괄적으로 호출할 수 있으며, 다음과 같은 연결 관리를 수행하는 데 매우 편리합니다. 서버에 연결하는 클라이언트 또는 연결 끊기 연결, 클라이언트 그룹화 및 클라이언트 인증은 모두 SignalR을 사용하여 매우 쉽게 구현할 수 있습니다.

SignalR은 ASP .NET에 클라이언트와의 실시간 통신을 제공합니다. 물론, 이것은 사용하기 쉽고 충분한 확장성을 가지고 있습니다. 과거에는 사용자가 실시간 데이터 표시를 위해 페이지를 새로 고치거나 Ajax 폴링을 사용해야 했지만 이제는 SignalR을 사용하면 됩니다. 가장 중요한 점은 프로젝트를 다시 만들 필요가 없으며 기존 ASP .NET 프로젝트를 사용하여 SignalR을 원활하게 사용할 수 있다는 것입니다.

그룹 채팅 인스턴스 효과

먼저 테스트 케이스의 효과를 살펴보겠습니다. 렌더링:

여기에서는 스타일이 매우 간단합니다. 여기에 관련된 기능은 다음과 같습니다.

1. 온라인 사용자 수 계산

2. 온라인 사용자의 닉네임 및 연결 방법 표시(이 테스트 사례는 webSockets 및 longPolling(긴 연결)을 지원합니다) 3. 그룹 채팅 정보

MVC에서 SignalR을 사용하는 방법먼저 일반적으로 MVC 웹 프로젝트를 만든 다음 Nuget 콘솔 명령을 사용합니다. Inst

all

-package Microsoft.AspNet.SignalR을 추가합니다. 자동으로 추가되는 패키지는 다음과 같습니다.

 <package id="Microsoft.AspNet.SignalR" version="2.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.SignalR.Core" version="2.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.SignalR.JS" version="2.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.SignalR.SystemWeb" version="2.2.2" targetFramework="net45" />
그리고 관련 js 파일을 MVC 프로젝트의 Script 폴더에 자동으로 추가합니다:

jquery

.signalR-2.2.2.min.js
jquery.signalR -2.2.2.js

그런 다음 프로젝트 1차 디렉터리에 Startup.cs라는 파일 이름을 가진 클래스를 만들어야 하며, 그 안에 있는 주요 콘텐츠는 완료될 수 없습니다.

[assembly: OwinStartup(typeof(Stage.Api.Extend.Startup))]
namespace Stage.Api.Extend
{
  public class Startup
  {
    public void Configuration(IAppBuilder app)
    {
      app.MapSignalR("/chat", new Microsoft.AspNet.SignalR.HubConfiguration
      {
        EnableDetailedErrors = true,
        EnableJavaScriptProxies = true
      });
    }
  }
}

먼저 관심을 분석합니다. 위에서 아래로:

1. OwinStartup(Type) 생성자

유형을 전달하며 이 유형은 우리가 만든 Startup에 해당합니다. 이는 이 생성자 클래스를 통해 시작 위치를 표시합니다.

OwinStartup(Type) 构造函数传递的是一个类型,而这个类型对应的就是我们创建的Startup类,这个通过这个构造函数类标记起始位置;

2.  namespace Stage.Api.Extend 是我项目的命名空间,这个可以随便定义;

3.  public void Configuration(IAppBuilder app) 函数是固定必须的,这里程序会首先进入这个方法执行里面的逻辑代码;

4.  app.MapSignalR 是扩展的IAppBuilder接口方法,他有多种表现形式,这里我选择的是 public <a href="http://www.php.cn/wiki/188.html" target="_blank">static</a> IAppBuilder MapSignalR(this IAppBuilder builder, <a href="http://www.php.cn/wiki/57.html" target="_blank">string</a> path, HubConfiguration configuration); 2. namespace Stage.Api.Extend 는 내 프로젝트의 네임스페이스 , 이는 마음대로 정의할 수 있습니다

3. public void Configuration(IAppBuilder 앱) ; > 함수는 고정되어 있고 필요하며 여기의 프로그램은 먼저 이 메소드를 입력합니다.

4. app.MapSignalR 는 확장된 IAppBuilderInterfacemethod에는 다양한 표현 형식이 있습니다. 여기서는 public <a href="http://www.php.php%EB%A5%BC%20%EC%84%A0%ED%83%9D%ED%95%A9%EB%8B%88%EB%8B%A4.%20cn/wiki/188.html" target="_blank">정적 </a>

IAppBuilder MapSignalR(이 IAppBuilder 빌더, string🎜 경로, HubConfiguration 구성); , 여기를 참조하세요. MVC의 🎜routing🎜과 약간 유사합니다. 여기서 주목해야 할 주요 사항은 프런트 엔드 페이지에서 사용해야 하는 Path 매개 변수입니다. 🎜🎜백그라운드에 필요한 구성은 실제로 여기에서 완료되었습니다. 필요한 특정 작업은 다음과 같습니다. 새 클래스를 생성하고(여기서는 ChatHub라고 이름 지정함) 🎜상속 🎜Hub를 제공합니다. SignalR 프레임워크), 내부 논리 코드는 다음과 같습니다. 🎜
public class ChatHub : Hub
  {
    //
    public int Num = 10001;
    public static List<MoHubUser> _Users = new List<MoHubUser>();

    /// <summary>
    /// 添加聊天人
    /// </summary>
    /// <param name="user"></param>
    public void AddUser(MoHubUser user)
    {

      user.Id = Context.ConnectionId;
      if (!_Users.Any(b => b.Id == user.Id))
      {
        _Users.Add(user);
      }

      //Clients.All.newUser(user);
      Clients.All.userList(_Users);
    }

    /// <summary>
    /// 发送信息
    /// </summary>
    /// <param name="user"></param>
    /// <param name="message"></param>
    public void SendAll(MoHubUser user, string message)
    {
      Clients.All.addNewMessageToPage(user, message);
    }

    /// <summary>
    /// 某个聊天人退出是,通知所有在线人重新加载聊天人数
    /// </summary>
    /// <param name="stopCalled"></param>
    /// <returns></returns>
    public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
    {
      var user = _Users.SingleOrDefault(x => x.Id == Context.ConnectionId);
      if (user != null)
      {
        _Users.Remove(user);
        Clients.All.userList(_Users);
      }
      return base.OnDisconnected(stopCalled);
    }
  }

上面的3个方法分别做了:添加聊天人到List,发送信息到客户端,某个连接失效后通知各个有效的聊天人重新加载信息;这里值得关注的是通过重新 public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled) 方法来实现捕获并移除失效连接(这里是聊天人的信息);整篇测试用例通过Context.ConnectionId来保证连接的唯一性,只要有新的链接请求,那么服务端就会分配一个唯一串给这个链接,当客户端关闭页面或关闭链接这个是有就能在OnDisconnected方法中捕获到这个失效的链接的ConnectionId,这样就达到了移除失效聊天人的要求了;为了代码的方便性,这里创建了一个聊天人信息类:

public class MoHubUser
  {

    public string Id { get; set; }
    public string NickName { get; set; }
    public string TransportMethod { get; set; }
  }

到这里后台的聊天室代码就完成了就是这么简单;我们再来看试图中如何来写代码,这里我先给出我的html布局代码:

 @{
  ViewBag.Title = "神牛聊天室 - SignalR";
}
<style type="text/css">
  .p_left {
    width: 70%;
    float: left;
  }

  .p_right {
    width: 28%;
    float: left;
  }

  .ul {
    list-style: none;
    border: 1px solid #ccc;
    height: 500px;
    overflow-y: scroll;
    color: black;
  }

    .ul li {
      padding-top: 5px;
      padding-right: 25px;
    }

  .ul_user {
    list-style: none;
  }

    .ul_user li {
      padding-top: 5px;
    }

  .send {
    position: relative;
    background: #eae7e7;
    border-radius: 5px; /* 圆角 */
    padding-top: 4px;
    padding-left: 5px;
    margin-top: 13px;
  }

    .send .arrow {
      position: absolute;
      top: -16px;
      font-size: 0;
      border: solid 8px;
      border-color: #fff #fff #eae7e7 #fff;
    }
</style>
<h3>@ViewBag.Title 在线人数:<span id="sapnUserTotal">0</span>人</h3>
<p class="container text-left">
  <p class="p_left">
    <ul class="ul" id="discussion"></ul>
    <textarea rows="5" class="form-control" id="message" maxlength="500" placeholder="开始聊天. . ." style="max-width: 100%"></textarea><br />
    <input type="button" id="sendmessage" value="发 送" class="btn btn-default" />
    <input type="hidden" id="displayname" />
  </p>
  <p class="p_right">
    <ul id="users" class="ul_user"></ul>
  </p>
</p>

<script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
@*<script src="~/chat/hubs"></script>*@

客户端这里写法大致有两种选择,一种直接使用生成的代理来操作,一种不用自动生成的代理采用手动创建代理的方式;为了内容的简洁性,这里只简单讲解下自动生成的代理方式,而更多的是分享手动创建代理链接的方式;

使用生成的代理获取链接

首先,我们需要通过Script标签来引用一下自动生成代理的路径: 6b7e0e3e57921579395ce622aff978262cacc6d41bbb37262a98f745aa00fbf0 ,注意啦这里的路径/chat对应的就是咋们在前面Startup.cs文件中配置 app.MapSignalR("/chat" 路径,而后面/hubs固定的写法(至少目前我还没更多的试验过),只有先应用了这个~/chat/hubs,才能在后面使用生成的代理,先上段代码:

var chat = $.connection.chatHub;
    chat.client.newUser = function (user) {
      $("#users").append(&#39; <li><strong>&#39; + user.NickName + &#39;[&#39; + user.TransportMethod + &#39;]</strong></li>&#39;);
    };

    chat.client.userList = function (users) {
      console.log(users);
      $("#sapnUserTotal").html(users.length);
      $.each(users, function (i, item) {
        $("#users").append(&#39; <li>[&#39; + item.TransportMethod + &#39;] <strong>&#39; + item.NickName + &#39;</strong>(&#39; + item.Id + &#39;)</li>&#39;);
      });
    };
    chat.client.addNewMessageToPage = function (user, message) {
      console.log(user);
      $("#discussion").append(&#39; <li ><span><strong>&#39; + user.NickName + &#39;[&#39; + user.TransportMethod + &#39;]</strong>:</span><p class="send">&#39; + message + &#39;<p class="arrow"></p></p></li>&#39;);
    };
  //connection.hub.start({ transport: [&#39;webSockets&#39;, &#39;longPolling&#39;] }).done(function () {
    //  my.TransportMethod = connection.hub.transport.name;
    //  chat.server.addUser(my);

    //  $(&#39;#sendmessage&#39;).click(function () {
    //    //console.log(chat);
    //    var content = $.trim($(&#39;#message&#39;).val());
    //    if (content.length <= 0) { $(&#39;#message&#39;).val(&#39;&#39;).focus(); return; }
    //    chat.server.sendAll(my, content);
    //    $(&#39;#message&#39;).val(&#39;&#39;).focus();
    //  });
    //}).fail(function () {
    //  alert("链接聊天室失败,请重新刷新页面。");
    //});

咋们逐步来解析下代码注意点:

1.  var chat = $.connection.chatHub; 这里的chatHub对应的就是咋们创建的并继承Hub的ChatHub类,由于js变量开头都是小写,所以这里是chatHub,这句活就表示链接到咋们后端了ChatHub类了,然后就可以使用里面的方法啦(这种有点类似于早期的webform中某种ajax请求的写法)

2. 通过chat.client.xxx来接收服务端通知的消息,而这个xxx对应的方法名称和咋们后端的Clients.All.xxx,本章实例对应的是:chat.client.userList = function (users){}对应Clients.All.userList(_Users);这样后端就能直接通知客户端的对应方法了;注意这里我后端Clients.All用的是通知全部客户端的意思,如果您需要通知指定的链接需要用到的是: T Client(string connectionId); 方法

3. chat.client是后端调用客户端,那相对的chat.server就是客户端请求服务端,和上面一样通过chat.server.xxx来指定请求的服务端方法,注意这个时候服务端方法指的是继承类Hub的子类的公共方法(本篇对应的是:chat.server.sendAll(my, content)对应ChatHub.cs文件中的 public void SendAll(MoHubUser user, string message) 函数)

4.  connection.hub.start({ transport: ['webSockets', 'longPolling'] }) 来指定运行的交互协议

以上就是使用生成代理的方式,按照上面的注意点来写应该不是问题;

使用手动创建反向代理来链接

不采用生成的代码的方式,我们只需要修改前端就行了,后台代码不用变或设置不用变动;首先我们把上面说的Script引用自动代理的代码去掉,因为这个时候不需要了,我们还是先上代码:

var my = { NickName: "神牛001", TransportMethod: "" };
    var connection = $.hubConnection("/chat/hubs");
    var chat = connection.createHubProxy(&#39;chatHub&#39;);

    chat.on("userList", function (users) {
      console.log(users);
      $("#sapnUserTotal").html(users.length);
      $("#users").html("");
      $.each(users, function (i, item) {
        $("#users").append(&#39; <li>[&#39; + item.TransportMethod + &#39;] <strong>&#39; + item.NickName + &#39;</strong>(&#39; + item.Id + &#39;)</li>&#39;);
      });
    });

    chat.on("addNewMessageToPage", function (user, message) {
      console.log(user);
      $("#discussion").append(&#39; <li ><span><strong>&#39; + user.NickName + &#39;[&#39; + user.TransportMethod + &#39;]</strong>:</span><p class="send">&#39; + message + &#39;<p class="arrow"></p></p></li>&#39;);

      var p = document.getElementById(&#39;discussion&#39;);
      //p.scrollTop = p.scrollHeight;
      p.scrollTop = 999999;
    });

    var nickName = prompt("请输入一个昵称:", my.NickName);
    my.NickName = nickName.length > 0 ? nickName : my.NickName;
    $(&#39;#displayname&#39;).val(nickName);
    $(&#39;#message&#39;).focus();
   

    connection.start({ transport: [&#39;webSockets&#39;, &#39;longPolling&#39;] }).done(function () {

      my.TransportMethod = connection.transport.name;
      //console.log(my.TransportMethod);
      chat.invoke("addUser", my);

      $(&#39;#sendmessage&#39;).click(function () {
        var content = $.trim($(&#39;#message&#39;).val());
        if (content.length <= 0) { $(&#39;#message&#39;).val(&#39;&#39;).focus(); return; }

        chat.invoke("sendAll", my, content);
        $(&#39;#message&#39;).val(&#39;&#39;).focus();
      });
    });

同样列出如下注意点:

1.  var connection = $.hubConnection("/chat/hubs"); 创建链接,这里的path同样对应后端的 app.MapSignalR("/chat" ,路径保持一致

2.  var chat = connection.createHubProxy('chatHub'); 来创建反向代理链接,这里的name:chatHub对应的是后端的ChatHub类名称

3. 通过on("xxx",function(){})函数来绑定服务端通知客户端的事件,xxx对应Clients.All.xxx中的xxx

4.  connection.start({ transport: ['webSockets', 'longPolling'] }) 来设置允许的链接方式,并开始链接

5. connection.transport.name来获取链接的方式名称,默认start不设置的话有这么几种:webSockets,foreverFrame,serverSentEvents,longPolling

6. chat.invoke("xxx", param1, param2)는 호출을 사용하여 Hub 클래스를 상속하는 클래스의 공개 메서드를 매핑합니다. chat.invoke("sendAll", my, content) 对应 public void SendAll(MoHubUser user, string message)

위 내용은 SignalR을 사용하여 실시간 웹 채팅을 구현하기 위한 예제 코드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.