Enviando mensajes a grupos en SignalR ASP.NET

SignalR provee una capa de abstracción sobre algunos de los transportes requeridos para hacer aplicaciones de tiempo real. Estas aplicaciones empiezan directamente sobre HTTP pero en caso de que se tenga soporte para Web Sockets, dicha conexión será promovida a que use Web Sockets.

Todas las conexiones son administradas por SignalR y permite transmitir los cambios a todos los clientes conectados como si fuese una sala de chat o en caso de que sea necesario podemos notificar a un cliente específico.

Avanzando un poco mas del pequeño tutorial de chat que nos ofrece Microsoft y siguiendo un poco con la linea de variablenotfound con respecto a los Hubs vamos a mostrar un pequeño ejemplo para enviarle mensajes a diferentes grupos de usuarios.

Primero bajamos SignalR desde nuget
foto1

Creamos una carpeta llamada Hub y creamos la clase Hub
foto2
 

 

 

 

 

Apartir de SignalR 2.0 para iniciar el servicio necesitamos una Clase OWIN:

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(EF_SignalR.Startup))]

namespace EF_SignalR
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
} 

 

y el código:

   [HubName("MensajeroHub")]
    public class MensajeroHub : Microsoft.AspNet.SignalR.Hub
    {

        //funcion para agregarlo al grupete
        public void AgregarGrupo(int iddelGrupo)
        {
            Groups.Add(Context.ConnectionId, iddelGrupo.ToString());
        }


        public void EnvioMensajeGrupo(string groupName, string message,string tipo)
        {
            Clients.Group(groupName).CallBackMsj(string.Format("Grupo {0}: {1}", groupName, message), tipo);
        }
     
    }

Este es el nombre con que vamos a referenciar nuestro hub en el cliente

 [HubName("MensajeroHub")]

Con esta función vamos a ir agregando a los usuarios a nuestros grupos

public void AgregarGrupo(int iddelGrupo)
        {
            Groups.Add(Context.ConnectionId, iddelGrupo.ToString());
        }

Y con esta función vamos a hacer el push del servidor al cliente

public void EnvioMensajeGrupo(string groupName, string message,string tipo)
        {
            Clients.Group(groupName).CallBackMsj(string.Format("Grupo {0}: {1}", groupName, message), tipo);
        }

Para consumir nuestro Servicio desde el cliente, primero dibujamos un poco la página:


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-1.8.2.min.js"></script>
    <script src="Scripts/jquery.signalR-2.2.0.js"></script>
    <script src="Scripts/notify.js"></script>
    <script src="Scripts/GsSignalR.js"></script>
    <script src="signalr/hubs"></script>
    
</head>
<body>


<form id="form1" runat="server">


<div>


        
        <asp:CheckBox Text="Grupo 1" id="grupo1" runat="server" />
        <asp:CheckBox Text="Grupo 2" id="grupo2" runat="server" />
        
        <select id="combo">
<option value="warn">Warn</option>
<option value="info">Info</option>
<option value="error">Error</option>
<option value="sucess">Sucess</option>
        </select>
        
        
        <asp:TextBox runat="server" id="txtgrupo1" placeholder="Texto para grupo 1" /> 
        <input type="button" name="btnGrupo1" value="Enviar p/grupo1" id="btnGrupo1" /> 
        
        <asp:TextBox runat="server" id="txtgrupo2" placeholder="Texto para grupo 2" /> 
        <input type="button" name="btnGrupo2" value="Enviar p/grupo2" id="btnGrupo2" />


    </div>


    </form>


</body>
</html>

Cabe mencionar aquí la llamada al Hub autogenerador por SingalR, sin eso no vivimos

    <script src="signalr/hubs"></script>

y el script que nos gestiona el servicio esta acá


