domingo, 31 de mayo de 2015

Postback en ASP.Net desde el cliente javascript

Cuando inicie en el desarrollo de aplicaciones web dinámicas, inicie con ASP.Net y me gusto realmente, creo que fue más por el entorno de desarrollo, ya que para ser franco el mejor debbuger que he usado ha sido el de Visual Studio, algún día escribiré sobre mis inicios en el desarrollo web jeje; cuando estaba aprendiendo ASP.Net en ese entonces lo primero que hay que tener claro es el concepto de postback, para decirlo de una manera simplista digamos que es el enlace entre el cliente y el servidor cuando se genera un evento en alguno de sus controles desde el lado del cliente y de esta forma enviar la página nuevamente al cliente con las modificaciones respectivas, claro que hay que agregarle más mecanismos como el de mantener la información entre los llamados y más (perdón desarrolladores de .Net por explicar así de simple, ja escribir es tedioso a veces).

Cuando ya se ha desarrollan algunas páginas, siempre entra la duda de cómo hacer un llamado a los métodos del code behind desde el lado del cliente o mejor desde javascript, es algo lógico cuando se inicia, el motivo al escribir este post fue eso, una pregunta, una pregunta que nos formular los nuevos desarrolladores y con esto no quiero decir que lo sé todo, es más siento que conozco muy poco de ASP.Net a pesar de llevar 6 años (fecha actual 2015) desarrollando en esta tecnología, pero como uno de mis objetivos es ayudar pues escribiré sobre la cuestión en marcha.

ASP.Net provee de un forma de realizar el postback desde el cliente, es algo que nació con ASP.Net debido a cómo funcionaba ASP, en si es una mejora que implementaron para su tecnología pero como todo, eso depende desde el punto de vista en el que se mire.

Esta forma de realizar un postback, se logra gracias a un método de javascript, este es el __dopostbak(), y su implementación es la siguiente:

       function __doPostBack(eventTarget, eventArgument) {
            if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
                theForm.__EVENTTARGET.value = eventTarget;
                theForm.__EVENTARGUMENT.value = eventArgument;
                theForm.submit();
            }
        }

Es una función sencilla pero poderosa, así deben ser las cosas; esta función tiene dos parámetros de entrada, eventTarget es el identificador del control que causa el postback y eventArgument es información adicional asociada al control y/o acción que se desea realizar, además de esto la implementación de esta técnica tiene dos controles HTML que son los siguientes.

<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />

Bueno ya te puedes imaginar para que se definen, correcto ya lo tienes, es para que el valor se pueda acceder desde el code behind de nuestra página osea para identificar qué control ha realizado el postback en simples palabras; esto se realiza automáticamente en ASP.Net para la gran mayoría de los controles. Para tener en cuenta, según la definición que se encuentra en MSDN, en ASP.Net hay dos controles que realizan el postback digamos que de forma nativa (Button y ImageButton), los demás controles usan el método __dopostback y los input ocultos para tal propósito al igual que vamos hacer nosotros para dar una solución posible a la cuestión en marcha, digo posible porque pueden existir otras soluciones.

Listo, centremonos en el caso, necesitamos llamar a un método creado en el code behind desde el cliente para ejecutar alguna tarea en específico  (bueno desde una función javascript desde el cliente, hay que especificar ahora, porque ya se usa javascript desde el lado del servidor), para que este truco funciones (si truco, debe existir una forma más elegante e ingenieril :/ ), se necesita que nuestra página tenga algún control de servidor y que no sea ni el Button o ImageButton, y ¿Por qué será?, si señor, correcto es por eso, que atentos están.

Para realizar esto crearemos un proyecto web en visual studio express (voy a usar el 2013), lo nombrare Demos para ejemplos futuros, que sea limpio (Empty) y seleccionare tecnologías Web From, MVC, Web API, osea todo lo que me puede ofrecer, como dicen por ahí “pensando en el futuro”.


Listo, ahora se agregara un formulario nombrado DoPostback, la idea es simple agregar un control de servidor (TextBox) y ponemos el atributo AutoPostBack en true, se creara un elemento div con su evento onclick que llamara a una función javascript en la cual realizaremos el llamado a la función en el code behind, un ejemplo sencillo pero es para mostrar la idea a la cuestión. Ahora sí, manos a la obra.

