Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
В прошлый раз мы определили контроллер и модель, а теперь создадим всю остальную часть чата. Вначале определим представления.
Код главного представления Index.cshtml будет выглядеть следующим образом:
@model AjaxChat.Models.ChatModel @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Чат на Ajax и JQuery</title> @Styles.Render("~/Content/Site.css") </head> <body> <div id="Username"> </div> <div id="LastRefresh"> </div> <div id="container"> <div id="loginBlock"> Введите имя : <input type="text" id="txtUserName" /> <button id="btnLogin" value="Войти">Войти</button> </div> </div> <div id="Error"> </div> @Ajax.ActionLink("Login", "Index", new { user = "" }, new AjaxOptions { UpdateTargetId = "container", OnFailure = "LoginOnFailure", OnSuccess = "LoginOnSuccess" }, new { @id = "LoginButton", @style = "visibility:hidden;" }) @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/scripts/jquery.unobtrusive-ajax.min.js") @Scripts.Render("~/Scripts/chat.js") </body> </html>
Это представление без мастер-страницы. Элемент div
с id="Username" будет отображать ник пользователя.
Блок с id="LastRefresh
предназначен для отображения времени последнего обновления чата, а div
c id="Error" - для
вывода ошибок, которые могут возникнуть.
И для собственно логина у нас есть текстовое поле и кнопка. Однако при вводе ника и нажатии на кнопку данные сразу не будут передаваться на сервер, так как это не форма. Реальная отправка данных на сервер будет происходить с помощью ajax-ссылки, которая будет иметь id = "LoginButton":
@Ajax.ActionLink("Login", "Index", new { user = "" }, new AjaxOptions { UpdateTargetId = "container", OnFailure = "LoginOnFailure", OnSuccess = "LoginOnSuccess" }, new { @id = "LoginButton", @style = "visibility:hidden;" })
При нажатии на ссылку будет происходить обновление блока с id="container"
. За счет этого будет происходить частичное обновление текущей страницы
с помощью ajax, а не обычная перезагрузка страницы. Но сами мы на ссылку нажимать не будем. Мы ее даже видеть не будем, так как у нее установлен
стиль "visibility:hidden;"
Нажатие будет происходить автоматически в поключаемом в представлении файле chat.js:
$(document).ready(function () { // логин $("#btnLogin").click(function () { var nickName = $("#txtUserName").val(); if (nickName) { // формируем ссылку с параметрами, по которой идет обращение var href = "/Home?user=" + encodeURIComponent(nickName); href = href + "&logOn=true"; $("#LoginButton").attr("href", href).click(); //установка поля с ником пользователя $("#Username").text(nickName); } }); }); //при успешном входе загружаем сообщения function LoginOnSuccess(result) { Scroll(); ShowLastRefresh(); //каждые пять секунд обновляем чат setTimeout("Refresh();", 5000); //отправка сообщений по нажатию Enter $('#txtMessage').keydown(function (e) { if (e.keyCode == 13) { e.preventDefault(); $("#btnMessage").click(); } }); //установка обработчика нажатия кнопки для отправки сообщений $("#btnMessage").click(function () { var text = $("#txtMessage").val(); if (text) { //обращаемся к методу Index и передаем параметр "chatMessage" var href = "/Home?user=" + encodeURIComponent($("#Username").text()); href = href + "&chatMessage=" + encodeURIComponent(text); $("#ActionLink").attr("href", href).click(); } }); //обработчик кнопки выхода из чата $("#btnLogOff").click(function () { //обращаемся к методу Index и передаем параметр "logOff" var href = "/Home?user=" + encodeURIComponent($("#Username").text()); href = href + "&logOff=true"; $("#ActionLink").attr("href", href).click(); document.location.href = "Home"; }); } //при ошибке отображаем сообщение об ошибке при логине function LoginOnFailure(result) { $("#Username").val(""); $("#Error").text(result.responseText); setTimeout("$('#Error').empty();", 2000); } // каждые пять секунд обновляем поле чата function Refresh() { var href = "/Home?user=" + encodeURIComponent($("#Username").text()); $("#ActionLink").attr("href", href).click(); setTimeout("Refresh();", 5000); } //Отображаем сообщение об ошибке function ChatOnFailure(result) { $("#Error").text(result.responseText); setTimeout("$('#Error').empty();", 2000); } // при успешном получении ответа с сервера function ChatOnSuccess(result) { Scroll(); ShowLastRefresh(); } //скролл к низу окна function Scroll() { var win = $('#Messages'); var height = win[0].scrollHeight; win.scrollTop(height); } //отображение времени последнего обновления чата function ShowLastRefresh() { var dt = new Date(); var time = dt.getHours() + ":" + dt.getMinutes() + ":" + dt.getSeconds(); $("#LastRefresh").text("Последнее обновление было в " + time); }
Чтобы отправить данные по логину и нажать на ссылку, в обработчике нажатия мы прописываем следующие строки:
// формируем ссылку с параметрами, по которой идет обращение var href = "/Home?user=" + encodeURIComponent(nickName); href = href + "&logOn=true"; // автоклик по ajax-ссылке $("#LoginButton").attr("href", href).click();
Поскольку в запросе к серверу передается параметр logOn=true, то метод Index при обработке этого запроса будет отправлять клиенту частичное представление
ChatRoom: return PartialView("ChatRoom", chatModel);
. Создадим это представление:
@using AjaxChat.Models @model ChatModel <div id="RefreshArea"> @{ Html.RenderPartial("History", Model); } </div> @Ajax.ActionLink("ActionLink", "Index", new { user = "", logOn = "", logOff = "", chatMessage = "" }, new AjaxOptions { UpdateTargetId = "RefreshArea", OnSuccess = "ChatOnSuccess", OnFailure = "ChatOnFailure" }, new { @id = "ActionLink", @style = "visibility:hidden;" }) <div id="inputForm"> <table> <tr> <td rowspan="2"><textarea id="txtMessage" rows="3"></textarea></td> <td><button id="btnMessage" value="Отправить" >Отправить</button></td> </tr> <tr> <td><button id="btnLogOff" value="Выйти">Выйти</button></td> </tr> </table> </div>
Это частичное представление, типизированное моделью ChatModel, которая передается из метода Index. Оно содержит поля для ввода и отправки сообщений, а также кнопку выхода из чата.
Кроме того, здесь есть блок div id="RefreshArea"
, предназначенный непосредственно для вывода сообщений и пользователей.
Для рендеринга этой информации в нем идет обращение к частичному представлению History, которое мы сейчас создадим. И также тут есть невидимая ajax-ссылка,
обновляющая блок div id="RefreshArea"
:
@Ajax.ActionLink("ActionLink", "Index", new { user = "", logOn = "", logOff = "", chatMessage = "" }, new AjaxOptions { UpdateTargetId = "RefreshArea", OnSuccess = "ChatOnSuccess", OnFailure = "ChatOnFailure" }, new { @id = "ActionLink", @style = "visibility:hidden;" })
В вышерассмотренном файле javacript при удачном логине вызывается функция LoginOnSuccess
, которая в свою очередь вызывает
функцию Refresh()
:
function Refresh() { var href = "/Home?user=" + encodeURIComponent($("#Username").text()); $("#ActionLink").attr("href", href).click(); setTimeout("Refresh();", 5000); }
Эта функция опять же формирует строку запроса с параметрами для ajax-ссылки и производит автоклик на нее. В результате блок div id="RefreshArea"
будет обновляться новыми данными каждые пять секунд.
Подобное действие будет происходить также и при нажатии на кнопку отправки сообщения в чат:
var href = "/Home?user=" + encodeURIComponent($("#Username").text()); href = href + "&chatMessage=" + encodeURIComponent(text); $("#ActionLink").attr("href", href).click();
И поскольку в обоих случаях при передаче параметров в метод Index контроллера параметры logOn и logOff будут не установлены, то метод
Index в ответ будет возвращать частичное представление History.cshtml:return PartialView("History", chatModel);
Теперь создадим само частичное представление History.cshtml:
@using AjaxChat.Models @model ChatModel <div id="Users"> <p><b>В чате онлайн: @Model.Users.Count</b></p> @foreach (ChatUser user in Model.Users) { <p>@user.Name</p> } </div> <div id="Messages"> @foreach (ChatMessage msg in Model.Messages) { <p> @msg.Date<br /> @if (msg.User != null) { <b>@(msg.User.Name + ":")</b> @msg.Text } else { <span class="serverMes">@msg.Text</span> } </p> } </div>
В заключении можно еще как-нибудь стилизовать приложение. В итоге должно получиться примерно так. При запуске мы увидим поле логина:
И при удачном входе в чат уже сможем читать и посылать сообщения: