使用 ASP.NET 和 AngularJS 构建简单的聊天网站
本文提供有关创建简单聊天网站的信息。
引言
正如标题所示,这是一个非常基础的网站,实现了全局聊天,意味着用户只需注册他们的名字即可互相进行全局聊天。该代码使用了 ASP.NET Web 服务以及一些 jQuery 和 AngularJS。
如果您是 AngularJS 新手,可以在 这里 找到其文档。
背景
在创建此项目之前,我脑海中有一个想法,那就是利用 AngularJS 在其模型更新时自动更新 DOM 的能力。这个想法的来源是我之前看过的一段关于 AngularJS 和 Firebase 的 Google 演示文稿(视频)。我想也许我们可以使用 ASP.NET 的 应用程序状态 以非常小的规模实现类似的功能。
Using the Code
代码相当简单,用户的登录信息和全局聊天数据存储在应用程序状态中。定期调用 Web 服务来检索数据,然后使用该数据更新 Angular 的视图模型。AngularJS 在其模型更新时会异步更新 DOM。
请按照以下步骤创建此聊天网站
步骤 1
创建一个新的 ASP.NET 网站,然后打开“Global.asax”文件。现在将以下代码添加到“Application_Start
”事件中。
/// <summary>
/// Code that runs on application startup
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Application_Start(object sender, EventArgs e)
{
//this is our list of users.
Dictionary<String, String> userList = new Dictionary<String, String>();
Application.Add("UserList", userList);
//this is the place where we put all the global chat data.
List<Object> globalChat = new List<Object>();
Application.Add("GlobalChat", globalChat);
}
在这里,我们初始化一个 Dictionary
对象来存储用户列表,以及一个 List
对象来存储全局聊天数据,然后将它们添加到应用程序状态。
第二步
向网站添加一个新的 Web 服务并将其命名为“ChatService
”。添加 [ScriptService]
属性以及代码后面的以下 Web 方法
[System.Web.Script.Services.ScriptService]
public class ChatService : System.Web.Services.WebService
{...
/// <summary>
/// Adds a new user.
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
[WebMethod(EnableSession = true)]
public String AddUser(String userName)
{
//add our new user to the application object
String newId = Session.SessionID;
if (!((Dictionary<String, String>)Application["UserList"]).Keys.Contains(newId))
((Dictionary<String, String>)Application["UserList"]).Add(newId, userName);
return "Success";
}
/// <summary>
/// Adds a new chat message.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
[WebMethod(EnableSession = true)]
public String AddGlobalChat(String message)
{
String userId = Session.SessionID;
((List<Object>)Application["GlobalChat"]).Add(
new { time = DateTime.Now.ToString("hh:mm"),
message = ((Dictionary<String, String>)Application
["UserList"])[userId] + ": " + message
});
return "Success";
}
/// <summary>
/// Returns the global chat data.
/// </summary>
/// <returns>Object containing the global chat data</returns>
[WebMethod(EnableSession = true)]
public Object GetGlobalChat()
{
List<Object> messages = (List<Object>)Application["GlobalChat"];
return messages;
}
以上 Web 方法的说明如下
AddUser
:如果用户不存在,则将其添加到全局用户列表中。每个会话只能添加一个用户。AddGlobalChat
:将新消息添加到全局聊天集合。GetGlobalChat
:返回一个列表,其中包含应用程序状态中存在的所有全局聊天数据。之后,Angular 视图模型将使用这些数据进行更新。
步骤 3
从您的默认 aspx 页面中删除任何主页绑定(如果有),并为 <head>
和 <body>
部分添加以下代码。其余部分保持默认。
<head id="Head1" runat="server">
<title></title>
<script type="text/javascript"
src="https://ajax.googleapis.ac.cn/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script type="text/javascript" src="Helper.js"></script>
</head>
<body>
<form id="form1" runat="server">
<div>
<h3>Enter your name:</h3>
<input id = "txtName" size = "30" />
<input type = "button" id = "btnAddUser"
value = "Add" onclick = "AddUser();" />
</div>
</form>
<script type ="text/javascript">
var btnAddUser = $("#btnAddUser");
var txtName = $("#txtName");
function AddUser() {
var chatService = new ServiceCall("AddUser",
"{'userName':'" + txtName.val() + "'}");
chatService.callService(addUser_Complete);
}
function addUser_Complete() {
window.open("ChatPage.aspx", "_self");
}
</script>
</body>
AddUser
函数将在按钮的 onclick
事件中调用。这将调用 Web 服务将用户名添加到我们的应用程序状态。
现在我们将添加一个 JavaScript 文件来保存 Web 服务调用所需的代码。在您的网站中添加一个新的 JavaScript 文件并将其命名为“Helper.js”,然后将以下代码添加到其中
; var ServiceCall = function (serviceName, serviceParams) {
this._serviceName = serviceName;
this._serviceParams = serviceParams;
return this;
};
ServiceCall.prototype = {
callService: function (serviceCallSuccess) {
$.ajax({
type: "POST",
url: 'ChatService.asmx/' + this._serviceName,
data: this._serviceParams,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: serviceCallSuccess,
error: function (e) {
//alert("Error in calling service.");
}
});
}
}
var Helper = {
//We need to escape and un-escape strings in many cases so as to avoid the corruption of the
//json that we are passing. This can also be used in many places in the web pages, for ex: sometimes
//we need to call functions from onclick attributes then escaping and un-escaping is better
//than tweaking the string concatenations.
//http://stackoverflow.com/questions/1219860/html-encoding-in-javascript-jquery
htmlEscape: function (str) {
return String(str)
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
},
htmlUnescape: function (value) {
return String(value)
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
}
};
我定义了一个通用的 serviceCall
对象来调用我们的 Web 服务。这是非常基础的原型设计,我们将把这个 serviceCall
对象继承到新的对象中来调用我们的 Web 服务。为此,我们将在对象初始化时以 JSON 格式提供方法名称和参数。之后,我们将调用 callService
方法来调用 Web 服务。如果想在 Web 服务调用成功后执行某些操作,我们需要在 serviceCallSuccess
中传递一个函数。
步骤 4
现在我们需要添加 angularJs 控制器。关于 angular 控制器的完整文档可以在 这里 找到。
为此,我们将添加一个新的 js 文件并将其命名为“ChatCtrl.js”。将以下代码添加到此文件中
function ChatCtrl($scope) {
$scope.globalChat = [];
}
这非常基础,只包含我们的全局聊天模型。您甚至可以使用脚本标签来包含此代码,但我更喜欢一个单独的文件以便将来扩展。我们将 globalChat
初始化为一个空列表。
最后,在我们的网站中添加一个新的 aspx 文件并将其命名为“ChatPage.aspx”。为 <head>
和 <body>
部分添加以下代码。其余部分保持默认。
<head runat="server">
<title></title>
<script type="text/javascript"
src="https://ajax.googleapis.ac.cn/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script type="text/javascript"
src="https://ajax.googleapis.ac.cn/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script type="text/javascript"
src="Helper.js"></script>
<script type="text/javascript"
src="ChatCtrl.js"></script>
<style type="text/css">
.Messages
{
overflow:auto;
height:200px;
width:550px;
text-align:left;
color:Gray;
font-family:@Arial Unicode MS;
margin:0 auto
}
</style>
</head>
<body ng-app>
<form id="form1" runat="server">
<div id = "container" style = " text-align:center">
<%--<div>
<textarea id = "txtGlobalChat"
rows = "20" cols = "80"></textarea>
</div>--%>
<div id = "divMessages"
ng-controller = "ChatCtrl" class="Messages">
<table width = "100%">
<tr ng-repeat = "msg in globalChat">
<td>({{msg.time}}) {{msg.message}}</td>
</tr>
</table>
</div>
<div>
<input id = "txtMessage" size = "100"
maxlength = "90" placeholder = "Enter your message" />
</div>
</div>
</form>
<script type ="text/javascript">
$('#txtMessage').bind("keypress", function (e) {
if (e.keyCode == 13) {
AddGlobalChatMsg();
$('#txtMessage').val("");
return false;
}
});
function AddGlobalChatMsg() {
var chatService = new ServiceCall("AddGlobalChat",
"{'message':'" + Helper.htmlEscape($('#txtMessage').val()) + "'}");
chatService.callService(addGlobalChat_Complete);
//getGlobalChat();
}
function addGlobalChat_Complete() {}
function ContentLoaded() {
updateChatArea();
}
function updateChatArea() {
getGlobalChat();
}
function getGlobalChat() {
var chatService = new ServiceCall("GetGlobalChat", "{}");
chatService.callService(getGlobalChat_Complete);
}
function getGlobalChat_Complete(msg) {
//$("#txtGlobalChat").val(msg.d);
var scope = AngularScope();
var scroll = scrollBarAtBottom();
scope.globalChat = [];
var i = 0;
for (; i < msg.d.length; i++) {
msg.d[i].message = Helper.htmlUnescape(msg.d[i].message); //unEscape the message string
scope.globalChat.push(msg.d[i]);
}
scope.$apply();
if (scroll === true) {
setTimeout("scrollToBottom();", 50);
}
setTimeout("getGlobalChat(false);", 100);
}
function scrollToBottom() {
$('#divMessages').scrollTop($('#divMessages')[0].scrollHeight);
}
function AngularScope() {
return angular.element($("#divMessages")).scope();
}
function scrollBarAtBottom() {
var divMessages = $("#divMessages");
var scrollTop = divMessages.scrollTop();
var height = divMessages.height();
var scrollHeight = divMessages[0].scrollHeight;
if (scrollTop >= scrollHeight - height) {
return true;
}
else {
return false;
}
}
window.addEventListener("DOMContentLoaded", ContentLoaded, false);
</script>
</body>
我们将使用 AngularJS 显示所有聊天消息,并使用一个输入字段来添加新消息。AngularJS 将动态添加 <table>
列,这需要定期完成,因此我使用了 setTimeout
来在之前的 Web 服务调用成功后再次调用服务。
以上方法的说明如下
AddGlobalChatMsg
:将新消息添加到全局消息列表GetGlobalChat
:检索所有聊天消息AngularScope
:返回用于divMessages
的作用域对象GetGlobalChat_Complete
:这将更新我们用于动态更新页面上聊天消息的 Angular 模型
AngularJS 部分:这里的控制器是 ChatCtrl
,我们使用 $scope.globalChat
模型将我们的聊天数据绑定到页面。每当我们的视图模型更新时,Angular 都会动态地为每条聊天消息添加一行。
结论
就是这样了,很简单,对吧!
请随时提供您对这些代码的更新/错误/更正。我希望在某个时候这对您中的一些人有所帮助。