ASP.NET MVC4异步聊天室的示例代码

本文介绍了ASP.NET MVC4异步聊天室的示例代码,分享给大家,具体如下:

类图:

Domain层

IChatRoom.cs

using System;
using System.Collections.Generic;

namespace MvcAsyncChat.Domain
{
  public interface IChatRoom
  {
    void AddMessage(string message);
    void AddParticipant(string name);
    void GetMessages(
      DateTime since,
      Action<IEnumerable<string>, DateTime> callback);
    void RemoveParticipant(string name);
  }
}

IMessageRepo.cs

using System;
using System.Collections.Generic;

namespace MvcAsyncChat.Domain
{
  public interface IMessageRepo
  {
    DateTime Add(string message);
    IEnumerable<string> GetSince(DateTime since);
  }
}

ICallbackQueue.cs

using System;
using System.Collections.Generic;

namespace MvcAsyncChat.Domain
{
  public interface ICallbackQueue
  {
    void Enqueue(Action<IEnumerable<string>, DateTime> callback);
    IEnumerable<Action<IEnumerable<string>, DateTime>> DequeueAll();
    IEnumerable<Action<IEnumerable<string>, DateTime>> DequeueExpired(DateTime expiry);
  }
}

ChatRoom.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using MvcAsyncChat.Svcs;

namespace MvcAsyncChat.Domain
{
  public class ChatRoom : IChatRoom
  {
    readonly ICallbackQueue callbackQueue;
    readonly IDateTimeSvc dateTimeSvc;
    readonly IMessageRepo messageRepo;

    public ChatRoom(
      ICallbackQueue callbackQueue,
      IDateTimeSvc dateTimeSvc,
      IMessageRepo messageRepo)
    {
      this.callbackQueue = callbackQueue;
      this.dateTimeSvc = dateTimeSvc;
      this.messageRepo = messageRepo;
    }

    public void AddMessage(string message)
    {
      var timestamp = messageRepo.Add(message);

      foreach (var callback in callbackQueue.DequeueAll())
        callback(new[] { message }, timestamp);
    }

    public void AddParticipant(string name)
    {
      AddMessage(string.Format("{0} 已进入房间.", name));
    }

    public void GetMessages(
      DateTime since,
      Action<IEnumerable<string>, DateTime> callback)
    {
      var messages = messageRepo.GetSince(since);

      if (messages.Count() > 0)
        callback(messages, since);
      else
        callbackQueue.Enqueue(callback);
    }

    public void RemoveParticipant(string name)
    {
      AddMessage(string.Format("{0} left the room.", name));
    }
  }
}

InMemMessageRepo.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace MvcAsyncChat.Domain
{
  public class InMemMessageRepo : IMessageRepo
  {
    public InMemMessageRepo()
    {
      Messages = new List<Tuple<string, DateTime>>();
    }

    public IList<Tuple<string, DateTime>> Messages { get; private set; }

    public DateTime Add(string message)
    {
      var timestamp = DateTime.UtcNow;

      Messages.Add(new Tuple<string, DateTime>(message, timestamp));

      return timestamp;
    }

    public IEnumerable<string> GetSince(DateTime since)
    {
      return Messages
        .Where(x => x.Item2 > since)
        .Select(x => x.Item1);
    }
  }
}

CallbackQueue.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace MvcAsyncChat.Domain
{
  public class CallbackQueue : ICallbackQueue
  {
    public CallbackQueue()
    {
      Callbacks = new Queue<Tuple<Action<IEnumerable<string>, DateTime>, DateTime>>();
    }

    public Queue<Tuple<Action<IEnumerable<string>, DateTime>, DateTime>> Callbacks { get; private set; }

    public void Enqueue(Action<IEnumerable<string>, DateTime> callback)
    {
      Callbacks.Enqueue(new Tuple<Action<IEnumerable<string>, DateTime>, DateTime>(callback, DateTime.UtcNow));
    }

    public IEnumerable<Action<IEnumerable<string>, DateTime>> DequeueAll()
    {
      while (Callbacks.Count > 0)
        yield return Callbacks.Dequeue().Item1;
    }

    public IEnumerable<Action<IEnumerable<string>, DateTime>> DequeueExpired(DateTime expiry)
    {
      if (Callbacks.Count == 0)
        yield break;

      var oldest = Callbacks.Peek();
      while (Callbacks.Count > 0 && oldest.Item2 <= expiry)
      {
        yield return Callbacks.Dequeue().Item1;

        if (Callbacks.Count > 0)
          oldest = Callbacks.Peek();
      }
    }
  }
}