$(function () {

    /*CONFIGURACIONES INICIALES  */
    console.log("Inicio del servicio");
    myHub = $.connection.MensajeroHub;
        
    $.connection.hub.start().done(function () {
        console.log("conecta ok");
    })
   .fail(function () {
       console.log("fallo");
   });
    /*CONFIGURACIONES INICIALES  */

       //PUSH DEL SERVIDOR
    myHub.client.callBackMsj = function (message,tipo) {
        console.log(message + " " + tipo);
        $.notify(message,
            {
                position: 'top left',
                className: tipo
            }
         );
    };

   //LLAMADAS AL SERVIDOR***************************
    $("#grupo1").click(function () {
        console.log("agregar a grupo 1");
        //Esta funcion usa CamelCase osea que tiene que ir en minuscula
        myHub.server.agregarGrupo("1");
    });

    $("#grupo2").click(function () {
        console.log("agregar a grupo 2");
        myHub.server.agregarGrupo("2");
    });


    $("#btnGrupo1").click(function () {
        myHub.server.envioMensajeGrupo("1", $("#txtgrupo1").val(), $("#combo").val());
    });

    $("#btnGrupo2").click(function () {
        myHub.server.envioMensajeGrupo("2", $("#txtgrupo2").val(), $("#combo").val());
    });
    //LLAMADAS AL SERVIDOR***************************
});

Como se puede ver en las primeras lineas utilizo el nombre que especifico para el Hub con el tag hubName, aunque podría haber dejado el nombre de la clase, y luego inicio el servicio. Una vez hecho esto, la conexión entre cliente y servidor ya esta establecida.

myHub = $.connection.MensajeroHub;
    $.connection.hub.start().done(function () {
        console.log("conecta ok");
    })
   .fail(function () {
       console.log("fallo");
   });

Cuando el cliente toca uno de los checkbox simplemente realizamos esto para poder agregarlo a un grupo

  //LLAMADAS AL SERVIDOR***************************
    $("#grupo1").click(function () {
        console.log("agregar a grupo 1");
        //Esta funcion usa CamelCase osea que tiene que ir en minuscula
        myHub.server.agregarGrupo("1");
    });

Esto en el servidor

   //funcion para agregarlo al grupete
        public void AgregarGrupo(int iddelGrupo)
        {
            Groups.Add(Context.ConnectionId, iddelGrupo.ToString());
        }

Una vez diferenciados los grupos solamente tenemos que enviarle los mensajes al nombre del grupo correspondiente y SignalR hace el resto por nosotros.

 public void EnvioMensajeGrupo(string groupName, string message,string tipo)
        {
            Clients.Group(groupName).CallBackMsj(string.Format("Grupo {0}: {1}", groupName, message), tipo);
        }

En el cliente usamos notify para que sea mas lindo el mensaje. Notese que para recibir el push el método es Camel Case

  //PUSH DEL SERVIDOR
    myHub.client.callBackMsj = function (message,tipo) {
        console.log(message + " " + tipo);
        $.notify(message,
            {
                position: 'top left',
                className: tipo
            }
         );
    };

 

La interface que hice es bien simple y sirve para identificar a que grupo pertenece un usuario y poder enviarle mensajes. Y mas abajo muestro la misma interface con 2 browser abiertos para ver la diferencia.
foto3

 

 

foto4
 
 
 
 

LINK:
GoogleDrive

Anuncios

Usando Grid.MVC en VS2012

En una entrada dedicada a bootstrap hablé muy por arriba de este popular paquete. En esta oportunidad quiero dedicarle un post entero para comentar su funcionamiento y la manera que creo mas optima para usarlo. Pueden visitar el proyecto original.

Para descargarlo a nuestro proyecto lo buscamos en el MUG

foto1

foto3

Estilo y diseño

Por defecto vamos a utilizar el css que nos sugiere la misma librería


	&amp;lt;link href="@Url.Content('~/Content/bootstrap.min.css')"                rel="stylesheet" type="text/css" /&amp;gt;

Bindeo simple

Y nos metemos de lleno en el bindeo. Es realmente muy sencillo y rápido. En mi proyecto, para no hacerlo mas complicado, vamos a generar una Lista de la clase Cliente (List<Cliente>), la llenamos en el Controller y se la enviamos al View.

 public class TestController : Controller
    {
        //Genero una lista para bindearla al Grid
        private readonly List<Cliente> clients = new List<Cliente>()
        {
            new Cliente { Id = 1, Nombre = "Julio Avellaneda", Email = "julito_gtu@hotmail.com" },
            new Cliente { Id = 2, Nombre = "Juan Torres", Email = "jtorres@hotmail.com" },
            new Cliente { Id = 3, Nombre = "Oscar Camacho", Email = "oscar@hotmail.com" },
            new Cliente { Id = 4, Nombre = "Gina Urrego", Email = "ginna@hotmail.com" },
            new Cliente { Id = 5, Nombre = "Nathalia Ramirez", Email = "natha@hotmail.com" },
            new Cliente { Id = 6, Nombre = "Raul Rodriguez", Email = "rodriguez.raul@hotmail.com" },
            new Cliente { Id = 7, Nombre = "Johana Espitia", Email = "johana_espitia@hotmail.com" }
         };

        public ActionResult TestGridView()
        {
            //Envio la lista al cliente
            return View(clients);
        }

    }

y en primera instancia el View es lo mas simple posible, para luego hacerlo lo mas flexible que podamos.

&amp;lt;div style="width:700px;"&amp;gt;
        @Html.Grid(Model).Columns(columns =&amp;gt;
                    {
                        //columns.Add().RenderValueAs();

                        //columna 1
                        columns.Add(c =&amp;gt; c.Id, true).Titled("Cliente ID");

                        //columna 2
                        columns.Add(c =&amp;gt; c.Nombre).Titled("Name")
                            .Sanitized(false)
                            .Encoded(false);

                        //columna 3
                        columns.Add(c =&amp;gt; c.Email).Titled("Email");
                    }).WithPaging(3).Sortable(true)&amp;lt;/div&amp;gt;

foto4

 

Propiedades importantes

  • La propiedad WithPaging es la que me permite indicarle cuantas filas puede tener.
  • La propiedad Titled que me permite darle un nombre a la columna.
  • La propiedad para generar Columnas ocultas que me permite hacerla invisible con el “True”:
     columns.Add(c => c.Id, true).Titled("Cliente ID");
    
  • La propiedad sorteable para realizar ordenamientos ascendentes o descendentes.
    columns.Add(c => c.Nombre).Titled("Name").Sortable(true);
    
    //o si quiero especificar el orden
    columns.Add(c => c.Nombre).Titled("Name").Sortable(true).SortInitialDirection(GridSortDirection.Descending);
    

La propiedad RenderValueAs

En esta propiedad vamos a detallarla un poco mas porque nos permite realizar acciones muy amplias.