El Código HTML (resumido).

<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Demo dopostback</title>
    <script type="text/javascript">
        function LlamarMetodoCodeBehind() {
            var accion = document.getElementById('txtEventArgument').value;

            if (accion === 'servidor1') {               
                __doPostBack('divCliente', 'Evento1');
            }
            else {
                __doPostBack('divCliente', 'Evento2');
            }
        }
    </script>
</head>
<body>
    <form id="frmDopostback" runat="server">
        <header>
            <h1>Demo DoPostback</h1>
        </header>
        <div>
            <div>
                <asp:TextBox ID="txtEventArgument" runat="server" AutoPostBack="True"></asp:TextBox>
            </div>
            <br />
            <div id="divCliente" style="width:150px; height:20px; background-color:ButtonShadow" onclick="LlamarMetodoCodeBehind();">
                Llamar Servidor
            </div>
        </div>
    </form>
</body>
</html>

Aquí se puede observar tanto la función javascript como los elementos html que se definieron para el demo, valga aclarar que el control TextBox (txtEventArgument) tiene activo el AutoPostBack con el fin de que se agrega el método __doPostBack() en el cliente, si no, en la función javascript se generaría un error de método no implementado.

Code Behind (Resumido)

              protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack)
            {
                string idControl = Request.Params.Get("__EVENTTARGET");
                string argumento = Request.Params.Get("__EVENTARGUMENT");

                string script = "";

                if (idControl.Equals("divCliente"))
                {
                    if (argumento.Equals("Evento1"))
                    {
                        script = string.Format("", txtEventArgument.Text, argumento);
                        mostrarMensaje(script);
                    }
                    else
                    {
                        script = string.Format("", argumento);
                        mostrarMensaje(script);
                    }
                }
            }
        }

        private void mostrarMensaje(string script){
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "postback", script);
        }


Aquí tenemos una especie de filtro en el evento de página Page_Load, capturamos el identificador del control que realizo el llamado a __doPostBack(), el cual definimos en su parámetro de entrada, y capturamos el argumento que también lo pasamos como parámetro, con esto ya podemos comparar según el retorno de estos valores que hacer, aquí simplemente verificamos que el control que llama es divCliente, si es así analiza el argumento, si el argumento es “servidor1” realiza el llamado al método mostrarMensaje para imprimir un alert con un mensaje en específico, aquí se puede ver que el control TextBox cuando se digita algo en él y pierde el foco, el argumento __EVENTTARGET tiene el id del control (usa el debbuger de .Net).

Teniendo en cuenta lo anterior podemos imaginar que esta forma de usar el método __doPostBack() que ofrece ASP.Net nos puede ayudar en muchas cosas como por ejemplo.
  • Crear controles de usuario con eventos programados por nosotros.
  • Realizar un llamado al code behind para que realice alguna tarea en específico.
  • Darle capacidad a controles simples html para que sean analizados en el code behind y se realize algo en específico.
  • Etc.

Por ejemplo, yo uso normalmente el __doPostBack cuando se abre una ventana modal y al cerrarla se retorna algún tipo de resulta, dependiendo del resultado realizo un llamado a algún método del code behind en específico, realmente me ha ayudado mucho.

Como siempre digo lo que se presenta aquí no es una solución elegante o regla a usar, tiene muchas falencias de una buena programación, pero para eso estamos todos, sería bueno que el que tenga el conocimiento comparta en qué casos se debe usar y más como es la forma correcta de usarla, hay desarrolladores que recomiendan que no se debe usar directamente el nombre de la función __doPostBack en el código, que se debería hacer una referencia a ella por si de pronto a Microsoft le da por cambiar el nombre o su definición de parámetros quede fácil realizar dicho cambio en la aplicación.

Dejo el link en GitHub del proyecto y por favor si lo usan no modifiquen la raíz creen una rama, para que el ejemplo inicial quede para todos.

No siendo más, me despido, espero que sea de utilidad y por favor comenten, ya sea malo o bueno pero siempre a nivel constructivo.

happy coding :).