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