当前位置: 移动技术网 > IT编程>开发语言>.net > Asp.net SignalR快速入门

Asp.net SignalR快速入门

2017年12月12日  | 移动技术网IT编程  | 我要评论

宝宝腹泻怎么回事,数学老师不上课难受,第一站长论坛

今天的专题就是让大家可以快速的上手asp.net signalr。废话不多说了,下面正式进入今天专题的内容。

二、asp.net signalr 是个什么东东
   asp.net signalr是微软为实现实时通信的一个类库。一般情况下,signalr会使用javascript的长轮询(long polling)的方式来实现客户端和服务器通信,随着html5中websockets出现,signalr也支持websockets通信。另外signalr开发的程序不仅仅限制于宿主在iis中,也可以宿主在任何应用程序,包括控制台,客户端程序和windows服务等,另外还支持mono,这意味着它可以实现跨平台部署在linux环境下。

  signalr内部有两类对象:

http持久连接(persisten connection)对象:用来解决长时间连接的功能。还可以由客户端主动向服务器要求数据,而服务器端不需要实现太多细节,只需要处理persistentconnection 内所提供的五个事件:onconnected, onreconnected, onreceived, onerror 和 ondisconnect 即可。
hub(集线器)对象:用来解决实时(realtime)信息交换的功能,服务端可以利用url来注册一个或多个hub,只要连接到这个hub,就能与所有的客户端共享发送到服务器上的信息,同时服务端可以调用客户端的脚本。
  signalr将整个信息的交换封装起来,客户端和服务器都是使用json来沟通的,在服务端声明的所有hub信息,都会生成javascript输出到客户端,.net则依赖proxy来生成代理对象,而proxy的内部则是将json转换成对象。

  客户端和服务端的具体交互情况如下图所示:

  从上面的介绍可以看出,signalr既然是为实时而生的,这样就决定了其使用场所。具体适用情景有如下几点:

1、聊天室,如在线客服系统,im系统等
2、股票价格实时更新
3、消息的推送服务
4、游戏中人物位置的实时推送
   目前,我所在公司在开发的就是在线客服系统。

三、使用asp.net signalr在web端实现广播消息
   通过第二部分的介绍,相信大家对asp.net signalr有了一个初步的了解,接下来通过两个例子来让大家加深对signalr运行机制的理解。第一个例子就是在web端如何使用signalr来实现广播消息。

使用visual studio 2013,创建一个mvc工程
通过nuget安装signalr包。右键引用-》选择管理nuget程序包-》在出现的窗口中输入signalr来找到signalr包进行安装。
安装signalr成功后,signalr库的脚本将被添加进scripts文件夹下。具体如下图所示:


4. 向项目中添加一个signalr集线器(v2)并命名为serverhub。

  5. 将下面代码填充到刚刚创建的serverhub类中。

using microsoft.aspnet.signalr;
using microsoft.aspnet.signalr.hubs;
using system;

namespace signalrquickstart
{public class serverhub : hub
  {
    private static readonly char[] constant =
    {
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
      'w', 'x', 'y', 'z',
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
      'w', 'x', 'y', 'z'
    };

    /// <summary>
    /// 供客户端调用的服务器端代码
    /// </summary>
    /// <param name="message"></param>
    public void send(string message)
    {
      var name = generaterandomname(4);

      // 调用所有客户端的sendmessage方法
      clients.all.sendmessage(name, message);
    }

    /// <summary>
    /// 产生随机用户名函数
    /// </summary>
    /// <param name="length">用户名长度</param>
    /// <returns></returns>
    public static string generaterandomname(int length)
    {
      var newrandom = new system.text.stringbuilder(62);
      var rd = new random();
      for (var i = 0; i < length; i++)
      {
        newrandom.append(constant[rd.next(62)]);
      }
      return newrandom.tostring();
    }
  }
}

  6. 创建一个startup类,如果开始创建mvc项目的时候没有更改身份验证的话,这个类会默认添加的,如果已有就不需要重复添加了。按照如下代码更新startup类。

  7. 在home控制器中创建一个home action方法

public class homecontroller : controller
  {
    public actionresult index()
    {
      return view();
    }

    public actionresult about()
    {
      viewbag.message = "your application description page.";

      return view();
    }

    public actionresult contact()
    {
      viewbag.message = "your contact page.";

      return view();
    }

    public actionresult chat()
    {
      return view();
    }
  }

  8. 在views文件中home文件夹中创建一个chat视图,视图代码如下所示:

@{
  viewbag.title = "聊天窗口";
}

<h2>chat</h2>

<div class="container">
  <input type="text" id="message" />
  <input type="button" id="sendmessage" value="send" />
  <input type="hidden" id="displayname" />
  <ul id="discussion"></ul>
</div>

@section scripts
{
  <!--引用signalr库. -->
  <script src="~/scripts/jquery.signalr-2.2.0.min.js"></script>
   <!--引用自动生成的signalr 集线器(hub)脚本.在运行的时候在浏览器的source下可看到 -->
  <script src="~/signalr/hubs"></script>
  
  <script>
    $(function () {
      // 引用自动生成的集线器代理
      var chat = $.connection.serverhub;
      // 定义服务器端调用的客户端sendmessage来显示新消息
      
      chat.client.sendmessage = function (name, message) {
        // 向页面添加消息
        $('#discussion').append('<li><strong>' + htmlencode(name)
          + '</strong>: ' + htmlencode(message) + '</li>');
      };
      
      // 设置焦点到输入框
      $('#message').focus();
      // 开始连接服务器
      $.connection.hub.start().done(function () {
        $('#sendmessage').click(function () {
          // 调用服务器端集线器的send方法
          chat.server.send($('#message').val());
          // 清空输入框信息并获取焦点
          $('#message').val('').focus();
        });
      });
    });
    
    // 为显示的消息进行html编码
    function htmlencode(value) {
      var encodedvalue = $('<div />').text(value).html();
      return encodedvalue;
    }
  </script>
  }

  9. 修改app_start文件夹内的routconfig类,将action方法默认设置为chat.

public class routeconfig
  {
    public static void registerroutes(routecollection routes)
    {
      routes.ignoreroute("{resource}.axd/{*pathinfo}");
      routes.maproute(
        name: "default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "home", action = "chat", id = urlparameter.optional }
      );
    }
  }

  到此,我们的例子就实现完成了,接下来我们先来看看运行效果,之后再来解释到底signalr是如何来完成广播消息的。运行的运行结果如下。

  从运行结果,你可以发现,在任何一个窗口输入信息并发送,所有客户端将收到该消息。这样的效果在实际应用中很多,如qq,一登录qq的时候都会推送腾讯广告消息。

  看完了运行结果,接下来我们来分析下代码,进而来剖析下signalr到底是如何工作的。

  按照b/s模式来看,运行程序的时候,web页面就与signalr的服务建立了连接,具体的建立连接的代码就是:$.connection.hub.start()。这句代码的作用就是与signalr服务建立连接,后面的done函数表明建立连接成功后为发送按钮注册了一个click事件,当客户端输入内容点击发送按钮后,该click事件将会触发,触发执行的操作为: chat.server.send($('#message').val())。这句代码表示调用服务端的send函数,而服务端的send韩式又是调用所有客户端的sendmessage函数,而客户端中sendmessage函数就是将信息添加到对应的消息列表中。这样就实现了广播消息的功能了。

  看到这里,有人是否会有疑问,前面的实现都只用到了集线器对象,而没有用到持久连接对象。其实并不是如此,$.connection这句代码就是使用持久连接对象,当然你也可以在重新onconnected方法来查看监控客户端的连接情况,更新的代码如下所示:

 public class serverhub : hub
  {
    private static readonly char[] constant =
    {
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
      'w', 'x', 'y', 'z',
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
      'w', 'x', 'y', 'z'
    };

    /// <summary>
    /// 供客户端调用的服务器端代码
    /// </summary>
    /// <param name="message"></param>
    public void send(string message)
    {
      var name = generaterandomname(4);

      // 调用所有客户端的sendmessage方法
      clients.all.sendmessage(name, message);
    }

    /// <summary>
    /// 客户端连接的时候调用
    /// </summary>
    /// <returns></returns>
    public override task onconnected()
    {
      trace.writeline("客户端连接成功");
      return base.onconnected();
    }

    /// <summary>
    /// 产生随机用户名函数
    /// </summary>
    /// <param name="length">用户名长度</param>
    /// <returns></returns>
    public static string generaterandomname(int length)
    {
      var newrandom = new system.text.stringbuilder(62);
      var rd = new random();
      for (var i = 0; i < length; i++)
      {
        newrandom.append(constant[rd.next(62)]);
      }
      return newrandom.tostring();
    }
  }

  这样在运行页面的时候,将在输出窗口看到“客户端连接成功”字样。运行效果如下图所示:

  在第二部分介绍的时候说道,在服务端声明的所有hub信息,都会生成javascript输出到客户端,为了验证这一点,可以在chrome中f12来查看源码就明白了,具体如下图所示:

 看到上图,你也就明白了为什么chat.cshtml页面需要引入"signalr/hubs"脚本库了吧。

<!--引用signalr库. -->
  <script src="~/scripts/jquery.signalr-2.2.0.min.js"></script>
   <!--引用自动生成的signalr 集线器(hub)脚本.在运行的时候在浏览器的source下可看到 -->
  <script src="~/signalr/hubs"></script>

四、在桌面程序中如何使用asp.net signalr
   上面部分介绍了signalr在asp.net mvc 中的实现,这部分将通过一个例子来看看signalr在wpf或winform是如何使用的。其实这部分实现和asp.net mvc中非常相似,主要不同在于,asp.net mvc中的signalr服务器寄宿在iis中,而在wpf中应用,我们把signalr寄宿在wpf客户端中。

下面让我们看看signalr服务端的实现。

/// <summary>
    /// 启动signalr服务,将signalr服务寄宿在wpf程序中
    /// </summary>
    private void startserver()
    {
      try
      {
        signalr = webapp.start(serveruri); // 启动signalr服务
      }
      catch (targetinvocationexception)
      {
        writetoconsole("一个服务已经运行在:" + serveruri);
        // dispatcher回调来设置ui控件状态
        this.dispatcher.invoke(() => buttonstart.isenabled = true);
        return;
      }

      this.dispatcher.invoke(() => buttonstop.isenabled = true);
      writetoconsole("服务已经成功启动,地址为:" + serveruri);
    }

public class chathub : hub
  {
    public void send(string name, string message)
    {
      clients.all.addmessage(name, message);
    }

    public override task onconnected()
    {
      //
      application.current.dispatcher.invoke(() =>
        ((mainwindow)application.current.mainwindow).writetoconsole("客户端连接,连接id是: " + context.connectionid));

      return base.onconnected();
    }

    public override task ondisconnected(bool stopcalled)
    {
       application.current.dispatcher.invoke(() =>
        ((mainwindow)application.current.mainwindow).writetoconsole("客户端断开连接,连接id是: " + context.connectionid));

      return base.ondisconnected(true);
    }
  }

 public class startup
  {
    public void configuration(iappbuilder app)
    {
      // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?linkid=316888
      // 允许cors跨域
      //app.usecors(corsoptions.allowall);
      app.mapsignalr();
    }
  }
 

  通过上面的代码,我们signalr服务端的实现就完成了,其实现逻辑与asp.net mvc的代码类似。

  接下来,让我们看看,wpf客户端是如何连接和与服务器进行通信的。具体客户端的实现如下:

 public ihubproxy hubproxy { get; set; }
    const string serveruri = "http://localhost:8888/signalr";
    public hubconnection connection { get; set; }

    public mainwindow()
    {
      initializecomponent();

      // 窗口启动时开始连接服务
      connectasync();
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void buttonsend_click(object sender, routedeventargs e)
    {
      // 通过代理来调用服务端的send方法
      // 服务端send方法再调用客户端的addmessage方法将消息输出到消息框中
      hubproxy.invoke("send", generaterandomname(4), textboxmessage.text.trim());

      textboxmessage.text = string.empty;
      textboxmessage.focus();
    }

    private async void connectasync()
    {
      connection = new hubconnection(serveruri);
      connection.closed += connection_closed;

      // 创建一个集线器代理对象
      hubproxy = connection.createhubproxy("chathub");

      // 供服务端调用,将消息输出到消息列表框中
      hubproxy.on<string, string>("addmessage", (name, message) =>
         this.dispatcher.invoke(() =>
          richtextboxconsole.appendtext(string.format("{0}: {1}\r", name, message))
        ));

      try
      {
        await connection.start();
      }
      catch (httprequestexception)
      {
        // 连接失败
        return;
      }

      // 显示聊天控件
      chatpanel.visibility = visibility.visible;
      buttonsend.isenabled = true;
      textboxmessage.focus();
      richtextboxconsole.appendtext("连上服务:" + serveruri + "\r");
    }

  上面的代码也就是wpf客户端实现的核心代码,主要逻辑为,客户端启动的时候就调用connection.start方法与服务器进行连接。然后通过hubproxy代理类来调用集线器中send方法,而集线器中的send方法又通过调用客户端的addmessage方法将消息输出到客户端的消息框中进行显示,从而完成消息的推送过程。接下来,让我们看看其运行效果:

   从上面的运行效果看出,其效果和asp.net mvc上的效果是一样的。

五、总结
   到这里,本专题的所有内容就结束了,这篇signalr快速入门也是本人在学习signalr过程中的一些心得体会,希望可以帮助一些刚接触signalr的朋友快速入门。本篇主要实现了signalr的广播消息的功能,可以实现手机端消息推送的功能,接下来一篇将介绍如何使用signalr实现一对一的聊天。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网