воскресенье, 29 августа 2010 г.

Реализация web-чата на Asp.Net.

В этой статье мы реализуем web-чат.

Задание

1. Следующие требования являются обязательными:

1.1 Для входа в чат пользователи должны зарегистрироваться. Регистрация должна осуществляться с использованием Forms-based Authentication. На странице регистрации пользователь обязан указать ник, пароль и email

Кроме того может выбрать цвет ника, цвет текста сообщения, количество отображаемых сообщений ( от 15 до 50) по умолчанию 20 , частоту обновления окна с сообщениями чата(от 3 до 60 секунд) по умолчанию 15

1.2 Главное окно приложения представляет frameset разделеное на две части: верхний фрейм отображает сообщения чата, нижний отображает имя под которым зашел пользователь и поле ввода для сообщения и кнопку Send.

1.3 По нажатию кнопки Send сообщение пользователя добавляется в лист сообщений, пользователю отображается последние (указанное при регистрации количество) сообщений в верхнее окно

1.4 Лист сообщений хранится в объекте Application.

1.5 Ни какая информация не хранится на постоянных носителях( в файле, DB итд)

1.6 Верхнее окно самообновлется через заданое пользователем при регистрации количество секунд (стоит использовать META REFRESH , посмотрите как например тут http://chat.radio-msu.net/ )

1.7 При входе в чат(регистрации нового пользователя в системе) к листу сообщений добавляется: "В %ВашГород% %Время% и в чат заходит %НИК%".

1.8 Корректно(usability, security)обрабатывать происходящие в приложении ошибки.

2.Дополнительные задания: ( Важны и влияют на оценку)

2.1 Для отображения листа сообщений используется DataBind

2.2 Организовать сохранение листа сообщения в постоянное место хранения(лишь при уничтожении обьекта Application с последующим воставлением при создании приложения)

2.3 Если пользователь покидает чат то к листу сообщений добавляется "%Ник% покинул чат"

2.4 Обеспечить работу чата с выключенными cookie

2.5 В зависимости от настроек пользователей выводить русскоязычную, англоязычную, либо КАКОЙ_ТО_ЕЩЕ_ЯЗЫчную информацию при регистрации и в нижнем фрейме.

Реализация

Опишем реализацию класса логики нашего приложения, все методы будут снабжены комментариями, поэтому я не буду описывать каждый метод отдельно.

using System;

using System.Data;

using System.Configuration;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

using System.Collections;

using System.Drawing;

using System.Web.SessionState;

/// <summary>

/// Базовый класс

/// </summary>

public class Chat:System.Web.UI.Page

{

/// <summary>

/// Список сообщений

/// </summary>

static protected ArrayList records = new ArrayList();

/// <summary>

/// Количество сообщений на экране

/// </summary>

static public int NumRecord = 0;

/// <summary>

/// Вспомогательная переменная

/// </summary>

protected HtmlForm _form = null;

/// <summary>

/// Инициализация класса

/// </summary>

/// <param name="e"></param>

protected override void OnInit(EventArgs e)

{

base.OnInit(e);

foreach (Control ctl in Controls)

{

if (ctl is HtmlForm)

{

_form = ctl as HtmlForm;

}

}

}

/// <summary>

/// Отправить сообщение в чат

/// </summary>

/// <param name="sUser">Кто отправил</param>

/// <param name="sMsg">Что отправил</param>

static public void AddMessage(string sUser, string sMsg)

{

string sAddText = "~" + sUser + "~" + sMsg;

records.Add(sAddText);

if (records.Count > NumRecord)

{

records.RemoveRange(0, records.Count - NumRecord );

}

}

/// <summary>

/// Получение списка сообщений на экране

/// </summary>

/// <param name="colorNick">Цвет ника</param>

/// <param name="colorText">Цвет текста</param>

/// <returns>список сообщений</returns>

static public string GetAllMessages(string colorNick, string colorText)

{

string sResponse = "";

for (int i = 0; i < records.Count; i++)

{

sResponse = sResponse + FormatChat(records[i].ToString(), colorNick, colorText);

}

return(sResponse);

}

/// <summary>

/// Получение строки textBox-a, в который вводят сообщения

/// </summary>

/// <param name="sKeys"></param>

/// <returns>Строка textBox-a </returns>

protected string GetParamValue(string sKeys)

{

string request = String.Empty;

if (Request.Params[sKeys] != null && Request.Params[sKeys].ToString() != String.Empty)

{

request = Request.Params[sKeys].ToString();

}

return request;

}

/// <summary>

/// Запись сообщения в нужном виде и цвете

/// </summary>

/// <param name="sLine">Строка сообщения</param>

/// <param name="colorNick">Цвет ника</param>

/// <param name="colorText">Цвет текста</param>

/// <returns>Отформатированная строка</returns>

static private string FormatChat(string sLine,string colorNick,string colorText)

{

int iFirst = sLine.IndexOf("~");

int iLast = sLine.LastIndexOf("~");

string sUser = sLine.Substring(iFirst+1, iLast-(iFirst+1));

string sMsg = sLine.Substring(iLast+1);

string strSUser = "<font color=" + colorNick + ">" + sUser + "</font>";

string strSMsg = "<font color=" + colorText + ">" + sMsg + "</font>";

string sRet = strSUser + ": " + strSMsg + "<br>";

return(sRet);

}

}

Теперь опишем интерфейс страниц. Начнём с первой, это Default.aspx.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Untitled Page</title>

</head>

<frameset id="subParentFrame" rows="50%,*" frameborder="1" border="1" framespacing="1">

<frame id="topFrame" name="topFrame" src="TopForm.aspx">

<frame id="bottomFrame" name="bottomFrame" src="BottomForm.aspx">

<noframes></noframes>

</frameset>

</html>

Далее оипишем логику страницы Login.cs.

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

using System.Drawing;

using System.Collections.Generic;

using System.Reflection;

using System.Data.SqlClient;

using ChatDataSetTableAdapters;

/// <summary>

/// Страница авторизации

/// </summary>

public partial class Login : System.Web.UI.Page

{

/// <summary>

/// Датасет для хранения логинов и паролей

/// </summary>

ChatDataSet chatDataSet = new ChatDataSet();

/// <summary>

/// TabelAdapter для выполнения запроса

/// </summary>

UserTableAdapter taUser = new UserTableAdapter();

/// <summary>

/// Метод, выполняющийся при загрузке страницы

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Page_Load(object sender, EventArgs e)

{

if (Page.IsPostBack == false)

{

Application["message"] = "";

Session["NickColor"] = "";

Session["TextColor"] = "";

populateDdlColor(ddlNickColor);

colorManipulation(ddlNickColor);

populateDdlColor(ddlTextColor);

colorManipulation(ddlTextColor);

}

}

#region создание DropDownList выбора цвета

/// <summary>

/// Связывание списка цветов с Items DropDownList-а

/// </summary>

/// <param name="ddl"></param>

private void populateDdlColor(DropDownList ddl)

{

ddl.DataSource = GetColorList();

ddl.DataBind();

}

/// <summary>

/// Окрашивание заднего фона DropDownList

/// </summary>

/// <param name="ddl"></param>

private void colorManipulation(DropDownList ddl)

{

int row;

for (row = 0; row < ddl.Items.Count - 1; row++)

{

ddl.Items[row].Attributes.Add("style",

"background-color:" + ddl.Items[row].Value);

}

ddl.BackColor =

Color.FromName(ddl.SelectedItem.Text);

}

/// <summary>

/// Получение списка цветов

/// </summary>

/// <returns></returns>

private List<string> GetColorList()

{

string[] allColors = Enum.GetNames(typeof(System.Drawing.KnownColor));

string[] systemEnvironmentColors =

new string[(

typeof(System.Drawing.SystemColors)).GetProperties().Length];

int index = 0;

foreach (MemberInfo member in (

typeof(System.Drawing.SystemColors)).GetProperties())

{

systemEnvironmentColors[index++] = member.Name;

}

List<string> finalColorList = new List<string>();

foreach (string color in allColors)

{

if (Array.IndexOf(systemEnvironmentColors, color) < 0)

{

finalColorList.Add(color);

}

}

return finalColorList;

}

/// <summary>

/// Смена цвета

/// </summary>

/// <param name="ddl"></param>

protected void ChangeColor(DropDownList ddl)

{

ddl.BackColor = Color.FromName(ddl.SelectedItem.Text);

colorManipulation(ddl);

ddl.Items.FindByValue(ddl.SelectedValue).Selected = true;

}

#endregion

/// <summary>

/// Смена, выбранного цвета ника

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void ddlNickColor_SelectedIndexChanged(object sender, EventArgs e)

{

ChangeColor(ddlNickColor);

Session["NickColor"] = ddlNickColor.SelectedItem.Value;

}

/// <summary>

/// Смена, выбранного цвета текста

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void ddlTextColor_SelectedIndexChanged(object sender, EventArgs e)

{

ChangeColor(ddlTextColor);

Session["TextColor"] = ddlTextColor.SelectedItem.Value;

}

/// <summary>

/// Авторизация, при нажатии на кнопку Login

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Login_Click(object sender, EventArgs e)

{

taUser.Fill(chatDataSet.Users, login.Value, Password.Value);

if (chatDataSet.Users.Rows.Count != 0)

{

FormsAuthentication.RedirectFromLoginPage(login.Value, cbCookie.Checked);

}

else

{

lbError.Text = "Invalid Credentials: Please try again";

}

Session["Nick"] = tbNick.Text;

Application["Message"] = " came to chat";

Session["Freq"] = Int32.Parse(tbFreqUpdates.Text);

Chat.NumRecord = Int32.Parse(tbNumMessages.Text);

Chat.AddMessage(Session["Nick"].ToString(), Application["Message"].ToString());

}

}

Вот и реализация Login.aspx.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ Import Namespace="System.Web.Security " %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Untitled Page</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<h3><font face="Verdana">Login Page</font></h3>

<table style="width: 347px; height: 126px">

<tr>

<td>

Nick:</td>

<td style="width: 153px">

<asp:TextBox ID="tbNick" runat="server"></asp:TextBox></td>

<td>

<asp:RequiredFieldValidator ID="rfvNick" runat="server" ErrorMessage="*" ControlToValidate="tbNick"></asp:RequiredFieldValidator></td>

</tr>

<tr>

<td>Email:</td>

<td style="width: 153px"><input id="login" type="text" runat=server style="width: 149px; height: 17px"/></td>

<td><ASP:RequiredFieldValidator ID="rfvLogin" ControlToValidate="login" Display="Static" ErrorMessage="*" runat=server/></td>

</tr>

<tr>

<td>Password:</td>

<td style="width: 153px"><input id="Password" type=password runat=server style="width: 148px"/></td>

<td><ASP:RequiredFieldValidator ID="rqfPassword" ControlToValidate="Password" Display="Static" ErrorMessage="*" runat=server/></td>

</tr>

<tr>

<td>Persistent Cookie:</td>

<td style="width: 153px"><ASP:CheckBox id=cbCookie runat="server" /> </td>

<td></td>

</tr>

</table>

<asp:Label id="lbError" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server />

<table style="width: 397px; height: 160px">

<tr>

<td>

Nick Color:</td>

<td style="width: 1px"><asp:DropDownList ID="ddlNickColor" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ddlNickColor_SelectedIndexChanged" Width="128px">

</asp:DropDownList></td>

<td style="width: 2px">

<asp:CompareValidator ID="cvNickColor" runat="server" ControlToValidate="ddlNickColor"

ErrorMessage="*" Operator="NotEqual" ValueToCompare="Transparent"></asp:CompareValidator></td>

</tr>

<tr>

<td>

Text Color:</td>

<td style="width: 1px"><asp:DropDownList ID="ddlTextColor" runat="server" AutoPostBack="True" OnSelectedIndexChanged="ddlTextColor_SelectedIndexChanged" Width="128px">

</asp:DropDownList></td>

<td style="width: 2px">

<asp:CompareValidator ID="cvTextColor" runat="server" ControlToValidate="ddlTextColor"

ErrorMessage="*" Operator="NotEqual" ValueToCompare="Transparent"></asp:CompareValidator></td>

</tr>

<tr>

<td>

Number of messages</td>

<td style="width: 1px">

<asp:TextBox ID="tbNumMessages" runat="server" Width="124px"></asp:TextBox></td>

<td style="width: 2px">

<asp:RequiredFieldValidator ID="rfvNumMessuges" runat="server" ControlToValidate="tbNumMessages"

ErrorMessage="*"></asp:RequiredFieldValidator></td>

</tr>

<tr>

<td>

The frequency of updates</td>

<td style="width: 1px">

<asp:TextBox ID="tbFreqUpdates" runat="server" Width="125px"></asp:TextBox></td>

<td style="width: 2px">

<asp:RequiredFieldValidator ID="rfvFreqUpdates" runat="server" ControlToValidate="tbFreqUpdates"

ErrorMessage="*" Height="10px"></asp:RequiredFieldValidator></td>

</tr>

</table>

<p>

<asp:button ID="Button2" text="Login" OnClick="Login_Click" runat=server/>&nbsp;</p>

</div>

</form>

</body>

</html>

И осталось описать TopForm.aspx и BottomForm.aspx, которые будут грузится во фрэймы на странице Default.

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

/// <summary>

/// Нижний фрейм

/// </summary>

public partial class BottomForm : Chat

{

/// <summary>

/// Метод, выполняющийся при загрузке страницы

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Page_Load(object sender, EventArgs e)

{

string formName = _form.ClientID;

string bottomFunction = String.Concat("javascript:return fnPostBackBetweenFrames('document.", formName, "','topFrame','TopForm.aspx');");

btPost.Attributes.Add("onclick",bottomFunction);

}

}

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="BottomForm.aspx.cs" Inherits="BottomForm" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>BottomForm</title>

<script language="javascript" src="script.js"></script>

</head>

<body>

<form id="form1" runat="server">

<div>

<asp:TextBox ID="tbMessage" runat="server" Height="97px" TextMode="MultiLine" Width="294px"></asp:TextBox>

<br />

<asp:Button ID="btPost" runat="server" Text="Post" Width="298px" Height="25px" />

</div>

</form>

</body>

</html>

using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

using System.Drawing;

/// <summary>

/// Верхний фрейм

/// </summary>

public partial class TopForm : Chat

{

/// <summary>

/// Метод, выполняющийся при загрузке страницы

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void Page_Load(object sender, EventArgs e)

{

Response.Write("<meta http-equiv=\"Refresh\"content=\"" + Session["Freq"] + "\">");

if (GetParamValue("tbMessage") != String.Empty)

{

AddMessage(Session["Nick"].ToString(), GetParamValue("tbMessage"));

}

Response.Write(Chat.GetAllMessages(Session["NickColor"].ToString(), Session["TextColor"].ToString()));

}

}

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="TopForm.aspx.cs" Inherits="TopForm" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>TopForm</title>

</head>

<body>

<form id="form1" runat="server">

<div>

&nbsp;</div>

</form>

</body>

</html>

А вот скрипт который будет обновлять наш фрэйм с чатом.

/* Description : Post between Frames */

function fnPostBackBetweenFrames(postBackFormString, frameName, actionUrl)

{

var postBackForm = eval(postBackFormString);

postBackForm.target = frameName;

postBackForm.action = actionUrl;

postBackForm.__VIEWSTATE.name = '';

postBackForm.method = "post";

postBackForm.submit();

return false;

}

А вот наша xsd схема базы.

clip_image002

Комментариев нет:

Отправить комментарий