Supongamos que yo quiero poner un link en mi grilla que me permita realizar alguna acción( ir a MiController y ejecutar mi método “ActionResultfunction”, entonces puedo usar esta propiedad para renderearlo de la siguiente manera, en la columna del nombre:


columns.Add()
   .Encoded(false)
   .Sanitized(false)
   .RenderValueAs(o => Html.ActionLink(((string)"Eliminar"),
   "EliminarGrid",  //Action Result
   "Persona",  // Controller
   new { id = (int)o.Id }, //Parametros
   null //attributes...nulo
   ).ToHtmlString());

La grilla nos quedará formada de la siguiente manera con un link que irá hacia MiController y el actionResult ActionResultfunction

foto6

Ahora supongamos que quiero enviarle parámetros:

Y nuestro PersonaController nos queda de una manera muy simple:

    public class PersonaController : Controller
    {
 public ActionResult EliminarGrid(int id)
        {
            List<Cliente> clients = (List<Cliente>)Session["Lista"];

            foreach (Cliente element in clients)
            {
                if (id == element.Id)
                {
                    clients.Remove(element);
                    break;
                }
            }

            Session["Lista"] = clients;
            return RedirectToAction("TestGridView", "Test");
        }      

    }

Agregar un nuevo Row
Si uno agrega una grilla, una de las cosas mas básicas es poder agregar nuevas filas a la misma.

<table id="footer">
<tr class="group-footer">
<td colspan="2">
                        @if (Model.Count()==0)
                        {
                          <span class="label label-alert"@Html.ActionLink(((string)"Nueva"),
                                                                "Nueva",  //Action Result
                                                                "Persona",  // Controller
                                                                null, //Parametros
                                                                null //attributes...nulo
                                                                )                         </span>
                        }else{
                          <span class="label label-info"@Html.ActionLink(((string)"Agregar"),
                                                                    "Nueva",  //Action Result
                                                                    "Persona",  // Controller, se agrega sin usar la palabra "Controller"
                                                                    null, //Parametros
                                                                    null //attributes...nulo
                                                                    )
                          </span>
                        }<lt;/>
</tr>
<table>

De esta manera agregamos el link para poder ingresar nuevos valores a la grilla.
Esto se va a administrar desde PersonaController y se visualizará en la view Persona/Nueva.

@{
    ViewBag.Title = "Nueva Persona";
}
<h2>Nueva</h2>

@using (Html.BeginForm("Alta","Persona"))
{
<table style="width: 100%;">
<tr>
<td>Nombre</td>
<td>@Html.TextBox("txtNombre")</td>
</tr>
</table>

<input id="btnGuardar" type="submit" value="Guardar" />
    /*vuelve al menu anterior*/
<input type="button" value="Volver"             onclick="@("window.location.href='" + @Url.Action("TestGridView", "Test") + "'");" />
}

Los 2 métodos del Controller permiten agregar y eliminar un valor de la grilla y siempre retornan a la misma view: TestGridView:

        [HttpPost]
        public ActionResult Alta(string txtID, string txtNombre)
        {
            List<Cliente> clients = (List<Cliente>)Session["Lista"];
            clients.Add(new Cliente { Id = clients.Count + 1, Nombre = txtNombre, Email = "" });

            Session["Lista"] = clients;
            return RedirectToAction("TestGridView", "Test");
        }

        public ActionResult EliminarGrid(int id)
        {
            List<Cliente> clients = (List<Cliente>)Session["Lista"];

            foreach (Cliente element in clients)
            {
                if (id == element.Id)
                {
                    clients.Remove(element);
                    break;
                }
            }

            Session["Lista"] = clients;
            return RedirectToAction("TestGridView", "Test");
        }

Dejo el ejemplo como siempre. Espero que les sirva el ejemplo como una introducción.
Saludos

LINK:
GoogleDrive

PASSWORD:
https://trytocatch.wordpress.com/

Encriptar Querystring en ASP.NET

Hoy quiero publicar un pequeño proyecto que permita agregar de manera transparente en sus sitios una forma de encriptar el contenido del QueryString en aplicaciones Web con ASP.NET. Vamos a utilizar el Visual Studio 2012 y vamos a desarrollar el código en C#. En esta primera publicación quiero mostrarlo en sin utilizar el paradigma de MVC, pero también quiero aplicar la misma idea para poder encriptar con MVC.

Normalmente nuestras aplicaciones tendrían este QueryString:
foto 1

Sigue leyendo

Recorrer todos los controles de una página ASP.NET

Buscando la manera de encontrar una serie de Gridview en una página es que llegué a crear esta función. Que es básicamente recorrer los controles de manera recursiva porque un control puede contener a otros controles en su interior. En mi caso era solamente ocultar el FooterRow de las Grillas (Gridview) y tengo en cuenta que cuando la grilla no tiene rows la oculto directamente.

El código en VB:

        For Each ctrl As Control In Page.Controls
          Dim gv As GridView = TryCast(ctrl, GridView)
          If gv Is Nothing Then
               RecorrerColeccion(ctrl)
          Else
              If gv.Rows.Count > 0 Then
                 gv.FooterRow.Visible = False
               Else
                 gv.Visible = False
              End If
          End If
       Next

Acá esta la función recursiva RecorrerColeccion:

 Sub RecorrerColeccion(ByVal parentCtrl As Control)
          For Each pctrl As Control In parentCtrl.Controls
              Dim gv As GridView = TryCast(pctrl, GridView)
              If gv Is Nothing Then
                  RecorrerColeccion(pctrl)
              Else
                  If gv.Rows.Count > 0 Then
                      gv.FooterRow.Visible = False
                  Else
                      gv.Visible = False
                  End If
              End If
          Next
      End Sub

Y acá esta el mismo ejemplo en C#:

 foreach (Control ctrl in Page.Controls) {
      GridView gv = ctrl as GridView;
      if (gv == null) {
          RecorrerColeccion(ctrl);
      } else {
          if (gv.Rows.Count > 0) {
              gv.FooterRow.Visible = false;
         } else {
              gv.Visible = false;
          }
      }
  }
   
  public void RecorrerColeccion(Control parentCtrl)
  {
      foreach (Control pctrl in parentCtrl.Controls) {
          GridView gv = pctrl as GridView;
          if (gv == null) {
              RecorrerColeccion(pctrl);
          } else {
              if (gv.Rows.Count > 0) {
                  gv.FooterRow.Visible = false;
              } else {
                  gv.Visible = false;
              }
          }
      }
  }

Espero que les resuelva el problema como a mi.

Saludos.

Recorrer todos los controles de una página ASP.NET

Buscando la manera de encontrar una serie de Gridview en una página es que llegué a crear esta función. Que es básicamente recorrer los controles de manera recursiva porque un control puede contener a otros controles en su interior. En mi caso era solamente ocultar el FooterRow de las Grillas (Gridview) y tengo en cuenta que cuando la grilla no tiene rows la oculto directamente.

El código en VB:

        For Each ctrl As Control In Page.Controls
          Dim gv As GridView = TryCast(ctrl, GridView)
          If gv Is Nothing Then
               RecorrerColeccion(ctrl)
          Else
              If gv.Rows.Count > 0 Then
                 gv.FooterRow.Visible = False
               Else
                 gv.Visible = False
              End If
          End If
       Next

Acá esta la función recursiva RecorrerColeccion:

Sub RecorrerColeccion(ByVal parentCtrl As Control)
          For Each pctrl As Control In parentCtrl.Controls
              Dim gv As GridView = TryCast(pctrl, GridView)
              If gv Is Nothing Then
                  RecorrerColeccion(pctrl)
              Else
                  If gv.Rows.Count > 0 Then
                      gv.FooterRow.Visible = False
                  Else
                      gv.Visible = False
                  End If
              End If
          Next
      End Sub

Y acá esta el mismo ejemplo en C#:

 foreach (Control ctrl in Page.Controls) {
      GridView gv = ctrl as GridView;
      if (gv == null) {
          RecorrerColeccion(ctrl);
      } else {
          if (gv.Rows.Count > 0) {
              gv.FooterRow.Visible = false;
         } else {
              gv.Visible = false;
          }
      }
  }
   
  public void RecorrerColeccion(Control parentCtrl)
  {
      foreach (Control pctrl in parentCtrl.Controls) {
          GridView gv = pctrl as GridView;
          if (gv == null) {
              RecorrerColeccion(pctrl);
          } else {
              if (gv.Rows.Count > 0) {
                  gv.FooterRow.Visible = false;
              } else {
                  gv.Visible = false;
              }
          }
      }
  }

Espero que les resuelva el problema como a mi.

Saludos.

AddressOf (Operador)

Este operador (AddressOf) crea un objeto delegate que apunta a un determinado procedimiento, de hecho, podrá asignar normalmente el resultado de AddressOf a una variable delegate sin tener que crear explícitamente un objeto delegate. La diferencia con los punteros es que los delegados de Visual Basic son un tipo de referencia basado en la clase System.Delegate.

En criollo El AddressOf es la forma en la que VB maneja los delegados. Lo que hace AddressOf es decir: cuando se dispare Depurar(), yo quiero que me ejecutes el método borrarRow que debe ser Shared.

Un simple ejemplito de AdrressOf Usando el método genérico de Array, ForEach.

Recibe como parámetros:

Array: Matriz Array unidimensional de base cero en cuyos elementos se va a llevar a cabo la acción.

Action: Delegado Action que se va a ejecutar en cada elemento de array.

Sub Depurar()

Array.ForEach(dataset.Tables(“TABLA”).Select(“CAMPO_ESTADO=1”), AddressOf borrarRow)

Array.ForEach(dataset.Tables(“TABLA2”).Select(“CAMPO_ESTADO=1”), AddressOf borrarRow)

Array.ForEach(dataset.Tables(“TABLA3”).Select(“CAMPO_ESTADO=1”), AddressOf borrarRow)

End Sub

Shared Sub borrarRow(ByVal dr As DataRow)

dr.Delete()

End Sub

El Delegado borrará los campos que coincidan con la condicion del select, osea que un CAMPO_ESTADO sea igual a 1.
Saludos.

Tags: , , , , , , ,

FileUpLoad e ImagenThumbnail

Una de las limitaciones del control fileupload de asp.net 2.0 es que luego de seleccionar el archivo, en este caso una imagen, se requiere un botón adicional para subir la imagen al servidor y previsualizarla. Este post pretende mostrar una manera (lo que no significa que sea la única ni la mejor) de realizar ambos pasos, subir la imagen al servidor y realizar el thumbnail con solo seleccionar la imagen.

Se va utilizar Visual Studio 2005 y por ende asp.net 2.0 (probado para IE 6.0 en adelante y Mozilla-Firefox 2.0.6).

Seguir leyendo “FileUpLoad e ImagenThumbnail”