Sabias que….?

Los operadores (++ o –) incrementan o decrementan el valor de una variable numérica en 1. Pero…… existen 2 condiciones:

1- Cuando es un prefijo, osea ++x  le suma 1 a la variable y devuelve el resultado (osea x+1)

2- Cuando es un postfijo, osea x++ le suma 1 a la variable, pero devuelve el valor anterior a sumarlo (osea devuelve el valor de x y después le suma 1).

	public static void Main()
	{
	var x=10;
var y=++x; //10+1
Console.WriteLine(y);

var z=y++; //en este caso "y" vale 12....pero como uso
//prefijo le pasa 11 a la variable "z"
Console.WriteLine(z);

Console.WriteLine(y);

	}

Referencia MSDN

Acá dejo el ejemplo para que se vea en vivo:

https://dotnetfiddle.net/H2ihKf

Saludos!

Mapear Stored Procedure con EF 6

Inspirado un poco en este link y pensando en una solución para poder mapear el resultado de un Stored Procedure a un objeto tipado es que se me ocurre esta humilde solución.

Entiy Framework tiene la posibilidad de ejecutar un o bien una consulta SELECT o ejecutar un Stored procedure y devolver su valor en un objeto. Ahora bien, lo mas simple es devolver un valor de un tipo primitivo (int, string, bool) como se muestra en el ejemplo del link

using (var context = new BloggingContext())
{
var blogNames = context.Database.SqlQuery(
"SELECT Name FROM dbo.Blogs").ToList();
}

Esto está muy bien pero realmente no es muy útil en un entorno real. Por eso creé este pequeño algoritmo para obtener un objeto completo y genérico de un SP enviado junto con sus parámetros.

 

  public virtual IList<T> Procedimiento_Complejo<T>(string nombreStoredProcedure, params object[] parametros)
        {
            var sqlRaw = "";
            if (string.IsNullOrEmpty(nombreStoredProcedure))
                throw new ArgumentNullException("nombreStoredProcedure");

            sqlRaw = nombreStoredProcedure.Trim() + " ";
            sqlRaw = parametros.Aggregate(sqlRaw, (current, item) =&gt; current + (" @" + item + ","));
            sqlRaw = sqlRaw.Remove(sqlRaw.Length - 1);

            //chequeo que exista el SP
            var query = Contexto.Database.SqlQuery(
                        typeof(int), string.Format("SELECT COUNT(*) FROM [sys].[objects] WHERE [type_desc] = 'SQL_STORED_PROCEDURE' AND [name] = '{0}';", nombreStoredProcedure), new object[] { });
            int existe = query.Cast<int>().Single();
            if (existe == 0)
                throw new ArgumentException("nombreStoredProcedure"); //no existe el SP en la base

            return Contexto.Database.SqlQuery<T>(sqlRaw, parametros).ToList();
       }

El código en si es bastante simple, realiza una concatenación de los parámetros enviados y hace un chequeo de que el SP exista en la base. Hacer la función genérica me permite usarla con cualquier objeto, tanto complejo como primitivo, que se requiera.
Un ejemplito Simple, rápido y reutilizable.

Saludos

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

Probando Greasemonkey….con el Banco Galicia

Para probar este excelente complemento se me ocurrió un mini escript muy sencillo. Poder ver la cotización del dolar del Banco Galicia. De manera normal para poder ver la cotización, hay que seguir una serie de pasos y selección de combos bastante molesta para llegar finalmente al siguiente Request:

https://wsec01.bancogalicia.com.ar/scripts/homebanking/transaccional/TransferenciasCotizacion.asp?CodSuc=001&TipoOp=V

Recordemos que greasmonkey es un addon para Firefox, aunque el código al ser javascript puede ser usado en otros browsers con diferentes herramientas, que permite por medio de scripts hechos por usuarios, añadir de forma arbitraria pequeñas dosis de DHTML a cualquier página web para modificar su comportamiento.

Para empezar vamos a instalar la extensión.
foto1

Una vez instalado le damos click al monito y New User Script.
foto2

  • @name :nombre del programa
  • @namespace :web del autor o otra dirección de interés
  • @description :descripción del programa
  • @include : Página web en la cual nuestro script funcionará
  • @require : A diferencia del resto esta no es obligatoria y tan solo la debemos usar cuando queramos cargar uno o más archivos externos. Por Ejemplo para JQuery.



     
Una vez generado vamos a ir al monito nuevamente y ahí vamos a Manager User Script –> seleccionamos Options en nuestro Script “DolarPrice” y en donde dice Includedd Pages agregamos la pagina principal:

  1. https://wsec01.bancogalicia.com.ar/scripts/homebanking/Principal.asp

y luego en Edit Script User vamos a agregarle el pequeño script:


