本文介绍了ASP.NET MVC4异步聊天室的示例代码,分享给大家,具体如下:
类图:
Domain层
IChatRoom.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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
1
2
3
4
5
6
7
8
9
10
11
|
using System; using System.Collections.Generic; namespace MvcAsyncChat.Domain { public interface IMessageRepo { DateTime Add( string message); IEnumerable< string > GetSince(DateTime since); } } |
ICallbackQueue.cs
1
2
3
4
5
6
7
8
9
10
11
12
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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
1
2
3
4
5
6
7
8
9
|
using System; namespace MvcAsyncChat.RequestModels { public class GetMessagesRequest { public string since { get ; set ; } } } |
SayRequest.cs
1
2
3
4
5
6
7
8
9
10
11
12
|
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
1
2
3
4
5
6
7
8
9
10
11
12
|
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
1
2
3
4
5
6
7
8
9
|
using System; namespace MvcAsyncChat.ResponseModels { public class SayResponse { public string error { get ; set ; } } } |
ChatController.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
@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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
@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 > } |
运行结果如图:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/wulex/article/details/78169106?utm_source=tuicool&utm_medium=referral