ASP.NET MVC4异步聊天室的示例代码
程序员文章站
2022-06-23 10:49:43
本文介绍了asp.net mvc4异步聊天室的示例代码,分享给大家,具体如下:
类图:
domain层
ichatroom.cs
using syste...
本文介绍了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> }
运行结果如图:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读