RequestModels文件夹实体类

EnterRequest.cs

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace MvcAsyncChat.RequestModels
{
  public class EnterRequest
  {
    [DisplayName("名称")]
    [Required, StringLength(16), RegularExpression(@"^[A-Za-z0-9_\ -]+$", ErrorMessage="A name must be alpha-numeric.")]
    public string Name { get; set; }
  }
}

GetMessagesRequest.cs

using System;

namespace MvcAsyncChat.RequestModels
{
  public class GetMessagesRequest
  {
    public string since { get; set; }
  }
}

SayRequest.cs

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace MvcAsyncChat.RequestModels
{
  public class SayRequest
  {
    [Required, StringLength(1024), DataType(DataType.MultilineText)]
    public string Text { get; set; }
  }
}

ResponseModels文件夹实体类

GetMessagesResponse.cs

using System;
using System.Collections.Generic;

namespace MvcAsyncChat.ResponseModels
{
  public class GetMessagesResponse
  {
    public string error { get; set; }
    public IEnumerable<string> messages { get; set; }
    public string since { get; set; }
  }
}

SayResponse.cs

using System;

namespace MvcAsyncChat.ResponseModels
{
  public class SayResponse
  {
    public string error { get; set; }
  }
}

ChatController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Async;
using MvcAsyncChat.Domain;
using MvcAsyncChat.RequestModels;
using MvcAsyncChat.ResponseModels;
using MvcAsyncChat.Svcs;

namespace MvcAsyncChat.Controllers
{
  public class ChatController : AsyncController
  {
    readonly IAuthSvc authSvc;
    readonly IChatRoom chatRoom;
    readonly IDateTimeSvc dateTimeSvc;

    public ChatController(
      IAuthSvc authSvc,
      IChatRoom chatRoom,
      IDateTimeSvc dateTimeSvc)
    {
      this.authSvc = authSvc;
      this.chatRoom = chatRoom;
      this.dateTimeSvc = dateTimeSvc;
    }

    [ActionName("enter"), HttpGet]
    public ActionResult ShowEnterForm()
    {
      if (User.Identity.IsAuthenticated)
        return RedirectToRoute(RouteName.Room);

      return View();
    }

    [ActionName("enter"), HttpPost]
    public ActionResult EnterRoom(EnterRequest enterRequest)
    {
      if (!ModelState.IsValid)
        return View(enterRequest);

      authSvc.Authenticate(enterRequest.Name);
      chatRoom.AddParticipant(enterRequest.Name);

      return RedirectToRoute(RouteName.Room);
    }

    [ActionName("room"), HttpGet, Authorize]
    public ActionResult ShowRoom()
    {
      return View();
    }

    [ActionName("leave"), HttpGet, Authorize]
    public ActionResult LeaveRoom()
    {
      authSvc.Unauthenticate();
      chatRoom.RemoveParticipant(User.Identity.Name);

      return RedirectToRoute(RouteName.Enter);
    }

    [HttpPost, Authorize]
    public ActionResult Say(SayRequest sayRequest)
    {
      if (!ModelState.IsValid)
        return Json(new SayResponse() { error = "该请求无效." });

      chatRoom.AddMessage(User.Identity.Name+" 说:"+sayRequest.Text);

      return Json(new SayResponse());
    }

    [ActionName("messages"), HttpPost, Authorize]
    public void GetMessagesAsync(GetMessagesRequest getMessagesRequest)
    {
      AsyncManager.OutstandingOperations.Increment();

      if (!ModelState.IsValid)
      {
        AsyncManager.Parameters["error"] = "The messages request was invalid.";
        AsyncManager.Parameters["since"] = null;
        AsyncManager.Parameters["messages"] = null;
        AsyncManager.OutstandingOperations.Decrement();
        return;
      }

      var since = dateTimeSvc.GetCurrentDateTimeAsUtc();
      if (!string.IsNullOrEmpty(getMessagesRequest.since))
        since = DateTime.Parse(getMessagesRequest.since).ToUniversalTime();

      chatRoom.GetMessages(since, (newMessages, timestamp) =>
      {
        AsyncManager.Parameters["error"] = null;
        AsyncManager.Parameters["since"] = timestamp;
        AsyncManager.Parameters["messages"] = newMessages;
        AsyncManager.OutstandingOperations.Decrement();
      });
    }

    public ActionResult GetMessagesCompleted(
      string error,
      DateTime? since,
      IEnumerable<string> messages)
    {
      if (!string.IsNullOrWhiteSpace(error))
        return Json(new GetMessagesResponse() { error = error });

      var data = new GetMessagesResponse();
      data.since = since.Value.ToString("o");
      data.messages = messages;

      return Json(data);
    }
  }
}

room.js

var since = "",
  errorCount = 0,
  MAX_ERRORS = 6;

function addMessage(message, type) {
  $("#messagesSection > td").append("<div class='" + (type || "") + "'>" + message + "</div>")
}

function showError(error) {
  addMessage(error.toString(), "error");
}

function onSayFailed(XMLHttpRequest, textStatus, errorThrown) {
  showError("An unanticipated error occured during the say request: " + textStatus + "; " + errorThrown);
}

function onSay(data) {
  if (data.error) {
    showError("An error occurred while trying to say your message: " + data.error);
    return;
  }
}

function setSayHandler() {
  $("#Text").keypress(function (e) {
    if (e.keyCode == 13) {
      $("#sayForm").submit();
      $("#Text").val("");
      return false;
    }
  });
}

function retryGetMessages() {
  if (++errorCount > MAX_ERRORS) {
    showError("There have been too many errors. Please leave the chat room and re-enter.");
  }
  else {
    setTimeout(function () {
      getMessages();
    }, Math.pow(2, errorCount) * 1000);
  }
}

function onMessagesFailed(XMLHttpRequest, textStatus, errorThrown) {
  showError("An unanticipated error occured during the messages request: " + textStatus + "; " + errorThrown);
  retryGetMessages();
}

function onMessages(data, textStatus, XMLHttpRequest) {
  if (data.error) {
    showError("An error occurred while trying to get messages: " + data.error);
    retryGetMessages();
    return;
  }

  errorCount = 0;
  since = data.since;

  for (var n = 0; n < data.messages.length; n++)
    addMessage(data.messages[n]);

  setTimeout(function () {
    getMessages();
  }, 0);
}

function getMessages() {
  $.ajax({
    cache: false,
    type: "POST",
    dataType: "json",
    url: "/messages",
    data: { since: since },
    error: onMessagesFailed,
    success: onMessages,
    timeout: 100000
  });
}

Chat视图文件夹

Enter.cshtml

@model MvcAsyncChat.RequestModels.EnterRequest

