首页 > 编程 > .NET > 正文

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

2020-01-17 22:17:11
字体:
来源:转载
供稿:网友

本文介绍了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>}

运行结果如图:

这里写图片描述

这里写图片描述

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表