В этой статье мы реализуем 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/> </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> </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 схема базы.
Комментариев нет:
Отправить комментарий