本文介绍了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 MVC的Bundle捆绑
- ASP.NET MVC下自定义错误页和展示错误页的方式
- Asp.net MVC scheduler的实现方法详解
- Asp.net mvc验证用户登录之Forms实现详解
- asp.net mvc webapi 实用的接口加密方法示例
- ASP.NET MVC API 接口验证的示例代码
- asp.net mvc CodeFirst模式数据库迁移步骤详解
- IIS部署asp.net mvc网站的方法
- Asp.Net中MVC缓存详解