ASP.NET MVC4异步聊天室的示例代码
 更新时间:2017年10月17日 15:02:38   作者:逆世风灵  

这篇文章主要介绍了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>
}

运行结果如图:

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

您可能感兴趣的文章:ASP.NET 使用application与session对象写的简单聊天室程序Asp.net使用SignalR实现聊天室的功能ASP.NET网站聊天室的设计与实现(第3节)asp.net mvc signalr简单聊天室制作过程分析.net core使用FastHttpApi构建web聊天室实例代码

ASP.NET
MVC4
异步
聊天

相关文章
ASP.NET Core MVC压缩样式、脚本详解这篇文章主要介绍了ASP.NET Core MVC压缩样式、脚本详解的相关资料,需要的朋友可以参考下 2017-02-02
ASP.NET Core简单介绍教程(1)这篇文章主要为大家详细介绍了Asp.Net Core的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 2017-06-06
ASP.NET MVC4异步聊天室的示例代码这篇文章主要介绍了ASP.NET MVC4异步聊天室的示例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 2017-10-10
Asp.net后台把脚本样式输出到head标签中节省代码冗余最近在学习开发服务器控件,其它就少不了为控件注册js和css之类的资源文件,或者直接注册纯脚本样式。其中就遇到如下问题
    1、 注册的资源文件或纯脚本样式在生成的页面中都不在head标签中(当然这个不影响页面功能)

    2、 一个页面使用多个一样的控件时,会出现重复输入(出现多余代码)

2013-02-02
ADO.NET通用数据库访问类这篇文章主要为大家介绍了ADO.NET通用数据库访问类,利用ADO.NET的体系架构打造通用的数据库访问通用类,感兴趣的小伙伴们可以参考一下 2016-03-03
asp.net替换和恢复html特殊字符替换html中的特殊字符需要进行替换的文本。替换完的文本。 2008-05-05
ASP.NET书籍信息录入实现代码这篇文章主要介绍了ASP.NET书籍信息录入实现代码,特别适合网上书城项目中使用,需要的朋友可以参考下 2015-10-10
HttpWebRequest的常见错误使用TcpClient可避免有时使用HttpWebRequest对象会出现错误有三种服务器提交了协议冲突/基础连接已经关闭:连接被意外关闭/无法发送具有此谓词类型的内容正文,感兴趣的朋友可以参考下本文 2013-02-02
ASP.NET技巧:请求网址并解析返回的htmlASP.NET技巧:请求网址并解析返回的html… 2006-09-09
.NET事件监听机制的局限与扩展分析这篇文章主要介绍了.NET事件监听机制的局限与扩展,详细分析了.NET事件监听机制的机制与优劣,有助于更好的理解.NET的运行原理,需要的朋友可以参考下 2014-11-11

最新评论

声明:本站(华域联盟www.cnhackhy.com)所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。