@{
  View.Title = "Enter";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

@section Head {}

<tr id="enterSection">
  <td>
    <h2>[MVC聊天]是使用ASP.NET MVC 3的异步聊天室
    <table>
      <tr>
        <td class="form-container">
          <fieldset>
            <legend>进入聊天室</legend>
            @using(Html.BeginForm()) {
              @Html.EditorForModel()
              <input type="submit" value="Enter" />
            }
          </fieldset>
        </td>
      </tr>
    </table>
  </td>
</tr>

@section PostScript {
  <script>
    $(document).ready(function() {
      $("#Name").focus();
    });
  </script>
}

Room.cshtml

@using MvcAsyncChat;
@using MvcAsyncChat.RequestModels;
@model SayRequest

@{
  View.Title = "Room";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

@section Head {
  <script src="@Url.Content("~/Scripts/room.js")"></script>
}

<tr id="messagesSection">
  <td></td>
</tr>
<tr id="actionsSection">
  <td>

    <label for="actionsList">操作:</label>
    <ul id="actionsList">
      <li>@Html.RouteLink("离开房间", RouteName.Leave)</li>
    </ul>
    @using (Ajax.BeginForm("say", new { }, new AjaxOptions() {
      OnFailure = "onSayFailed",
      OnSuccess = "onSay",
      HttpMethod = "POST", }, new { id = "sayForm"})) {
      @Html.EditorForModel()
    }
  </td>
</tr>

@section PostScript {
  <script>
    $(document).ready(function() {
      $("#Text").attr("placeholder", "你说:");
      $("#Text").focus();
      setSayHandler();
      getMessages();
    });
  </script>
}

运行结果如图:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Asp.net使用SignalR实现酷炫端对端聊天功能

    一.引言 在前一篇文章已经详细介绍了SignalR了,并且简单介绍它在Asp.net MVC 和WPF中的应用.在上篇博文介绍的都是群发消息的实现,然而,对于SignalR是为了实时聊天而生的,自然少了不像QQ一样的端对端的聊天了.本篇博文将介绍如何使用SignalR来实现类似QQ聊天的功能. 二.使用SignalR实现端对端聊天的思路 在介绍具体实现之前,我先来介绍了使用SignalR实现端对端聊天的思路.相信大家在前篇文章已经看到过Clients.All.sendMessage(name,

  • asp.net mvc signalr简单聊天室制作过程分析

    signalr的神奇.实用很早就知道,但一直都没有亲自去试用,仅停留在文章,看了几篇简单的介绍文字,感觉还是很简单易用的. 由于最后有个项目需要使用到它,所以就决定写个小程序测试一下,实践出真知:别人写的文章,由于环境(版本等)不同,还是或多或少存在一些出入的. 环境:vs2013 / asp.net mvc 5 / signalr 2.2.1 / jquery 1.10.2 先上两个效果图: 系统会自动给加入聊天室的人员分配一个ID,是该人员的唯一标识(绿色为当前用户说的话,橙色为当前用户之外

  • Asp.net MVC SignalR来做实时Web聊天实例代码

    本章和大家分享的内容是使用Signal R框架创建个简易的群聊功能,主要讲解如何在.Net的MVC中使用这个框架,由于这个项目有官方文档(当然全英文),后面也不打算写分享篇了,主要目的是让朋友们在需要使用Web实时通信的时候有更多一种解决方案,毕竟这是微软主推的一种解决方案之一. SignalR网上简介 ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当所连接的客户端变得可用

  • ASP.NET 使用application与session对象写的简单聊天室程序

    ASP.Net中有两个重要的对象,一个是application对象,一个是session对象. Application:记录应用程序参数的对象,该对象用于共享应用程序级信息. Session:记录浏览器端的变量对象,用来存储跨网页程序程序的变量或者对象. 说实话,写了快一年的asp.net,application对象还真没怎么用过.看了看书,根据这两个对象的特性写了一个简单的聊天室程序.真的是非常的简陋. 我的思路是,有两个页面Default页和ChatRoom页,页面布局如图: Default

  • Asp.net SignalR创建实时聊天应用程序

    一.概述 使用 ASP.NET 那么 SignalR 2 创建一个实时聊天应用程序.将 SignalR 添加 MVC 5 应用程序中,并创建聊天视图发送并显示消息. 在Demo中,将学习SignalR 开发任务包括 ︰ 向 MVC 5 应用程序添加那么 SignalR 图书馆. 创建集线器和浩然启动类,以将内容推送到客户端. 使用 web 页中的那么 SignalR jQuery 库发送邮件并显示更新从集线器. 下面的屏幕快照显示在浏览器中运行的已完成的聊天应用程序. 二.实现 创建一个 ASP

  • Asp.net使用SignalR实现聊天室的功能

    一.引言 在前一篇文章<Asp.net使用SignalR实现酷炫端对端聊天功能>中,我向大家介绍了如何实现实现端对端聊天的功能的,在这一篇文章中将像大家如何使用SignalR实现群聊这样的功能. 二.实现思路 要想实现群聊的功能,首先我们需要创建一个房间,然后每个在线用户可以加入这个房间里面进行群聊,我们可以为房间设置一个唯一的名字来作为标识.那SignalR类库里面是否有这样现有的方法呢?答案是肯定的. // IGroupManager接口提供如下方法 // 作用:将连接ID加入某个组 //

  • ASP.NET网站聊天室的设计与实现(第3节)

    大家都玩过网站聊天室吧,那知道它是怎么实现的吗? 今天我们就来设计一个网站聊天室,用户输入用户名登陆聊天室,采用框架结构实现. 学习内容: 第一步,聊天室首页与简单计数器设计 1.打开VS2008.在"解决方案'101'下新建网站,命名为Chatroom.默认首页文件为Default.aspx. 2.为Default.aspx添加窗体控件,切换到"设计"视图,从左侧工具箱标准组中拖出2个Lable控件,1个Textbox控件,一个Button控件,最后给输入昵称的Textbo

  • ASP.NET MVC4异步聊天室的示例代码

    本文介绍了ASP.NET MVC4异步聊天室的示例代码,分享给大家,具体如下: 类图: Domain层 IChatRoom.cs using System; using System.Collections.Generic; namespace MvcAsyncChat.Domain { public interface IChatRoom { void AddMessage(string message); void AddParticipant(string name); void GetM

  • Python基于Socket实现简易多人聊天室的示例代码

    前言 套接字(Sockets)是双向通信信道的端点. 套接字可以在一个进程内,在同一机器上的进程之间,或者在不同主机的进程之间进行通信,主机可以是任何一台有连接互联网的机器. 套接字可以通过多种不同的通道类型实现:Unix域套接字,TCP,UDP等. 套接字库提供了处理公共传输的特定类,以及一个用于处理其余部分的通用接口. socket模块: 要创建套接字,必须使用套接字模块中的socket.socket()函数,该函数具有一般语法 s = socket.socket (socket_famil

  • Python实现网络聊天室的示例代码(支持多人聊天与私聊)

    实验名称: 网络聊天室 功能: i. 掌握利用Socket进行编程的技术 ii. 掌握多线程技术,保证双方可以同时发送 iii. 建立聊天工具 iv. 可以和单人聊天 v. 可以和多个人同时进行聊天 vi. 使用图形界面,显示双方的语录 vii. 程序可以在一定程度上进行错误识别 概述 实验通过聊天室可以完成单人或多人之间的聊天通信,功能的实现主要是通过Socket通信来实现.本次实验采用客户端/服务器(C/S)架构模式,通过Python语言来编写服务器端与客户端的程序.运用多线程可完成多点对多

  • Java实现NIO聊天室的示例代码(群聊+私聊)

    功能介绍 功能:群聊+私发+上线提醒+下线提醒+查询在线用户 文件 Utils 需要用maven导入下面两个包 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> </dependency> <dependency> <group

  • Qt实现网络聊天室的示例代码

    目录 1. 效果演示 2. 预备知识 2.1 QTcpServer 2.2 QTcpServer信号 2.3 QTcpSocket 2.4 QTcpSocket信号 3. 通信流程 3.1 服务器端 3.2 客户端 1. 效果演示 客户端 服务器 连接成功之后 2. 预备知识 在Qt中,实现网络编程的方式比用C++或C实现要方便简单许多,因为Qt已经替我们封装好了,我们会使用就可以了,然后大家还需要了解Qt 的信号槽机制,可以参考我这篇文章,Qt信号槽 2.1 QTcpServer QTcpSe

  • SpringBoot+Netty实现简单聊天室的示例代码

    目录 一.实现 1.User类 2.SocketSession类 3.SessionGroup 4.WebSocketTextHandler类 5.WebSocketServer类 6.index.html 二.效果 一.实现 1.User类 import java.util.Objects; public class User {     public String id;     public String nickname;     public User(String id, Strin

  • WPF+ASP.NET SignalR实现简易在线聊天功能的示例代码

    目录 涉及知识点 什么是ASP.NET SignalR 在线聊天整体架构 ASP.NET SignalR在线聊天服务端 1. 创建ASP.NET Web API项目 2. 创建消息通知中心Hub 3. 注册服务和路由 4. ASP.NET SignalR中心对象生存周期 SignalR客户端 1. 安装SignalR客户端依赖库 2. 客户端消息接收发送 运行示例 在实际业务中,当后台数据发生变化,客户端能够实时的收到通知,而不是由用户主动的进行页面刷新才能查看,这将是一个非常人性化的设计.有没

  • 利用Python打造一个多人聊天室的示例详解

    一.实验名称 建立聊天工具 二.实验目的 掌握Socket编程中流套接字的技术,实现多台电脑之间的聊天. 三.实验内容和要求 vii.掌握利用Socket进行编程的技术 viii.必须掌握多线程技术,保证双方可以同时发送 ix.建立聊天工具 x.可以和多个人同时进行聊天 xi.必须使用图形界面,显示双方的语录 四.实验环境 PC多台,操作系统Win7,win10(32位.64位) 具备软件python3.6 . 五.操作方法与实验步骤 服务端 1.调入多线程.与scoket包,用于实现多线程连接

  • C语言利用UDP实现群聊聊天室的示例代码

    目录 1.UDP群聊的功能 2.写项目的流程 3.流程图 4.代码实现 4.1头文件 4.2函数 4.3服务器 4.4客户端 1.UDP群聊的功能 有新用户登录,其他在线的用户可以收到登录信息 有用户群聊,其他在线的用户可以收到群聊信息 有用户退出,其他在线的用户可以收到退出信息 服务器可以发送系统信息 2.写项目的流程 画流程图 根据流程图写框架 一个功能一个功能实现 3.流程图 4.代码实现 4.1头文件 #ifndef __MYHEAD_H__ #define __MYHEAD_H__ #

  • java聊天室的实现代码

    本文实例为大家分享了java实现聊天室的具体代码,供大家参考,具体内容如下 聊天室界面: 源码: public class ClientFrame extends Frame { private TextField textFieldContent = new TextField(); private TextArea textAreaContent = new TextArea(); private Socket socket = null; private OutputStream out

随机推荐