Chat
Neste artigo você verá como é fácil fazer um chat em ASP.NET sem usar nenhuma biblioteca adicional, apenas o .NET Framework. Para isso vamos usar um recurso chamado callback.
Neste artigo você verá como é fácil fazer um chat em ASP.NET sem usar nenhuma biblioteca adicional, apenas o .NET Framework. Para isso vamos usar um recurso chamado callback.
Callback é uma nova característica do ASP.NET 2.0 que permite receber valores do servidor Web sem renderizar novamente a página. São feitas requisições XMLHTTP ao servidor, ao invés de HTTP.
Para trabalhar com Callback é necessário conhecimento básico em JavaScript para chamar o servidor via XMLHTTP e depois receber o retorno do mesmo. Mas espera aí! Requisições XML assíncronas! Usando JavaScript! Isso é AJAX! Na verdade o AJAX é callback e não o contrário. Callback pode ser considerado uma forma artesanal de AJAX, ou até mesmo o esqueleto de todo componente AJAX.
Quando um postback normal é realizado, é executada uma requisição HTTP, que é processada de acordo com os métodos da interface IPostbackEventHandler. A classe System.Web.UI.Page implementa essa interface. O ciclo de vida da página ao executar um postback normal é mostrado na Figura 1.
Figura 1. Ciclo de vida da página ao executar um postback
Agora, quando executamos um callback, chamamos uma função JavaScript que envia uma requisição XMLHTTP assíncrona ao servidor Web e são processados os métodos da interface ICallbackEventHandler. O ciclo de vida da página ao executar um callback é mostrado na Figura 2.
Figura 2. Ciclo de vida da página ao executar um callback
O chat deste artigo será composto por uma página com uma lista de salas de bate-papo cadastradas no banco. O usuário escolhe a sala e então é aberto um popup com um frameset com três frames. Um frame lateral para listar os usuários, um frame inferior para enviar mensagens e um central com as mensagens dos usuários do chat. O chat também terá a opção de espiar, onde o usuário apenas visualiza as mensagens.
Criando o banco de dados
Vamos primeiro criar o banco de dados para cadastrar as salas de bate-papo e logar as mensagens do chat. Abra o SQL Server Management Studio ou utilize o IDE do Visual studio 2005 e crie um novo banco de dados chamado “DBCHAT”. Depois rode o script da Listagem 1.
Listagem 1. Script do banco
USE DBCHAT
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[CHAT](
[COD_CHAT] [int] IDENTITY(1,1) NOT NULL,
[NOM_CHAT] [varchar](100) NULL,
[DSC_CHAT] [text] NULL,
[MAX_USERS] [int] NULL,
[DAT_CHAT] [datetime] NULL
CONSTRAINT [DF_CHAT_DAT_CHAT] DEFAULT (getdate()),
CONSTRAINT [PK_CHAT] PRIMARY KEY CLUSTERED
(
[COD_CHAT] ASC
) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[CHAT_MENSAGEM](
[COD_CHAT_MENSAGEM] [int] IDENTITY(1,1) NOT NULL,
[DAT_MENSAGEM] [datetime] NULL,
[NICK_AUTOR] [varchar](1000) NULL,
[DSC_MENSAGEM] [text] NULL,
[RESERVADO] [bit] NULL,
[NICK_DESTINO_RESERVADO] [varchar](1000) NULL,
[COD_CHAT] [int] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[SP_CHAT_SALAS_LISTAR]
AS
BEGIN
SET NOCOUNT ON;
SELECT [COD_CHAT],[NOM_CHAT],[DSC_CHAT],[MAX_USERS],
[DAT_CHAT]
FROM [dbo].[CHAT]
ORDER BY
[NOM_CHAT]
END
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[SP_CHAT_INSERIR_MENSAGEM]
@DAT_MENSAGEM DATETIME,
@NICK_AUTOR varchar(1000),@DSC_MENSAGEM text,
@RESERVADO bit,
@NICK_DESTINO_RESERVADO varchar(1000) = null,
@COD_CHAT int
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[CHAT_MENSAGEM]
([DAT_MENSAGEM],[NICK_AUTOR],[DSC_MENSAGEM],
[RESERVADO],[NICK_DESTINO_RESERVADO],[COD_CHAT])
VALUES
(@DAT_MENSAGEM,@NICK_AUTOR,@DSC_MENSAGEM,@RESERVADO,
@NICK_DESTINO_RESERVADO,@COD_CHAT)
END
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[SP_CHAT_SALAS_GET]
@COD_CHAT int
AS
BEGIN
SET NOCOUNT ON;
SELECT [COD_CHAT],[NOM_CHAT],[DSC_CHAT],[MAX_USERS],
[DAT_CHAT]
FROM [dbo].[CHAT]
WHERE
COD_CHAT = @COD_CHAT
END
Nesse script criamos duas tabelas, uma para as salas de bate papo e outra para as mensagens de cada sala. Também criamos três Stored Procedures (SP). Uma para listar as salas on-line, uma para retornar informações de uma sala específica e outra para inserir mensagens do bate-papo, para ficarem armazenadas.
Não criamos uma SP para retornar as mensagens do chat pois elas serão guardadas em uma variável de aplicação on-line, ou seja, quando o usuário ver a mensagem no chat, ela não está sendo recuperada do banco, mas sim do servidor Web. Após rodar o script o banco de dados será semelhante a Figura 3.
Figura 3. Tabelas e Stored Procedures do banco
Criando o projeto
Abra o Visual Studio 2005 e crie um novo projeto Web (File>New>Web Site), dando o nome de “Chat”, usando a linguagem C#. No Solution Explorer clique com o botão direito no projeto e escolha Add ASP.NET Folder>App_Code.
Dentro da pasta App_Code crie uma nova pasta chamada “Chat”. Dentro dessa crie as seguintes classes (menu Website>Add New Item>Class): “ChatManager.cs”, “ChatRoom.cs”, “ChatUser.cs” e “ChatMessage.cs”. Essas classes serão o núcleo do chat. A classe ChatManager é a principal, pois controlará todo o fluxo de mensagens e usuários de todas as salas.
A classe ChatRoom representa uma sala de bate-papo e contém uma fila (Queue) de ChatMessage e uma lista (List) de ChatUser. Nessas duas propriedades usaremos Generics, um novo conceito do C# 2.0. A ChatUser representa um usuário em uma ChatRoom, e a ChatMessage representa uma mensagem enviada ao chat.
Depois volte ao nível de pasta do projeto, e crie uma nova pasta chamada “Controls”. Dentro dessa vamos criar os seguintes User Controls (no momento vamos apenas criá-los, depois vamos codificá-los), clicando com o botão direito sob a pasta e escolhendo Add New Item>Web User Control: “Enviar.ascx”, “Nick.ascx”, “ListaSalas.ascx”, “Mensagem.ascx” e “ListaUsuarios.ascx”.
Vamos usar UserControls, para deixar o chat mais flexível para mudanças e novas funcionalidades. Volte ao nível do projeto e vamos criar as seguintes páginas (no momento vamos apenas criá-las, depois vamos codificá-las): “Nick.aspx”, ”Chat.aspx”, “Usuarios.aspx”, ”Mensagem.aspx” e “Enviar.aspx”. Depois de criar os arquivos, o Solution Explorer deve estar semelhante a Figura 4.
Figura 4. Solution Explorer com os arquivos do projeto
Classes ChatUser e ChatMessage
Para começar vamos trabalhar na classe ChatUser. Abra o arquivo ChatUser.cs e coloque o seguinte código:
public class ChatUser
{
//Nick escolhido pelo usuário
public string Nick;
}
Depois vamos alterar a classe que representa uma mensagem de chat, a ChatMessage. Abra o arquivo ChatMessage.cs e adicione código da Listagem 2.
Listagem 2. Alterando a classe ChatMessage
using System;
public class ChatMessage
{
public ChatMessage()
{
Codigo = DateTime.Now.Ticks;
}
public ChatMessage(long lngCodigo)
{
Codigo = lngCodigo;
}
public long Codigo;
public ChatUser Autor = new ChatUser();
public DateTime Data;
public bool Reservado;
public ChatUser DestinoReservado = null;
public string Message;
}
A classe ChatMessage contém os seguintes atributos públicos:
- Codigo: A classe tem dois construtores, um onde o código é carregado automaticamente com DateTime.Now.Ticks para identificar o milisegundo exato que a mensagem foi criada. No outro construtor, o código é passado por parâmetro;
- Autor, DestinoReservado e Reservado: O Autor nunca é nulo, porém o DestinoReservado recebe nulo quando a mensagem não é reservada. A propriedade Reservado indica se a mensagem é reservada;
- Mensagem: A string da mensagem.
Classe ChatManager
Agora vamos codificar a principal classe do sistema, a ChatManager (ChatManager.cs), pois é nela que teremos todo o controle e mecanismo do chat. Como era de se esperar, essa classe é bastante extensa (Listagem 3). Por restrições de espaço, disponibilizamos o código completo para download, aqui mantive apenas as partes principais necessárias ao bom entendimento.
Listagem 3. Código da classe ChatManager
...
using System.Collections.Generic;
using System.Data.SqlClient;
public class ChatManager
{
private const string
SP_CHAT_ROOM_LIST = "SP_CHAT_SALAS_LISTAR";
private const string
SP_CHAT_ROOM_GET =
"SP_CHAT_SALAS_GET @COD_CHAT=";
private const string SP_CHAT_INSERT_MESSAGE =
"SP_CHAT_INSERIR_MENSAGEM @DAT_MENSAGEM='', "+
"@NICK_AUTOR='',@DSC_MENSAGEM='', "+
"@RESERVADO=,@NICK_DESTINO_RESERVADO='', "+
"@COD_CHAT= ";
private const string
IDENTIFICADOR_CHAT_ROOM_IN_APPLICATION =
"CHATROOM_";
public const string SESSION_ID_CHAT = "idChatRoom";
public const string SESSION_NICK_CHAT = "nick";
public static List getChatRoomList()
{
//lista para retorno
List chatList = new List();
//acessa o banco e retorna um Dataset com as
//Salas de Bate-papo
SqlDataAdapter Adapter = new SqlDataAdapter(
SP_CHAT_ROOM_LIST, ConfigurationManager.
ConnectionStrings[1].ConnectionString);
DataSet objDataSet = new DataSet();
Adapter.Fill(objDataSet);
//Percorre o DataSet retornado do banco,
//e preencha a lista
foreach (DataRow row in objDataSet.Tables[0].Rows)
{
ChatRoom room = getChatRoomById(
Convert.ToString(row["COD_CHAT"]), true);
chatList.Add(room);
}
return chatList;
}
public static ChatRoom getChatRoomById(
string id, bool PreencherNumeroUsuariosOnline)
...
public static ChatRoom CurrentChatRoom
{
get
{
//Se está espiando, então busca a sala da
//QueryString e não da Session
if (HttpContext.Current.Request.QueryString[
"Espiar"] != null)
{
//Busca a QueryString
if (HttpContext.Current.Request.QueryString[
"id"] != null)
{
string id = HttpContext.Current.
Request.QueryString["id"];
return GetChatRoomObjectFromApplication(
id, true);
}
//Se está espiando, e não existe a
//QueryString Id, então retorna null,
//indicando que não existe a Sala Atual
else
{
return null;
}
}
//Busca a queryString
else if (HttpContext.Current.Request.QueryString[
"id"] != null)
{
string id = HttpContext.Current.Request.
QueryString["id"];
return GetChatRoomObjectFromApplication(
id, true);
}
//Se não está espiando, então busca o código da
//sala da Session
else if (HttpContext.Current.Session[
SESSION_ID_CHAT] != null)
{
string id = HttpContext.Current.Session[
SESSION_ID_CHAT].ToString();
return GetChatRoomObjectFromApplication(
id, true);
}
//Se não está espiando, e não existe Session,
//então retorna null, indicando que não existe
//a Sala Atual
else
{
return null;
}
}
set
{
//Busca o Código da sessão, aqui não é preciso
//preocupação com a funcionalidade Espiar,
//pois é desnecessário
string id;
if (HttpContext.Current.Session[
SESSION_ID_CHAT] != null)
{
id = HttpContext.Current.Session[
SESSION_ID_CHAT].ToString();
}
else
{
throw new Exception(
"Por favor, informe o Código da "+
"Sala de Bate-papo");
}
//Acrescenta a sala na variável de Application
HttpContext.Current.Application[
string.Format(
IDENTIFICADOR_CHAT_ROOM_IN_APPLICATION,
id)] = value;
}
}
public static string GetUserListInCurrentChatRoom(
bool TrazCurrentUser, bool DecodificaHTML)
{
string r = "";
foreach (ChatUser user in
CurrentChatRoom.ChatUserList)
{
//se é usuário atual
if (user.Nick ==
CurrentChatRoom.CurrentChatUser.Nick)
{
//se é o usuário atual entra na lista
if (TrazCurrentUser)
{
r += (user.Nick) + "§";
}
}
else
{
r += (user.Nick) + "§";
}
}
// se existe algum usuário
if (r.Length > 0)
//tira última vírgula
r = r.Substring(0, r.Length - 1);
//se é para decodificar o HTML, no caso de um
//Textbox, ComboBox ou Textarea
if (DecodificaHTML)
{
r = HttpUtility.HtmlDecode(r);
}
return r;
}
...
No início da classe declaramos algumas variáveis que representam Stored Procedures no banco de dados. Também criamos variáveis para identificar as variáveis de sessão e aplicação, onde armazenamos as mensagens e os usuários on-line das salas de bate-papo. Quase todos os métodos dessa classe são estáticos.
O getChatRoomList busca do banco as salas de bate-papo cadastradas e retorna uma List. O getChatRoomById(string id, bool PreencherNumeroUsuariosOnline) retorna uma sala de bate-papo específica.
Uma propriedade importante é a CurrentChatRoom que representa a sala de bate-papo que o usuário escolheu, essa variável encapsula uma variável de sessão. O GetUserListInCurrentChatRoom retorna a lista de usuários separados por “§” para que no callback de JavaScript possamos recuperar a lista.
O RemoveChatUserFromCurrentChatRoomByNick exclui o usuário da sala de bate-papo atual, o getNumberUsuariosOnLineByCodigo retorna o número de usuários on-line de uma determinada sala de bate-papo a partir do código passado como parâmetro.
O GetNewMessagesForUserInCurrentChatRoom retorna uma lista de mensagens que o usuário atual ainda não viu, na parte do cliente. Existe uma variável com o código da última mensagem que o usuário recebeu, assim o usuário chama esse método passando o código, e então recebe todas as mensagens mais novas.
Para isso funcionar, existe a propriedade CurrentChatRoom.ChatMessageQueue que é uma fila que guarda as mensagens, utilizando Generics. O SendMessageInCurrentChatRoom acrescenta a mensagem que o usuário enviou na fila de mensagens da sala de bate-papo atual.
Nesse método limitamos o tamanho da fila a 30 mensagens. Com isso se um usuário entrar em uma conversa já existente, ele conseguirá ver apenas as últimas 30 mensagens. Se o seu servidor tiver uma quantidade grande de memória, pode aumentar esse número. Nesse método verificamos o Web.config, e se configurado, logamos no banco a mensagem do usuário.
Classe ChatRoom
Agora vamos codificar a classe ChatRoom, abrindo o arquivo ChatRoom.cs e adicionando código da Listagem 4.
Listagem 4. Classe ChatRoom
...
using System.Collections.Generic;
public class ChatRoom
{
public int Codigo;
public string Nome;
public string Descrição;
public int MaximoUsuarios;
public DateTime Data;
public int UsuariosOnLine;
public List ChatUserList;
public Queue ChatMessageQueue =
new Queue(30);
public ChatUser CurrentChatUser
{
get
{
string apelido;
//Se está espiando, então não há usuário atual,
//e retornamos um objeto instanciado sem dados
if (HttpContext.Current.Request.QueryString[
"Espiar"] != null)
{
return new ChatUser();
}
//se não está espiando, então busca a Session
else if (HttpContext.Current.Session[
ChatManager.SESSION_NICK_CHAT] != null )
{
apelido = HttpContext.Current.Session[
ChatManager.SESSION_NICK_CHAT].ToString();
return ChatManager.
GetChatUserByIdInCurrentChatRoom(apelido);
}
//Se não está na Session, então a segunda opção é
//verificar se existe um POST com o apelido.
//A segunda opção acontecerá quando essa
//propriedade for acessada da tela de Nick
else if (HttpContext.Current.Request.Form[
"txtApelido"] != null )
{
apelido = HttpContext.Current.Request.Form[
"txtApelido"].Replace("'", "");
return ChatManager.
GetChatUserByIdInCurrentChatRoom(apelido);
}
else
{
return null;
}
}
}
}
Nessa classe, a principal propriedade é a CurrentChatUser, que encapsula uma variável de sessão que guarda o usuário atual da sala de bate papo. A propriedade ChatMessageQueue é usada na classe ChatManager para guardar as mensagens da sala de bate papo.
Controle de lista de salas
Agora vamos codificar o controle que lista as salas de bate-papo disponíveis. Para isso, abra o arquivo ListaSalas.ascx e coloque o código da Listagem 5.
Listagem 5. Arquivo ListaSalas
...
<div id="chat" >
<ul>
foreach (ChatRoom room in ChatRoomList)
{
%>
<li>
<span>
(/
)
</span>
<a id="AncoraEspiar"
href="javascript:EspiarChat();">
espiar
</a>
<a id="AncoraEntrar"
</href="javascript:EntrarChat(,
,
);">
Entrar
</a>
</li>
<script type="text/javascript">
//se usuários on-line já lotaram a sala
if (==
)
{
document.getElementById(
'AncoraEntrar').style.display =
'none';
}
//Se a sala não tem usuários OnLine
if (==0)
{
document.getElementById(
'AncoraEspiar').style.display =
'none';
}
</script>
</ul>
</div>
<script type="text/javascript">
//Redireciona o usuário para espiar um chat
function EspiarChat(codigo)
{
var urlespiar =
'chat.aspx?Nick=Espiao&Espiar=true&id=' +
codigo;
window.open(urlespiar, 'EspiarChat',
'toolbar=0, statusbar=0, location=0, '+
'menubar=0, scrollbars=no, width=800px, '+
'height=600px');
}
//redireciona o usuário para colocar seu nick
function EntrarChat(codigo)
{
var urleEntrar = 'nick.aspx?id=' + codigo;
window.open(urleEntrar, 'Chat', 'toolbar=0, '+
'statusbar=0, location=0, menubar=0, '+
'scrollbars=no, width=380px, height=170px');
}
</script>
No controle de salas, escrevemos as listas no HTML do UserControl a partir dos métodos da classe ChatManager e acrescentamos duas funções JavaScript, para abrir a popup do chat em forma de espiar ou em forma de participar. Tecle F7 (ou menu View>Code) para visualizar o código e acrescente o código da Listagem 6.
Listagem 6. Código do ListaSalas.ascx.cs
...
using System.Collections.Generic;
public partial class Controls_ListaSalas : UserControl
{
public List ChatRoomList =
new List();
protected void Page_Load(object sender, EventArgs e)
{
//Se não é a primeira vez que carrega a página
if (!IsPostBack)
{
ChatRoomList = ChatManager.getChatRoomList();
}
}
}
No código anterior, usamos o método da classe ChatManager para preencher uma lista de salas cadastradas no banco de dados. Agora vamos adicionar o controle de lista de salas na página Default.aspx, apenas arrastando o mesmo do Solution Explorer para a página.
Ajustando o Web.Config
Falta apenas um passo para podermos ver funcionando nosso controle, vamos preparar o Web.config. Abra o arquivo e acrescente o código da Listagem 7 (se ainda não existir o arquivo, clique em WebSite>Add New Item>Web Configuration File).
Listagem 7. Alterando o Web.config
<appSettings>
<add key="FazLogMensagensChatNoBanco"
value="true"/>
appSettings>
<connectionStrings>
<add name="ChatStringConnetion"
connectionString="Server=.\SQLEXPRESS;
Database=DBCHAT;Integrated Security=True"/>
</connectionStrings>
Acrescentamos uma AppSetting indicando se deve ser feito o log das mensagens de chat no banco de dados, e também incluímos uma string de conexão apontando para o banco que criamos no início do artigo. Agora, acesse o banco de dados e inclua duas salas de bate papo na tabela Chat (semelhante aos itens da Figura 5). Rode a aplicação e veja a mesma em execução na Figura 6.
Figura 5. Adicionando dados na tabela Chat
Figura 6. Aplicação em execução
Controle de nick
Agora que já temos a página inicial que lista as salas de bate-papo e abre uma popup para o usuário digitar o nick, vamos codificar o controle de nick. Abra o arquivo Nick.ascx e adicione o código da Listagem 8.
Listagem 8. Arquivo Nick.ascx
...
<ul>
<li>
<label for="txtApelido">Digite seu apelido:label>
<input type="text" id="txtApelido"
name="txtApelido"/>
li>
<li>
<a href="javascript:EntrarnoChat();" id="btnEntrar"
title="Entrar">Entrara>
<a href="javascript:Close();" id="btnFechar"
title="Fechar">Fechara>
</li>
</ul>
<script type="text/javascript">
//fecha a janela
function Close()
{
window.close();
}
//Entra o usuário no chat
function EntrarnoChat()
{
if (document.getElementById(
'txtApelido').value=='')
{
alert('Por favor, digite seu Apelido');
}
else
{
document.forms[0].submit();
}
}
//Abre popup do chat
function AbreChat()
{
window.open('chat.aspx', 'ChatMSDN',
'toolbar=0, statusbar=0, location=0, '+
'menubar=0, scrollbars=no, width=800px, '+
'height=600px');
}
</script>
Esse código será a janela onde o usuário digitará o nick. Quando o usuário clicar em Entrar, será aberto outro popup com o próprio chat. Mais adiante você verá que na tela de chat usaremos JavaScript para fechar o popup de nick. Assim, não ficamos com tantos popups abertos. Tecle F7 (ou menu View>Code) para visualizar o código e acrescente o código da Listagem 9.
Listagem 9. Arquivo Nick.ascx.cs
public partial class Controls_Nick: UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if ( Request.Form["txtApelido"] != null )
{
if ( Request.QueryString["id"] != null )
{
string apelido = Server.HtmlEncode((
Request.Form["txtApelido"].Replace(
"'", "").Replace("§", "") ));
if (Request.QueryString["id"] != null)
{
if (Session[ChatManager.
SESSION_ID_CHAT] == null)
{
Session[ChatManager.SESSION_ID_CHAT] =
Convert.ToInt32(Request.QueryString[
"id"]);
}
if (Request.QueryString["id"] !=
Session[ChatManager.SESSION_ID_CHAT].
ToString())
{
string script =
"alert('Você já está participando de "+
"outro Chat, por favor feche-o "+
"primeiro');window.close();";
Page.ClientScript.RegisterStartupScript(
GetType(), "redirect", script, true);
}
else
{
if (ProntoParaInclusaoDeUsuarioNoChat(
apelido))
{
string script;
script = "AbreChat();";
Page.ClientScript.RegisterStartupScript(
GetType(), "redirect", script, true);
Session[ChatManager.SESSION_NICK_CHAT] =
apelido;
}
}
}
}
}
}
private bool ProntoParaInclusaoDeUsuarioNoChat(
string apelido)
{
string script;
//se a sala não está cheia
if (ChatManager.CurrentChatRoom.ChatUserList.Count <
ChatManager.CurrentChatRoom.MaximoUsuarios)
{
//verifica se já existe um usuário com o mesmo nick
if (ChatManager.IsDuplicateNickInCurrentChatRoom(
apelido))
{
//Mostra ao usuário que a sala está cheia
script = "alert('Já existe outro usuário "+
"nessa sala com o Nick que você está "+
"usando, por favor tente outro');";
Page.ClientScript.RegisterStartupScript(
GetType(), "redirect", script, true);
}
else
{
return true;
}
}
else
{
//Mostra ao usuário que a sala está cheia
script = "alert('A Sala Já Está Cheia, tente "+
"novamente mais tarde');parent.window.close();";
Page.ClientScript.RegisterStartupScript(
GetType(), "redirect", script, true);
}
return false;
}
O code behind do controle de nick verifica se o usuário está apto para entrar, verificando se o nick já existe ou se a sala está cheia. Se o usuário conseguir passar nessa validação, o controle abre a popup do chat.
Agora vamos acrescentar o controle que acabamos de codificar na página Nick.aspx (apenas arrastando o mesmo do Solution Explorer para a página). Rode a aplicação e clique em Entrar, você verá uma tela parecida com a Figura 7.
Figura 7. Cadastrando o nick na sala
A página Chat.aspx
A página Chat.aspx conterá um frameset para servir de container para as páginas Mensagem.aspx, Usuarios.aspx e Enviar.aspx. Abra o arquivo Chat.aspx e adicione o código da Listagem 10.
Listagem 10. Arquivo Chat.aspx
...
<title>Untitled Page</title>
<script type="text/javascript">
//Fecha a janela de nick, se ela existir
if (window.opener.location.toString().
indexOf('nick') >= 0)
{
window.opener.close();
}
</script>
</head>
<frameset rows="*,126" cols="*" frameborder="yes"
border="1" framespacing="0">
<frameset cols="*,200" frameborder="yes" border="1"
framespacing="0">
<frame src="Mensagem.aspx?"
name="leftFrame" scrolling="no" noresize="noresize"
id="leftFrame" title="Chat" />
<frame src="Usuarios.aspx?"
name="mainFrame" id="mainFrame" title="Usuários"/>
</frameset>
<frame src="Enviar.aspx?"
name="bottomFrame" scrolling="No"
noresize="noresize" id="bottomFrame"
title="Mensagem"/>
frameset>
<noframes>
<body>
</body>
</noframes>
</html>
Essa página funciona como um container, onde apenas existe um frameset com os frames para os controles de mostrar mensagens, enviar mensagens e mostrar usuários.
Para ver como ficou a página, inicie o sistema a partir da página Default.aspx, escolha uma sala de Chat e então digite seu nick. Ao clicar em Entrar a tela será parecida com a Figura 8.
Figura 8. Tela onde serão adicionadas as mensagens do Chat
Nota: O design do Visual Studio não suporta frameset, portanto, você não poderá arrastar controles para o designer, terá de trabalhar no código HTML.
O controle lista de usuários
Agora vamos codificar o controle para mostrar os usuários que estão na sala. Esse controle também controlará a saída dos usuários. Então abra o arquivo ListaUsuarios.ascx e adicione o código da Listagem 11.
Listagem 11. Arquivo ListaUsuarios.ascx
...
<script type="text/javascript">
//Função para tirar o usuário da Sala de Bate-Papo
function ByeByeUser()
{
ChamarByeByeUserinServer("ByeBye");
}
//Atualiza a lista de usuários a cada segundo
function Updater()
{
ChamarServerListUser();
setTimeout("Updater()",1000);
}
//retorno do callback de quando o usuário está saindo
function RetornoCallBackByByeUser(text,context)
{
//não faz nada pois o usuario já saiu,
//e a tela já fechou quando passar aqui
}
//retorno do callback quando atualiza a
//lista de usuários
function RetornoCallBackListUsers(text,context)
{
var arrText = text.toString().split("§");
document.getElementById('ulUsers').innerHTML =
getHTMLToUserList(arrText);
}
function getHTMLToUserList(arrText)
{
var s = '';
for(var i=0; i < arrText.length;i++)
{
s += '
'+
arrText[i] +'' ;
}
return s;
}
script>
<div id="usuarios">
<ul id="ulUsers">
</ul>
</div>
O controle de lista de usuário é o mais importante da tela de Chat, pois ele controlará o tempo de vida de um usuário no Chat, ele controlará quem saiu e quem entrou do Chat.
Ele vai implementar um callback que fica a cada segundo enviando uma requisição ao servidor (via XMLHTTPRequest) e verificando se existem novos usuários ou se usuários saíram do Chat. Você pode configurar esse tempo para um valor maior. Agora abra o arquivo ListaUsuarios.ascx.cs e adicione o código da Listagem 12.
Listagem 12. Arquivo ListaUsuarios.ascx.cs
...
public partial class Controls_ListaUsuarios :
UserControl, ICallbackEventHandler
{
public string GetCallbackResult()
{
return GetUserListInCurrentChatRoom();
}
public void RaiseCallbackEvent(string eventArg)
{
RaiseCallbackEventInUserControl(eventArg);
}
protected void Page_Load(object sender, EventArgs e)
{
//se é a primeira vez que carrega a página
if (!IsPostBack)
{
//se o browser suportar callback via
//XMLHTTPRequest
if (Page.Request.Browser.SupportsCallback)
{
//Trata toda problemática da entrada do
//usuário na Sala
LogicaDeInclusaoDeUsuarioNoChat();
//Registra o callback para atualizar a
//Lista de usuários
GerarScriptCallBackListUsersInChat();
//Registra o callback para tirar o usuário
//do Chat
GerarScriptCallBackByByeUser();
}
}
}
private void LogicaDeInclusaoDeUsuarioNoChat()
{
//Verifica se o Request é válido e não está espiando
if (Session[ChatManager.SESSION_NICK_CHAT] != null
&& Request.QueryString["Espiar"] == null)
{
//string para script de possível erro
string script;
//se a sala não está cheia
if (ChatManager.CurrentChatRoom.ChatUserList.Count <
ChatManager.CurrentChatRoom.MaximoUsuarios)
{
//recupera apelido da sessão
string apelido = Session[
ChatManager.SESSION_NICK_CHAT].ToString();
//verifica se existe um usuário já com o
//mesmo nick
if (!ChatManager.
IsDuplicateNickInCurrentChatRoom(apelido))
{
//Acrescenta o novo usuário na sala
ChatManager.CurrentChatRoom.ChatUserList.Add(
ChatManager.RecuperarNovoChatUser(apelido));
//Coloca mensagem de usuário entrou na sala
string message = " entrou na Sala";
ChatManager.SendMessageInCurrentChatRoom(
ChatManager.getChatMessageforChatbyStrings(
ChatManager.CurrentChatRoom.CurrentChatUser,
message, false, string.Empty, false));
}
else
{
//Mostra ao usuário que a já existe outro
//usuário nessa sala com o nick que você
//está usando
script = "alert('Já existe outro usuário "+
"nesta sala com o Nick que você está "+
"usando, por Favor Tente outro');"+
"window.close();";
Page.ClientScript.RegisterStartupScript(
GetType(), "redirect", script, true);
}
}
else
{
//Mostra ao usuário que a sala está cheia
script = "alert('A Sala Já Está Cheia, "+
"tente novamente mais tarde');"+
"window.close();;";
Page.ClientScript.RegisterStartupScript(
GetType(), "redirect", script, true);
}
}
}
public void GerarScriptCallBackByByeUser()
{
//gera o script da função tira o usuário do chat
string ConteudoChamarByeByeUserinServer =
Page.ClientScript.GetCallbackEventReference(
this, "arg", "RetornoCallBackByByeUser",
"context");
string ScriptChamarByeByeUserinServer =
string.Format(
"function ChamarByeByeUserinServer(arg,context)"+
"{{;}}", ConteudoChamarByeByeUserinServer);
Page.ClientScript.RegisterClientScriptBlock(
GetType(), "ChamarByeByeUserinServerScript",
ScriptChamarByeByeUserinServer, true);
}
public void GerarScriptCallBackListUsersInChat()
{
//Gera o script da função que faz a requisição
//XMLHTTP e a registra na página, onde ela já está
//referenciada para lista de usuários
string ConteudoChamarServerListUser =
Page.ClientScript.GetCallbackEventReference(
this, "arg", "RetornoCallBackListUsers",
"context");
string ScriptChamarServerListUser =
string.Format(
"function ChamarServerListUser(arg,context)"+
"{{;}}", ConteudoChamarServerListUser);
Page.ClientScript.RegisterClientScriptBlock(
GetType(), "ChamarServerListUserScript",
ScriptChamarServerListUser, true);
}
public string VerificarExistenciaQueryStrings()
{
string str = string.Empty;
if (Request.QueryString["Espiar"] == null)
{
if (Session[ChatManager.SESSION_NICK_CHAT] ==
null)
{
str += "Por Favor, informe o seu Apelido. ";
}
if (Session[ChatManager.SESSION_ID_CHAT] ==
null)
{
str += "Por Favor, informe o Código da Sala ";
}
}
return str;
}
public void ExibirErroParaUsuarioEFecharJanela(
string mensagem)
{
Page.ClientScript.RegisterStartupScript(GetType(),
"erros", string.Format(
"alert('');history.back();", mensagem), true);
}
protected override void OnInit(EventArgs e)
{
//Verifica a Session, para evitar que o usuário
//digite manualmente o endereço do Chat no browser
string strMensagemDeFaltaDeQueryStrings =
VerificarExistenciaQueryStrings();
if (strMensagemDeFaltaDeQueryStrings !=
string.Empty)
{
ExibirErroParaUsuarioEFecharJanela(
strMensagemDeFaltaDeQueryStrings);
}
base.OnInit(e);
}
public string GetUserListInCurrentChatRoom()
{
return ChatManager.GetUserListInCurrentChatRoom(
true, false);
}
public void RaiseCallbackEventInUserControl(
string eventArg)
{
if (eventArg == "ByeBye" && Request.QueryString[
"Espiar"] == null)
{
//Coloca mensagem de usuário Saiu na sala
string message = " saiu da Sala";
ChatManager.SendMessageInCurrentChatRoom(
ChatManager.getChatMessageforChatbyStrings(
ChatManager.CurrentChatRoom.CurrentChatUser,
message, false, string.Empty, false));
//Remove usuários da Sala
string apelido = (Session[ChatManager.
SESSION_NICK_CHAT].ToString().Replace(
"'", ""));
ChatManager.
RemoveChatUserFromCurrentChatRoomByNick(
apelido);
Session[ChatManager.SESSION_ID_CHAT] = null;
Session[ChatManager.SESSION_NICK_CHAT] = null;
}
}
Note que o controle de mostrar usuários implementa a interface ICallbackEventHandler, que contém os métodos RaiseCallbackEvent e GetCallbackResult. O primeiro é executado imediatamente após a chamada feita via JavaScript, e recebe um parâmetro do JavaScript.
Utilizamos a string ByeBye para identificar se o usuário fechou a janela. Se não, atualizamos a lista, utilizando o GetCallbackResult que retorna uma string com a nova lista de usuários, utilizando o GetUserListInCurrentChatRoom da classe ChatManager.
Vamos acrescentar o controle que acabamos de criar na página Usuarios.aspx, semelhante a técnica utilizada anteriormente. Mas não esqueça de chamar a função Updater no onload do body:
Rode a aplicação novamente, e faça o mesmo processo (começando pela Default.aspx) e você verá uma tela parecida com a Figura 9.
Obs.: Como usamos uma variável de aplicação, ao fechar todas as janelas do browser, o conteúdo das mesmas ainda é mantido. Isso pode causar alguma confusão entre os usuários e as salas de bate-papo, usuários que você já pensou ter saído, e de repente aparecem novamente na lista.
Para evitar isso, em tempo de desenvolvimento, sempre pare o servidor Web do Visual Studio. Já em produção a solução é parar a aplicação no IIS e logo em seguida iniciar de novo, mas existe uma dica, crie um arquivo dentro da pasta Bin e depois delete-o. Isso fará a aplicação ser reiniciada, e os dados limpados.
Figura 9. Lista dos usuários da sala
O controle Lista de Mensagens
Vamos codificar agora o controle que mostra as mensagens do Chat. Esse controle se preocupa apenas com as mensagens, ele não precisa ter conhecimento se o usuário existe ou não.
No código a seguir guardo em uma variável JavaScript o ID da última mensagem que o usuário visualizou na última atualização, assim sempre garanto não trazer mensagens repetidas para o cliente. Abra o arquivo Mensagem.ascx e coloque o código da Listagem 13.
Listagem 13. Arquivo Mensagem.ascx
...
<div id="title">
<h1>Sala de Chat –
<span class="sala">ChatManager.CurrentChatRoom.Nome%>
</ span>
</h1>
<form name="frmChat" id="frmChat">
<p>
<input type="checkbox" checked="checked"
name="chkRolagem" id="chkRolagem" /> <label
id="rolagem"
for="chkRolagem">rolagem automáticalabel>
</p>
</form>
</div>
<div id="mensagens" >
<ul id="ulChat">
</ul>
</div>
<script type="text/javascript">
//variável que controla qual a última mensagem
//que o usuário recebeu
var LastMsgId = 0;
//função que atualiza a lista de mensagens a
//cada 1 segundo
function Updater()
{
//Chama a função criada pelo .NET passando a
//última mensagem que o usuário viu
ChamaServerChatMessageList(LastMsgId);
setTimeout("Updater()",1000);
}
//funcao callback que é executada depois que
//volta do servicor
function RetornoCallBackChatMessageList(
text, context)
{
//Cria um array pelo separador de Mensagens
var arrText = text.toString().split("|");
document.getElementById('ulChat').innerHTML +=
getHTMLToChatMessages(arrText);
if (document.getElementById('chkRolagem').checked)
{
document.getElementById('mensagens').scrollTop =
9000;
}
}
function getHTMLToChatMessages(arrText)
{
var textmsg = ''
for(var i=0; i < arrText.length;i++)
{
//Pega array com os campos separados da mensagem
var arr = arrText[i].split("§");
var message = '';
var nick_sender = '';
var date_msg = '';
//[codigo]§[data]§[autor]§[mensagem]|
message = arr[3];
nick_sender = arr[2];
date_msg = arr[1];
if (message!=null)
{
//atualiza o código da última mensagem que
//o usuário recebeu
LastMsgId = arr[0];
textmsg += '
(' + date_msg +
') ' + nick_sender + '' +
message + '';
}
}
return textmsg;
}
</script>
<script type="text/javascript"> //variável que controla qual a última mensagem
//que o usuário recebeu
var LastMsgId = 0;
//função que atualiza a lista de mensagens a
//cada 1 segundo
function Updater()
{
//Chama a função criada pelo .NET passando a
//última mensagem que o usuário viu
ChamaServerChatMessageList(LastMsgId);
setTimeout("Updater()",1000);
}
//funcão callback que é executada depois que
//volta do servicor
function RetornoCallBackChatMessageList(
text, context)
{
//Cria um array pelo separador de Mensagens
var arrText = text.toString().split("|");
document.getElementById('ulChat').innerHTML +=
getHTMLToChatMessages(arrText);
if (document.getElementById('chkRolagem').checked)
{
document.getElementById('mensagens').scrollTop =
9000;
}
}
function getHTMLToChatMessages(arrText)
{
var textmsg = ''
for(var i=0; i < arrText.length;i++)
{
//Pega array com os campos separados da mensagem
var arr = arrText[i].split("§");
var message = '';
var nick_sender = '';
var date_msg = '';
//[codigo]§[data]§[autor]§[mensagem]|
message = arr[3];
nick_sender = arr[2];
date_msg = arr[1];
if (message!=null)
{
//atualiza o código da última mensagem que
//o usuário recebeu
LastMsgId = arr[0];
textmsg += '
(' + date_msg +
') ' + nick_sender + '' +
message + '';
}
}
return textmsg;
}
</script>
Então agora, falta fazer o code behind do controle, acessando o arquivo Mensagem.ascx.cs e adicionando o código da Listagem 14.
Listagem 14. Arquivo Mensagem.ascx.cs
...
public partial class Controls_Mensagem : UserControl,
ICallbackEventHandler
{
//nick do usuário que está vendo a tela
private string NickViwerUser = "";
//código da última mensagem que o usuário viu
private string LastMsgIdViwedUser = "";
protected void Page_Load(object sender, EventArgs e)
{
//Se é a primeira vez que a página é carregada
if (!IsPostBack)
{
//se browser suportar callback via XMLHTTPRequest
if (Page.Request.Browser.SupportsCallback)
{
//gera script para callback
GerarScriptCallBackChamaServerChatMessageList();
}
}
}
private void GerarScriptCallBackChamaServerChatMessageList()
{
//Gera o script da função que faz a requisição
//XMLHTTP e a registra na página, onde ela já está
//referenciada para lista de Mensagems
string ConteudoChamaServerChatMessageList =
Page.ClientScript.GetCallbackEventReference(
this, "arg", "RetornoCallBackChatMessageList",
"context");
//monta a função para receber o conteúdo
string ScriptChamaServerChatMessageList =
string.Format(
"function ChamaServerChatMessageList(arg, "+
"context){{;}}",
ConteudoChamaServerChatMessageList);
//registra o script na página
Page.ClientScript.RegisterClientScriptBlock(
GetType(), "ChamarServerListUserScript",
ScriptChamaServerChatMessageList, true);
}
public string GetCallbackResult()
{
//Aqui retorno as mensagens que o usuário ainda não
//viu, com base na última mensagem que ele viu
return GetNewMessagesForUserInCuttentChatRoom(
NickViwerUser, LastMsgIdViwedUser);
}
private string GetNewMessagesForUserInCuttentChatRoom(
string apelido, string ultimaMensagem)
{
//Acessa a classe ChatManager e recupera a lista
return ChatManager.
GetNewMessagesForUserInCuttentChatRoom(
apelido, ultimaMensagem);
}
public void RaiseCallbackEvent(string eventArg)
{
//chama o método para tratar e passa o argumento,
//que é o código da última mensagem que o usuário viu
RaiseCallbackEventInUserControl(eventArg);
}
public void RaiseCallbackEventInUserControl(
string eventArg)
{
string apelido;
//essa está espiando
if (Request.QueryString["Espiar"] != null)
{
apelido = "espiao";
}
else
{
apelido = Session[
ChatManager.SESSION_NICK_CHAT].ToString();
}
NickViwerUser = apelido;
LastMsgIdViwedUser = eventArg;
}
}
Note também que o controle que mostra mensagens, implementa a interface ICallbackEventHandler e faz requisições ao servidor segundo a segundo para atualizar a lista mensagens.
Por efeitos de performance recuperamos apenas as novas mensagens, que o usuário ainda não viu e fazemos isso utilizando a variável de código já citada anteriormente.
Agora que criamos o controle, como fizemos anteriormente, vamos adicionar o controle na página. Abra o arquivo Mensagem.aspx e arraste o controle do Solution Explorer.
Um detalhe importante é a linha do body, onde temos o seguinte código onload="Updater(); que faz com que a função JavaScript seja chamada pela primeira vez. Rode novamente a aplicação e veja uma tela semelhante a Figura 10.
Figura 10. Visualizando as mensagens do Chat
O controle de envio de mensagens
O último controle é o de envio de mensagens, que realmente faz o que o Chat deve fazer. Então vamos abrir o arquivo Enviar.ascx e adicione o código da Listagem 15.
Listagem 15. Arquivo Enviar.ascx
...
<div id="form">
<form onsubmit="SendMesasge();return false; "
id="frmMensagem" name="frmMensagem" method="post"
action="#">
<ul>
<li>
<p><label for="txtMensagem">Insira aqui a sua mensagemlabel>p>
<input type="text" id="txtMensagem" name="txtMensagem"
class="floatLeft" />
<a href="javascript:SendMessage();" id="btnEnviar"
title="Enviar">Enviara>
<a href="javascript:parent.window.close();"
id="btnSair" title="Sair">Saira>
<div id="botoes">
<a href="javascript:parent.window.close();"
id="btnSair" title="Sair">a>
div>
li>
<li>
<label for="cboFalar">Falar Paralabel>
<select id="cboFalar" onchange="TratarCheck(this)"
onblur="FazerContinuar()" onfocus="FazerParar()"
name="cboFalar"
>
</select>
<input type="checkbox" id="chkReservado"
name="chkReservado"
/><label for="chkReservado" >reservadamentelabel>
</li>
</ul>
</form>
</div>
<script type="text/javascript">
//variável que controla quando atualizar a
//lista de usuários na combo
var PararDeAtualizarUsuarios = false;
//trata o comportamento da checkBox reservado,
//em função da Combo de usuários
function TratarCheck(combo)
{
//se selecionou todos, então desmarca o Reservado
if (combo.selectedIndex==0)
{
document.getElementById(
'chkReservado').checked = false;
}
}
//Pára Atualização de usuários
function FazerParar()
{
PararDeAtualizarUsuarios = true;
}
//Continua a monitorar a atualização de usuários
function FazerContinuar()
{
PararDeAtualizarUsuarios = false;
}
//Retorna o valor de uma QueryString
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i
{
var pair = vars[i].split("=");
if (pair[0] == variable)
{
return pair[1];
}
}
return '';
}
//Envia mensagem ao Servidor
function SendMessage()
{
//pega a mensagem digitada pelo usuário
//tirando os separadores § e | para evitar erros
var message = document.getElementById(
'txtMensagem').value.toString().replace(
"§","").replace("|","");
var destino_reservado = '';
var reservado = 'false';
//se digitou mensagem válida
if (message!='')
{
//se é reservado
if (document.getElementById(
'chkReservado').checked)
{
destino_reservado = document.getElementById(
'cboFalar').value;
//se reservado é valido
if (destino_reservado=='')
{
alert('Você não pode enviar mensagens '+
'reservadas para Todos');
document.getElementById(
'txtMensagem').value = '';
document.getElementById(
'txtMensagem').focus();
return;
}
reservado = 'true';
}
//Formata mensagem no formato
//[message]§[Reservado]§[Destino_reservado]
var mensagemformatada = message + '§' + reservado
+ '§' + destino_reservado;
ChamarServerSendMessage(mensagemformatada);
}
else
{
document.getElementById(
'txtMensagem').value = '';
document.getElementById('txtMensagem').focus();
}
}
//Função que é executada depois que volta do
//servidor, depois de enviar mensagem
function RetornoCallBackChamarServerSendMessage(
text, context)
{
document.getElementById('txtMensagem').value = '';
document.getElementById('txtMensagem').focus();
}
//Função que atualiza a lista de usuários
//segundo a segundo, se o usuário não está com o
//foco na combo
function Updater()
{
if (! PararDeAtualizarUsuarios)
{
ChamarServerListUser("Users");
}
setTimeout("Updater()",1000);
}
//Função que é executada depois que volta do
//servidor, e então atualiza a lista de usuários
function RetornoCallBackListUsers(text,context)
{
var arrText = text.toString().split("§");
var cboFalar = document.getElementById(
'cboFalar');
if (!document.getElementById(
'chkReservado').checked)
{
cboFalar.options.length = 0;
cboFalar.options[cboFalar.options.length] =
new Option('Todos','');
for(var i=0; i < arrText.length;i++)
{
//tira ele próprio da lista
if (arrText[i] != getQueryVariable('Nick'))
{
cboFalar.options[cboFalar.options.length] =
new Option(arrText[i],arrText[i]);
}
}
}
}
//Desabilita os botões se está espiando
function Espiar()
{
document.getElementById(
'txtMensagem').disabled = true;
document.getElementById(
'btnEnviar').disabled = true;
document.getElementById(
'emoticons').disabled = true;
document.getElementById(
'chkReservado').disabled = true;
document.getElementById(
'cboFalar').disabled = true;
}
</script>
O controle de Enviar Mensagem se preocupa apenas em enviar a mensagem para fila de mensagens no servidor. Utilizamos a mesma técnica de callback, para atualizar o DropDownList de usuários, para a funcionalidade de enviar reservadamente e para quando o usuário clicar em enviar mensagem, não seja necessário dar o postback na página.
Agora, falta apenas criar o code behind desse controle, então abra o arquivo Enviar.ascx.cs e adicione o código da Listagem 16.
Listagem 16. Arquivo Enviar.ascx.cs
...
public partial class Controls_Enviar : UserControl,
ICallbackEventHandler
{
protected override void OnLoad(EventArgs e)
{
//se é a primeira vez que carrega a página
if (!IsPostBack )
{
//se o browser suportar callback via
//XMLHTTPRequest
if (Page.Request.Browser.SupportsCallback)
{
//gera script de callback para listar
//usuários na Combo
GerarScriptCallBackListUsersInChat();
//gera script de callback para enviar
//novas mensagens
GerarScriptCallBackChamarServerSendMessage();
}
//está espiando, então chama a função Javascript
//Espiar();
if (Request.QueryString["Espiar"] != null)
{
Page.ClientScript.RegisterStartupScript(
GetType(), "ChamarServerSendMessageScript",
"Espiar()", true);
}
}
base.OnLoad(e);
}
public void GerarScriptCallBackChamarServerSendMessage()
{
//Gera o script da função que faz a requisição
//XMLHTTP e a registra na página, para envio de
//novas mensagens
string ConteudoChamarServerSendMessage =
Page.ClientScript.GetCallbackEventReference(this,
"arg", "RetornoCallBackChamarServerSendMessage",
"context");
string ScriptChamarServerSendMessage =
string.Format(
"function ChamarServerSendMessage(arg,context)"+
"{{;}}", ConteudoChamarServerSendMessage);
Page.ClientScript.RegisterClientScriptBlock(
GetType(), "ChamarServerSendMessageScript",
ScriptChamarServerSendMessage, true);
}
public void GerarScriptCallBackListUsersInChat()
{
//Gera o script da função que faz a requisição
//XMLHTTP e a registra na página, onde ela já
//está referenciada para lista de usuários
string ConteudoChamarServerListUser =
Page.ClientScript.GetCallbackEventReference(this,
"arg", "RetornoCallBackListUsers", "context");
string ScriptChamarServerListUser = string.Format(
"function ChamarServerListUser(arg,context)"+
"{{;}}", ConteudoChamarServerListUser);
Page.ClientScript.RegisterClientScriptBlock(
GetType(), "ChamarServerListUserScript",
ScriptChamarServerListUser, true);
}
public string GetCallbackResult()
{
//Retorna a lista de usuários
//com o HTML DECODIFICADO
return ChatManager.GetUserListInCurrentChatRoom(
false, true);
}
public void RaiseCallbackEvent(string eventArg)
{
//se o usuário enviou uma mensagem
if (eventArg.IndexOf("§") > 0)
{
ChatManager.SendMessageInCurrentChatRoom(
ChatManager.getChatMessageFromSendMessageFormat(
eventArg));
}
}
}
O controle de enviar pára de fazer requisições se o usuário estiver com o foco no DropDownList de usuários, para não causar um mau comportamento do controle ficar recarregando sempre.
Bem, depois de fazer esse último controle, agora só falta arrastá-lo para Enviar.aspx e chamar Updater no onload do body (conforme fizemos anteriormente). Quando rodar, o programa estará mais ou menos como à Figura 11.
Figura 11. Aplicação final em execução
Finalizamos o Chat, mas você ainda pode colocar um CSS para melhorar o layout.
A novidade é o uso do recurso de callback do ASP.NET 2.0 que permite controlar os Requests sem recarregar a página, com uma quantidade de código considerável, se comparado com o antigo ATLAS e agora ASP.NET AJAX, porém tempos atrás isso também seria uma explosão inovadora para os desenvolvedores.
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo