Tag Archives: Ajax

ASP.NET – How to call a server side method through Ajax in WebForms

[TRANSLATING – If you are reading the text below in portuguese, it’s because I’m lazy e I still not finished the translation. Keep calm, drink a coffee and come back a few minutes, or hours, or days…]

PageMethods in ASP.NET

First, a bit of history. If you want to read the code now, click >here!

Faz tempo que queria publicar este macete. Gosto de chamá-lo assim pois foge um pouco da linha de pensamento de quem programa há muito tempo usando WebForms. Chamadas AJAX tornaram-se algo tão natural no mundo web que quase não se pensa em sistema sem pelo menos uma chamada dessas. E, convenhamos, não é algo que o WebForms faz muito bem.

É claro que sempre tivemos o AJAX Control Toolkit (ACT) em mãos, mas assim como todo o “disfarce” que o WebForms faz sobre o protocolo HTTP, o ACT não faz diferente.

Mas e se for preciso fazer uma simples chamada a um método, mesmo que isso seja um retorno de um array de strings, ou um JSON, como fica? Há formas de fazê-lo se você pensar em um Handler puro (ASHX), mas você teria que re-estruturar toda sua aplicação só por conta disso. Mas calma, existe um jeito “bonito” de fazer isso. PageMethods!

PageMethods

Até agora não consegui encontrar uma explicação boa sobre o que são PageMethods. O que entendi foi, PageMethods são uma forma de expor funções server side da sua página ASP.NET WebForms para ser chamada por Javascript. Um exemplo é a melhor maneira de entender.

O que é preciso para usar PageMethods?

Primeiro, uma página ASPX. A página ou sua MasterPage deve possuir um controle ScripManager e nele, a propriedade EnablePageMethods definida para true.

<asp:ScriptManager ID="ScriptManager1"  runat="server" EnablePageMethods="true">
       <Scripts>
       </Scripts>
</asp:ScriptManager>

Se o ScriptManager já existir, basta acrescentar a propriedade, sem precisar mexer em referências que já existam.

Agora, a função que será chamada do lado server side. Como esta função trafegará por HTTP, o retorno desta precisa ser um tipo serializável, ou seja, que tenha uma representação em texto. No caso do exemplo, vamos retornar uma string simples. Crie a seguinte função no código da sua página:

[WebMethod]
// Get session state value.
public static string GetSessionValue(string key)
{
   return (string)HttpContext.Current.Session[key];
}
 
[WebMethod]
// Set session state value.
public static string SetSessionValue(string key, string value)
{
     HttpContext.Current.Session[key] = value;
     return (string)HttpContext.Current.Session[key];
}

Como é possível notar, o exemplo “brinca” com variáveis de servidor para provar que o trabalho está ocorrendo nele, e não no cliente. Os detalhes importantes são:

  • a função precisa retornar um tipo serializável
  • a função precisa ser static
  • a função precisa ser marcada com o atributo [WebMethod] do namespace System.Web.Services.

Por fim, o Javascript que vai chamar as funções. O código é auto explicativo. O importante a saber é que as funções criadas no código servidor serão expostas no Javascript através do objeto/function PageMethods. Assim, a função GetSessionValues criada no servidor será chamada no javascript com a sintaxe “PageMethods.GetSessionValues(parâmetros)”.

Além dos parâmetros da própria função, o PageMethods insere dos argumentos em cada uma delas, sendo eles duas funções que devem ser criadas na página, OnSucceeded e OnFailed. A primeira é invocada quando a chamada AJAX ocorre sem erros. A segunda serve exatamente para tratar erros vindos desta chamada. Veja mais detalhes no código:

// Initializes global variables and session state.
function pageLoad()
{
    PageMethods.SetSessionValue("SessionValue", Date(), 
        OnSucceeded, OnFailed);
}
 
// Gets the session state value.
function GetSessionValue(key) 
{
    PageMethods.GetSessionValue(key, OnSucceeded, OnFailed);
}
 
//Sets the session state value.
function SetSessionValue(key, value) 
{
    PageMethods.SetSessionValue(key, value, OnSucceeded, OnFailed);
}
 
// Callback function invoked on successful 
// completion of the page method.
function OnSucceeded(result, userContext, methodName) 
{
    if (methodName == "GetSessionValue")
    {
        alert("Current session state value: " + result;
    }
}
 
// Callback function invoked on failure 
// of the page method.
function OnFailed(error, userContext, methodName) 
{
    if(error !== null) 
    {
        alert( "An error occurred: " + error.get_message());
    }
}

O código pode ser colocado diretamente na página ou num arquivo Javascript separado.

Voilá! Temos AJAX de verdade do WebForms! Pelo menos quase isso.

Referências

http://www.asp.net/ajax/documentation/live/ViewSample.aspx?sref=Sys.Net.PageMethod/cs/PageMethod.aspx

ASP.NET – Bug no controle CalendarExtender/MaskedEditExtender do AJAX Control Toolkit

Dependendo da versão do AjaxControlToolkit utilizada, é preciso atentar a alguns bugs que ocorrem em alguns dos controles que o pacote disponibiliza.

Neste caso, o erro com que me deparei foi o seguinte, assumindo que o Depurador de Javascript do Internet Explorer esteja ativado:

Erro em tempo de execução do Microsoft JScript: ‘null’ é nulo ou não é um objeto

Ao enviar a execução para o Visual Studio, o erro acontece na seguinte execução:

var oldElement = newElement.cloneNode(true);

O erro ocorre numa combinação do uso dos controles CalendarExtender e MaskedEditExtender. O erro ocorre especificamente na função _switchMonth. Aparentemente, algumas data informadas no controle com MaskedEditExtender sem que o controle CalendarExtender tenha sido alguma vez chamado, e consequentemente criado, o bug é gerado. Um exemplo de data que gera o bug é 01/01/0002, dentre outras possíveis.

O erro ocorre por conta do seguinte código.

var newElement = this._modes[this._mode]; // new Element is NULL
var oldElement = newElement.cloneNode(true); // CRASH BOOM BANG.

A partir do Release 10920 do AjaxControlToolkit, o problema é resolvido. Porém, caso tenha alguma dificuldade com atualização de componentes ou se precisou promover alterações no toolkit que resultou em algo personalizado, o código que corrige o erro é:

this._isAnimating = true;

// Added by Deepak Chawla 23 July 2007 BUG: When the mask edit auto complete calls the calendars delegate body might not have been built
if (this._modes[this._mode] == null) // NEW CODE
this._buildBody(); // NEW CODE

var newElement = this._modes[this._mode];
var oldElement = newElement.cloneNode(true);

Referências:

http://www.codeplex.com/AjaxControlToolkit/WorkItem/View.aspx?WorkItemId=11121

http://www.codeplex.com/AjaxControlToolkit/Release/ProjectReleases.aspx?ReleaseId=4941

Tomás

ASP.NET – Registrando scripts em páginas com UpdatePanel

Registrar javascripts dinâmicos em páginas ASP.NET nunca foi algo muito prazerozo, mas alguns métodos oferecidos pela Engine como o Page.RegisterClientScriptBlock, que “cospe” um bloco de scripts dentro de uma página.

Isso resolvia alguns casos simples como mostrar uma mensagem num alert(), ou executar um função javascript qualquer já existente na página. Porém, com o novo cenário de aplicações Web, recheados de código Ajax, principalmente fruto do AjaxControlToolKit e derivados, a técnica não funciona mais pois a página não é mais carregada em sua totalidade, gerando o famoso postback.

A solução para isso foi a criação do método RegisterClientScriptBlock dentro da classe ScriptManager, que especificamente trata de registrar e executar um script em páginas que utilizem o controle UpdatePanel.

Um exemplo de chamada que registra um alert dentro um UpdatePanel seria:

ScriptManager.RegisterClientScriptBlock(this, this.GetType(), “scriptAjax”, “alert(’Oi’);”, true);

Detalhes a respeito do método pode ser visto no link abaixo:

http://msdn.microsoft.com/en-us/library/system.web.ui.scriptmanager.registerclientscriptblock.aspx

Abraços

Tomás