ASP.NET MVC4异步聊天室的示例代码
发布时间:2020-12-15 20:06:32 所属栏目:asp.Net 来源:网络整理
导读:本文介绍了ASP.NET MVC4异步聊天室的示例代码,分享给大家,具体如下: 类图: Domain层 IChatRoom.cs using System;using System.Collections.Generic;namespace MvcAsyncChat.Domain{ public interface IChatRoom { void AddMessage(string message); void
本文介绍了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,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>> Callbacks { get; private set; } public void Enqueue(Action<IEnumerable<string>,DateTime> callback) { Callbacks.Enqueue(new Tuple<Action<IEnumerable<string>,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"),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,errorThrown) { showError("An unanticipated error occured during the messages request: " + textStatus + "; " + errorThrown); retryGetMessages(); } function onMessages(data,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 SDK将文件上载到S3存储桶的文件夹
- ASP.NET处理程序未在IIS7上运行
- asp.net – MVP MVC和MVVM之间的区别
- asp.net-mvc – RouteCollection和路由表之间有什么区别
- asp.net – 防止将父web.config继承到IIS 7.5上的子应用程序
- asp.net – 通过XSP2运行守护进程的任何问题?
- ASP.NET UpdatePanel和Javascript __dopostback
- asp.net-mvc – 某些Razor视图没有发布
- asp.net – 刷新网页会怎么样?
- asp.net-mvc – ASP.NET MVC中的WebApi [FromUri]是什么?
推荐文章
站长推荐
- asp.net – 如何在经典的asp中使用.net共享会话?
- ASP.NET Core:跟踪当前活动页面,或如何在视图中
- asp.net – 访问IIS7 404重定向页面中的原始URL
- asp.net – aspnet_compiler找到错误版本的Syste
- regex – RegularExpressionAttribute – 如何使
- asp.net – 在生产服务器上运行EF迁移的最佳方法
- ASP.NET Hang – 通用字典并发问题导致GC死锁
- 如何将ASP.NET Repeater控件绑定到IList?
- asp.net-mvc – 在MVC中没有持久化Cookie
- asp.net-mvc – 无法加载文件或程序集Oracle.Dat
热点阅读