function reqListener () {
  var strPrecio= this.responseText;
    
  if (strPrecio.indexOf("'garbageCollector'" > -1)) {
      strPrecio=strPrecio.replace("<script language=Javascript>","");
      strPrecio=strPrecio.replace("</script>","");
      strPrecio=strPrecio.replace("parent.consultaCotizacionOk('","");
      strPrecio=strPrecio.replace("');","");

      strPrecio="El valor del dolar" + strPrecio;
    
    var myDiv = document.createElement('div');
    myDiv.innerHTML = strPrecio;
    myDiv.style.fontSize = "22px";
    myDiv.style.color = "red";
    document.getElementById('quickAccess').appendChild(myDiv);

  }
}

var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET","https://wsec01.bancogalicia.com.ar/scripts/homebanking/transaccional/TransferenciasCotizacion.asp?CodSuc=001&TipoOp=V");
oReq.send();

Lo único que hace el script es obtener el valor del Request con el XMLHttpRequest y formatearlo para mostrarlo así:
foto6



Simple y fácil como para arrancar.
Saludos.

RequireJS gestor de dependencias + JQuery

RequireJS es una herramienta de gestión de dependencias creada por James Burke, la cual ayuda a manejar los módulos, cargarlos en un orden correcto y combinarlos de forma fácil sin tener que realizar ningún cambio. A su vez, otorga una manera fácil de cargar código una vez cargada la página, permitiendo minimizar el tiempo de descarga.

Hecha la pequeña introducción vamos al ejemplo como utilizar requirejs con una versión propia de jquery y un archivo aparte.

La estrutcutra del proyecto es bien sencilla:

www/home.html

  • www/js
    • lib
      • jquery.Ejemplo.js
      • jquery-1.10.2.js
      • require.js
    • app
      • main.js
  • app.js

Lo unico que necesitamos en el html es simplemente la referencia a requirejs y a nuestra app.js

<script data-main="js/app" src="js/lib/require.js"></script>

El app.js es principalmente el archivo de configuración. Le vamos a decir donde están nuestros archivos con el baseURL, que tenga un delay de 200mseg y que cargue las 2 librerías: jquery y mi js de ejemplo. La forma de escribir es simple “jquery” es el module ID y “jquery-1.10.2” (siempre sin el .js) es el nombre físico del archivo.

requirejs.config({
    "baseUrl": "js/lib",
    waitSeconds: 200,
    "paths": {
      "app": "../app",
      "jquery": "jquery-1.10.2",
      "Ejemplo" : "jquery.Ejemplo"
    }
});

// Load the main app module to start the app
requirejs(["app/main"]);

Luego nos queda nuestro archivo de lógica, el main.js:

//En el define, pongo todos los módulos que cargue en app.js y los va a ir poniendo en el orden que los defina acá
define(["jquery", "Ejemplo"], function() {

//puedo escribir llamadas aqui....

});

Y por ultimo tenemos nuestro script (jquery.Ejemplo.js), en mi caso una pequeña función de fadein como para usar algo de jquery.

$( document.body ).click(function() {
  $( "div:hidden:first" ).fadeIn( "slow" );
});

requirejs

Como se ve, es muy simple agregar, modificar el orden de carga o quitar archivos para tener un mejor mantenimiento de nuestro proyecto. Dejo el ejemplo como para dar el puntapié inicial.
Saludos

LINK:
GoogleDrive

Animaciones a un input con JQuery.UI

Un pequeño ejemplo que nos permite agregarle una animación a un input cuando se ingresa un valor incorrecto.

Usamos 2 librerias de JQuery:

    <script src="jquery-1.10.2.js"></script>
    <script src="jquery-ui-1.11.1.js"></script>

La función Javascript va a utilizar Ajax para ir al servidor para validar el valor:

<script>
function RecalculoAjax(val) {

if ($.isNumeric(val.value)) {
$.ajax({
type: "POST",
url: "WebForm1.aspx/Validacion",
data: "{val: '" + val.value + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",

success: function (datos) {
var htmlString = datos.d;
if (datos.d != 'OK') {
$(val).effect("shake"); //hace vibrar el input
}

$('#lblresultado').text(htmlString);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
var err = eval("(" + XMLHttpRequest.responseText + ")");
alert('Ha ocurrido un error interno: ' + err.Message);
}
});         // ajax
} //if
else { $('#lblresultado').text("Ingrese un número"); }

}
</script>

En ese mismo código se ve como utilizamos de manera muy sencilla la animación:

if (datos.d != 'OK') {
$(val).effect("shake"); //hace vibrar el input
}

Y le agregamos el evento al textbox:

<asp:TextBox ID="TextBox1" runat="server" onblur="javascript:RecalculoAjax(this)" Width="190px"></asp:TextBox>

El ejemplo se muestra en este gif:

LINK:
GoogleDrive

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

Saludos.

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/