Los selectores jerárquicos en JQuery

Si ya hemos revisado los selectores básicos, podemos comenzar con el siguiente bloque: Selectores por jerarquía (Hierarchy selectors). En este grupo podemos obtener aquellos elementos que dependen de otros en la estructura de nuestra página. Por ejemplo, podemos recuperar los radiobuttons dentro de un formulario específico, imágenes dentro de una referencia sin indicar uno en concreto… Quizás puede interesarnos acceder a estos atributos para cambiar su estilo o darle una nueva funcionalidad de una manera indirecta. Las formas de acceso serían:

  • Antecesor y descendiente: Indicando cuál es el antecesor a través del tipo de elemento, podemos acceder a unos descendientes en concreto y darles así un valor añadido. La forma de acceder a ellos sería $(«antecesor descendiente»).

Ejemplo: Tenemos un body con un formulario que contiene dos divs y , a su vez, cada uno contiene una referencia.

<body>
<form id="form1" runat="server">
<div>
<a href="">Este es el primer enlace dentro de un div</a>
</div>
<div>
<a href="">Este es el segundo enlace dentro de un div</a>
</div>
</form>
</body>

Queremos que todos aquellos elementos de tipo referencia (descendientes) dentro de un div (antecesor) tengan un fondo azul.

$("div a").css("backgroundColor", "blue");

  • Parent > Child: En este caso, se pondrá el id del padre en primer lugar  y el tipo de los hijos del mismo separados por un mayor que. La diferencia con el anterior es que, en este caso, podemos indicar como primer valor el id de un elemento y los hijos son escogidos por el tipo. La manera de recuperarlos es $(«#parent > child»).

Ejemplo: Tenemos dos divs en el cuerpo de la página y deseamos que aquel llamado «padre» tenga el color de las letras de sus referencias de color rojo.

<body>
<form id="form1" runat="server">
<div id="padre">
Soy el div padre <span>Soy un span</span>
<label>
Esto es una label</label>
<a href="">Texto del enlace</a>
<div>
Texto escrito dentro del div <a href="">Texto del enlace</a>
<input value="Un boton" type="button" />
</div>
</div>
<span>Soy un span</span>
<label>
Esto es una label</label>
<div>
Soy un div
</div>
</form>
</body>

Escribiendo el siguiente selector, únicamente estaríamos pintando el texto del enlace que tiene como hijo el div padre, pero no aquel que está colocando dentro del segundo div que contiene el mismo.

$("#padre > a").css("color", "red");

  • Prev + next: Para complicarlo un poco más, podemos estar buscando todos los botones que tienen previamente una label. Esto se consigue especificando en un primer lugar qué necesitamos tener por delante de los elementos que estamos buscando en el siguiente selector: $(«prev + next»).

Ejemplo:

<body>
<form id="form1" runat="server">
<div id="padre">
<div>
Texto escrito dentro del div <a href="">Texto del enlace</a>
<input value="Input sin label" type="button" />
</div>
</div>
<div>
<div>
<label>
Label antes que un input</label>
<input value="Input despues de una label" type="button" />
</div>
</div>
</form>
</body>

El objetivo en este caso, sería poder mostrar el borde del botón de color rojo, pero solamente del segundo que es el único que cumple las condiciones establecidas.

$("label + input").css("borderColor", "red");

  • Prev ~ siblings: Por último, tenemos la posibilidad de seleccionar los elementos por tipo, considerados hermanos, de otro anterior indicado por id. La diferencia que tiene, respecto a parent > child es que este selector localiza el primer elemento especificado por  el id y, a partir de ese momento, todos los elementos del tipo indicado y  además  que estén a su mismo nivel se verán afectados por el cambio introducido. El selector sería el siguiente: $(«prev  ~ siblings»).

Ejemplo:

<body>
<form id="form1" runat="server">
<div id="padre">
Soy el div padre
<div>
Texto escrito dentro del div <a href="">Texto del enlace</a>
<input value="Un boton" type="button" />
</div>
</div>
<span>Soy un span</span>
<label>
Esto es una label</label>
<div>
Soy un div
</div>
</form>
</body>

Tomando como precedente el div con id padre quiero que los próximos elementos de tipo div tengan un borde de 5px y de color amarillo.

$("#padre ~ div").css("border", "5px solid yellow");

¡Saludos!

Los selectores básicos de JQuery

Para los días que tengo más complicados, y para que no decaiga la fiesta :D, me gustaría comenzar con una serie de post relacionados con JQuery.
Lo más básico de JQuery que debemos aprender son los Selectores. Hoy solamente voy a mostrar los denominados como básicos.

A través del símbolo $, podemos seleccionar uno o varios elementos de nuestra página HTML con el fin de poder manipularlos, asignarles eventos, etc. Podemos obtener los mismos de las siguientes maneras:

  • A través del ID del elemento:   Se utiliza el símbolo # seguido del id del elemento que queremos recuperar.
$('#txtControl').css('color', 'red');
  • A través del tag del elemento:  Se indica el tipo de elemento(s) sin ningún simbolo que le preceda.
$('a').css('fontFamily', "Comic Sans MS");
  • A través de la clase que tiene asignada el/los elemento: Utilizamos un punto seguido de la clase css para obtener los elementos que la tienen asignada.
$('.cuadrado').css('backgroundColor', 'blue');

  • A través de dos clases asignadas a un mismo elemento o varios: Igual que el selector por una clase simple, sumándole una clase más sin ningún tipo de separación.
$('.cuadrado.link').css('color', 'red');
  • Todos los elementos de la página: Escribimos un asterisco para referirnos a todos ellos.
$('*').css('fontSize', '20px');
  • A través de varios selectores a la vez: Especificamos los selectores, del tipo que queramos, separados por comas.
$('#txtControl,p,.cuadrado').css('textAlign', 'center');

¡Saludos!

Session-Per-Request en NHibernate con Action Filters en ASP.NET MVC

Una de las buenas prácticas a tener en cuenta antes de trabajar con NHibernate es la siguiente: La sesión y transacción pertenecen a un mismo ciclo de vida. Con esto quiero decir que es importante abrir una transacción cada vez que trabajamos con una base de datos dentro de una aplicación, ya sea para realizar una consulta, como una actualización, eliminación, etc.

Dado que en el post anterior, donde comencé a montar una aplicación con NHibernate y MVC, realicé los ajustes básicos para poder instanciar una sesión y dejar una clase, Connection.cs, lista para su uso, ahora voy a mostrar una forma adaptada a la estructura de MVC para manejar tanto la sesión como la transacción.

Llegados a este punto necesitamos conocer un nuevo concepto: Action Filters.
Un action filter es un atributo que podemos asignar tanto a una acción de nuestro controlador como a un controlador entero para poder proporcionarle una funcionalidad adicional. Para crear un atributo de tipo Action Filter, debemos generar una clase y heredar de ActionFilterAttribute. Esta clase contiene los siguientes métodos, ejecutados en este orden:

  1. OnActionExecuting, se lanza antes de que la acción sea ejecutada.
  2. OnActionExecuted, es llamada después de que la acción finalice.
  3. OnResultExecuting, comienza antes de que el resultado sea devuelto a la página.
  4. OnResultExecuted, ocurre cuando ha terminado de ejecutar el resultado que generó la acción.

En este caso, Session-Per-Request se podría traducir en Session-Per-Action ya que, lo que realmente nos interesa, es tener una sesión disponible para una acción en concreto o para todas las acciones de un controlador. Además, me interesa que la sesión de NHibernate esté disponible ANTES de realizar cualquier operación dentro de la acción en cuestión, ya que si no es así lo más probable es que se lanzara una excepción al no tener un objeto session listo al que consultar. Por último, para que el ciclo de vida se complete correctamente, cuando la acción solicitada finalice, necesito que mi transacción sea completada y mi sesión finalice junto con el ciclo de vida de la petición. Teniendo presentes estas anotaciones, podríamos obtener lo siguiente:

using System.Web.Mvc;
using NHibernate.Context;

namespace MovieManager.Models
{
public class SessionPerRequest : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext1)
{
var session = MvcApplication.SessionFactory.OpenSession();
session.BeginTransaction();
CurrentSessionContext.Bind(session);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
var session = CurrentSessionContext.Unbind(MvcApplication.SessionFactory);
if (session != null)
{
if (session.Transaction.IsActive)
{
try
{
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}

session.Close();
}
}
}
}

Para este ejemplo, he sobrescrito los métodos OnActionExecuting OnResultExecuted . En el primero de ellos, inicializo la sesión de NHibernate y bindeo la misma en el contexto de la aplicación. Por el contrario, en el segundo método recupero la sesión, compruebo si tiene alguna transacción en curso, realizo el commit (Si ocurriera algún error durante el commit de la transacción actual, se realizaría un rollback para evitar problemas) y cierro la sesión.

En el archivo web.config, necesitamos declarar una propiedad para indicar el contexto en el que se enmarca la aplicación. Esta propiedad es current_session_context_class y , en este caso, podríamos declararlo como web, tal y como indico en el siguiente código:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider, NHibernate</property>
<property name="connection.connection_string">
Server=localhostsqlexpress;initial catalog=MovieManager;Integrated Security=true
</property>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="current_session_context_class">web</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
<mapping assembly="MovieManager"/>
</session-factory>
</hibernate-configuration>

Por otro lado, podemos comprobar que hacemos referencia a MvcApplication.SessionFactory, lo cual significa que, para tener un mayor acceso a nuestra «Factoría de sesiones» he posicionado su declaración en el archivo Global.asax para poder acceder desde cualquier parte de mi aplicación.

using System.Web.Mvc;
using System.Web.Routing;
using NHibernate;
using NHibernate.Cfg;

namespace MovieManager
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801

public class MvcApplication : System.Web.HttpApplication
{
public static ISessionFactory SessionFactory = new Configuration().Configure().BuildSessionFactory();

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);

}

protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
}
}

Para ir finalizando, podemos ver la forma de utilizar el atributo SessionPerRequest en un controlador donde necesitaremos persistencia. Colocamos el mismo entre corchetes bien en la declaración del controlador o en cualquiera de las acciones.

using System.Web.Mvc;
using MovieManager.Models;

namespace MovieManager.Controllers
{
[SessionPerRequest]
public class HomeController : Controller
{
public ActionResult Index()
{
var movieRepository = new MovieRepository(MvcApplication.SessionFactory);
return View(movieRepository.ListMovies());
}

public ActionResult About()
{
return View();
}
}
}

En la acción Index, creamos un objeto MovieRepository, donde le pasamos como parámetro el objeto SessionFactory declarado en el fichero Global.asax. Llegados a este punto debemos tener en cuenta de que la sesión de NHibernate, necesaria para llamar a la base de datos y recuperar el listado de películas, ya ha sido inicializada justo antes de entrar en la acción gracias al atributo SessionPerRequest. Si echamos un vistazo al repositorio, vemos lo siguiente:

using System.Collections.Generic;
using MovieManager.Models.Objects;
using NHibernate;

namespace MovieManager.Models
{
public class MovieRepository
{
private readonly ISessionFactory _session;

public MovieRepository(ISessionFactory sessionFactory)
{
_session = sessionFactory;
}

public IList<Movie> ListMovies()
{
return _session.GetCurrentSession().CreateCriteria(typeof(Movie)).List<Movie>();
}
}
}

A través del constructor de la clase MovieRepository, estamos inyectando el objeto SessionFactory. De tal manera que podemos utilizar la misma factoría de sesiones en cualquiera de los métodos implementados en esta clase, que necesiten hacer una consulta, actualización, etc. Cuando todo haya terminado, todo quedará perfectamente finalizado gracias a Action Filters y Session-Per-Request/Action.

¡Saludos!

NHibernate y ASP.NET MVC

NHibernate es la versión de Hibernate (Java) para .NET. Es una herramienta para el mapeo objecto-relacional que ayuda a identificar en nuestro código los atributos de una clase con las columnas de nuestras tablas, por decirlo de una forma simplificada.
El objetivo es que, para el programador, sea posible manejar su base de datos a través de los objetos de .NET, con lo que se consigue una mayor abstracción.
Podemos conseguir más información en la página oficial de la comunidad de usuarios. También tenemos a nuestra disposición el grupo de Google NHibernate-Hispano, donde podrán echarnos una mano con esta librería.

Para poder utilizarla, voy a comentar una serie de pasos a tener en cuenta para su configuración:

  • Descargar la librería de NHibernate.
  • Crear una clase para el manejo de sesión y configuración de NHibernate.
  • Configuración en el archivo web.config.
  • Creación de nuestros objetos de negocio.
  • Creación de los archivos de mapeo.

DESCARGAR LA LIBRERÍA DE NHIBERNATE

En este post, vamos a trabajar con la versión NHibernate-2.1.0.GA. Para descargar la misma podemos hacerlo a través del siguiente enlace.

Como a día de hoy, nos encontramos en la versión ASP.NET MVC 1.0 y la 2.0 sigue estando en fase de desarrolo, vamos a utilizar la 1.0 para crear el ejemplo. Dicho esto, creamos un proyecto MVC (Si tenemos las dos versiones instaladas, se pueden diferenciar perfectamente ya que MVC 2.0 Preview 1 ó 2 tiene un 2 en el nombre de la plantilla).

En mi caso, voy a llamar a mi proyecto MovieManager. Confirmamos la creación del proyecto y lo primero que nos sugiere es crear un proyecto de Test. Aceptamos la sugerencia para poder utilizala más adelante 😀

Llegados a este punto, es necesario añadir una serie de referencias a nuestro proyecto. Descomprimimos el paquete que acabamos de descargar y añadimos las siguientes:

  • NHibernate.dll
  • Iesi.Collections.dll
  • log4net.dll
  • NHibernate.ByteCode.LinFu.dll

Cómo ya expliqué en un post anterior sobre la estructura de un proyecto ASP.NET MVC, tenemos tres partes bien diferenciadas: Modelo, Controlador, Vista(s). En este post, vamos a comenzar por la parte del modelo donde utilizaremos NHibernate.
En primer lugar, voy a crearme rápidamente una base de datos en SQL Server 2008 Express llamada MovieManager con una sola tabla por el momento.

CREAR UNA CLASE PARA EL MANEJO DE SESIÓN Y CONFIGURACIÓN DE NHIBERNATE

Cuando realizamos consultas a base de datos con NHibernate, es necesario controlar la sesión. A través del objeto session tenemos a nuestra disposición métodos como Save, Update, CreateCriteria, etc. Es muy importante manejar correctamente la sesión aunque espero poder hacerlo en algún post más adelante.

using NHibernate;
using NHibernate.Cfg;

namespace MovieManager.Models
{
public sealed class Connection
{
private static ISessionFactory _sessionFactory;
private static Configuration _nhConfig;
private static ISession _session;

public static ISession Session
{
get
{
if (_session == null)
GetCurrentSession();
return _session;
}
}

private static void Init()
{
_nhConfig = new Configuration();
_nhConfig.AddAssembly("MovieManager");
_sessionFactory = _nhConfig.BuildSessionFactory();

}
private static ISessionFactory GetSessionFactory()
{
if (_sessionFactory == null)
Init();
return _sessionFactory;
}

private static void GetCurrentSession()
{
_session = GetSessionFactory().OpenSession();
}
}
}

Actualizado 02/11/2009: Elimino los métodos innecesarios para este post en concreto. Mostraré en otro post diferente cómo sería la manera correcta de manejar la sesión y transacción de NHibernate.

CONFIGURACIÓN DEL ARCHIVO WEB.CONFIG

En el código anterior, teníamos una función Init() que se encargaba de cargar la configuración de NHibernate. Para que esto sea posible es necesario crear una sección en el web.config dónde configuramos todo lo relativo a la base de datos que queremos utilizar.

<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate" requirePermission="false"/>

Una vez declarada la sección, escribimos la misma con los valores necesarios para conectarnos a la base de datos oportuna:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider, NHibernate</property>
<property name="connection.connection_string">
Server=localhostsqlexpress;initial catalog=MovieManager;Integrated Security=true
</property>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
</session-factory>
</hibernate-configuration>

Actualizado 02/11/009 : Elimino la propiedad current_session_context_class, ya que por el momento no es necesario establecerla.

Existen varios dialectos soportados para poder utilizar distintos tipos de bases de datos. Para más información sobre ello, os facilito el siguiente enlace.

CREACIÓN DE NUESTROS OBJETOS DE NEGOCIO

La base de datos que tengo en mente almacena información sobre peliculas. Como hasta ahora solamente tenemos una tabla llamada Movies en nuestra base de datos, voy a crear la clase en .NET que representa a dicha tabla.

using System;
namespace MovieManager.Models.Objects
{
public class Movie
{
public int Id { get; set; }
public string Name { get; set; }
public string Genre { get; set; }
public string Synopsis { get; set; }
public DateTime Year { get; set; }
}
}


La clase Movie, no contiene ningún método especial ni atributo que tenga relación con NHibernate. Ese rol, lo tiene el archivo de mapeo que será el que relacione cada propiedad de esta clase con la columna de una tabla específica.

CREACIÓN DE LOS ARCHIVOS DE MAPEO

Para crear el archivo de mapeo necesitamos saber, el nombre de la tabla, el nombre de la clase que representará en .NET a nuestra tabla y los campos que queremos recuperar de base de datos.

 

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="MovieManager.Models.Objects.Movie,MovieManager" table="Movies" lazy="false">
<id name="Id" column="Id" unsaved-value="0">
<generator class="native" />
</id>
<property name="Name" column="Name" />
<property name="Genre" column="Genre"/>
<property name="Synopsis" column="Synopsis" />
<property name="Year" column="Year" />
</class>
</hibernate-mapping>

Hay que tener en cuenta un paso muy importante, a la par que olvidadizo 🙂 , y es lo siguiente: El archivo de mapeo debe tener la extensión .hbm.xml y, además, tenemos que asegurarnos de que el Action Build asignado a estos archivos de mapeo sea Embedded Resource ya que de no ser así la configuración de NHibernate no los tendrá en cuenta.

Con estos pasos, nuestra aplicación estaría lista para funcionar con NHibernate, ocupando la parte del Modelo. En el próximo post me centraré en la parte del controlador y vista para poder solicitar información al modelo y que el usuario pueda obtener a través de la vista los resultados recibidos.

¡Saludos!

Delegate

Un delegate es un objeto que hace referencia a uno o más métodos, previamente declarados en nuestra aplicación. Todos aquellos métodos que sean incluidos en él, tienen la particularidad de ser idénticos en cuanto al retorno y los parámetros que recibe. ¿Con todo esto qué quiero decir? ¿Cuál es el objetivo? La magia está en que, si nosotros creamos un delegate con una serie de métodos asociados, al llamar al mismo lanzará un método detrás de otro pasándole a cada uno de ellos el valor(es) con el que invocamos al delegate. Veamos un ejemplo:

delegate void Delegado(string cadena);

Si mi delegado es como el anterior, todos los métodos que contenga no deberán de retornar nada y necesitan como parámetro un string.
Esa sería la forma de declarar un delegado. Para continuar con el ejemplo, voy a crear dos métodos que cumplan las características del delegado (Esto es muy importante porque, de no ser así, lanzará una excepción).

public void Saludo(string cadena)
{
lblResult.Text += "Hola " + cadena;
}
public void Despedida(string cadena)
{
lblResult.Text += " Adios " + cadena;
}

La forma de asignar un método sería la siguiente:

protected void btnDelegado_Click(object sender, EventArgs e)
{
Delegado delegando = Saludo;
delegando += Despedida;
delegando(txtCadena.Text);
}

Para asignar el método Saludo, simplemente utilizo el símbolo = y, para añadir el método Despedida +=
Si quisiéramos eliminar en algún momento del delegado uno de los métodos, únicamente tendríamos que utilizar -= nombre_del_Metodo

¡Saludos!

Cliente JSON para WCF

En un post anterior, mostré como crear un servicio web con Windows Communication Foundation. Para consumir el mismo, vamos a crear un pequeño cliente JSON con JQuery.
Creamos un proyecto ASP.NET Web Application:

Antes de comenzar con nuestro código, necesitamos la librería de JQuery, la cual podemos obtenerla en este enlace. Una vez descargada, agregamos el archivo a nuestra solución.
Por otro lado, vamos a crear un nuevo archivo JScript, llamado JSON.js, donde implementaremos la funcionalidad que llamará a nuestro servicio y recogerá el resultado. Nuestro proyecto quedaría de la siguiente manera:


He utilizado la página Default.aspx para mostrar dos textbox para recoger los valores y dos botones con los que llamaremos al servicio.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ClienteJSON._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Cliente JSON</title>
</head>
<body>
<div id="Calculos">
<div>
<div>
<label id="lblNumeroUno">
Introduce número:</label>
<input type="text" id="txtNumUno" />
</div>
<div>
<label id="lblNumeroDos">
Introduce otro número:</label>
<input type="text" id="txtNumDos" />
</div>
<div>
<input type="button" id="btnSumar" value="Sumar" />
<input type="button" id="btnRestar" value="Restar" />
</div>
</div>
</div>

<script type="text/javascript" src="jquery-1.3.2.js"></script>
  <script type="text/javascript" src="JSON.js"></script>

</body>
</html>

Por último, sólo nos quedaría llamar a nuestro servicio web y mostrar el resultado que nos aporta, en función de si queremos Sumar o Restar los número que introducimos a través de la interfaz. Abrimos el archivo JSON.js e introducimos lo siguiente:

$("#btnSumar").bind("click", function(e) {

var params = { "a": $('#txtNumUno').val(), "b": $('#txtNumDos').val() };

$.ajax({
type: "GET",
url: "http://localhost/WCF/Service.svc/json/Suma",
data: params,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
alert("Resultado Suma: " + msg.d.Result);
}
});
});


$("#btnRestar").bind("click", function(e) {

var params = { "a": $('#txtNumUno').val(), "b": $('#txtNumDos').val() };

$.ajax({
type: "GET",
url: "http://localhost/WCF/Service.svc/json/Resta",
data: params,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
alert("Resultado Resta: " + msg.d.Result);
}
});
});

La verdad es que, teniendo JQuery, es bastante simple realizar este tipo de funcionalidad. He utilizado el método Bind, para asignarles el evento a cada uno de nuestros botones. De esta manera, no tenemos que introducir ningún código de javascript en nuestro aspx. Más adelante me gustaría enfocarme más en la manera de funcionar de esta librería.

En el mismo sitio donde bindeamos el evento click a nuestro botón, creamos la función que se va a ejecutar.
Utilizamos la variable params para montar nuestra cadena de parámetros. Hay que tener en cuenta que el nombre de cada parámetro se debe corresponder con el que tienen en el servicio web (en este caso a y b).
Creamos un objeto ajax con los atributos type (el tipo de HTTP Verb que vamos a utilizar), la url donde se aloja nuestro servicio, seguido del método que vamos a invocar, en data le pasamos los parámetros necesarios para el cálculo solicitado, contentType indica cómo va a evaluar JQuery la respuesta y cómo nos la va a devolver (En el caso de JSON evalúa la respuesta como tal y nos retorna un objeto javascript), dataType es el formato en el que estamos pasando nuestro parámetros y en la parte success se adjunta la función que se lanzará cuando haya terminado el proceso en caso de éxito. En un principio, esto es lo mínimo que debemos usar.

Si arrancamos la aplicación, ya tenemos nuestra Suma y nuestra Resta funcionando con un servicio web en WCF y su cliente en JSON.

 
¡Saludos!

Actualización 31/10/2009: En el archivo JSON.js, he modificado la forma de recuperar el valor de los textbox por .val(), que sería la forma correcta con JQuery. De la otra manera, $(‘#textbox’)[0].value, era un híbrido que funciona exactamente igual, pero creo que queda más elegante con .val(). ¡Saludos!

Soporte Intellisense para JQuery en Visual Studio 2008

Por el momento, hasta que no podamos disfrutar del todo de Visual Studio 2010, la versión 2008 no tiene por defecto el soporte para el intellisense de JQuery. ¡Pero todo tiene solución! Ya que entiendo que es una gran comodidad para el programador visualizar las posibilidades que nos ofrece una librería como esta.
En primer lugar debemos tener instalado el SP1 para Visual Studio 2008 (o también, desde ese mismo link, podemos conseguir el Visual Studio 2008 Express Editions con el SP1 integrado)  y un hotfix que podéis descargar de esta dirección.
Una vez que tenemos listo nuestro Visual Studio, ya podemos descargar los vsdoc.js que nos ofrece JQuery. Si accedemos al listado de descargas, podemos visualizar los vsdocs disponibles desde la versión 1.2.6 en adelante. Los archivos necesarios son aquellos que en la descripción aparece lo siguiente: Visual Studio Autocomplete Documentation.

Descargamos el vsdoc para la versión que estamos utilizando de JQuery y lo agregamos en nuestro proyecto. Al comienzo de los archivos js, indicamos como referencia el vsdoc que hemos añadido de la siguiente forma:

/// <reference path="~/jquery-1.3.2-vsdoc2.js"/>

Por último, podemos comprobar como efectivamente nos muestra el listado de posibilidades y una pequeña descripción de el uso de las mismas.

¡Saludos!

System.InvalidOperationException IIS 7

En el post anterior, comentaba algunos comandos para poder solucionar los problemas que pudiéramos tener con nuestras aplicaciones con WCF y nuestro IIS. Con esos dos pasos, conseguí que funcionara perfectamente en Windows XP (IIS 5.1)… pero al llegar a casa y volver a ejecutar la aplicación en IIS 7 con Windows 7… Llega de nuevo la desilusión. El caso es que lo conseguí arreglar cuando tenía la versión de 32bits, pero me bajé la de 64bits y claro, para que voy a apuntarme este tipo de cosas 😉
El error que me mostraba era el siguiente:

Después de dar muchísimas vueltas, leer blogs, preguntar a Google de cuatrocientas formas distintas, etc. nada me sirvió y la verdad es que sigo sin entender bien por qué. El caso es que se me ocurre la genial idea de montarlo como Sitio web en vez de Directorio Virtual y ahora le parece estupendo.

 

La verdad es que no entiendo bien por qué no acepta el servicio como un directorio virtual, pero es la única forma en la que he conseguido que me funcionara con WCF en Windows 7 y la verdad no recuerdo si llegué a la misma conclusión cuando tenía instalada la versión de 32bits.
¿Alguien sabe otra solución o conoce la causa de esto? En cualquier caso, si a alguien le sucede lo mismo que a mí y no encuentra otra solución alternativa a esta, siempre nos quedarán los sitios web 🙂

¡Saludos!

Failed to access IIS metabase

  1. Siempre instalaré IIS antes que Visual Studio.
  2. Siempre instalaré IIS antes que Visual Studio.
  3. Siempre instalaré IIS antes que Visual Studio.
  4. Siempre instalaré IIS antes que Visual Studio.
  5. Siempre instalaré IIS antes que Visual Studio.
  6. Siempre instalaré IIS antes que Visual Studio.
  7. Siempre instalaré IIS antes que Visual Studio.
  8. Siempre instalaré IIS antes que Visual Studio.
  9. Siempre instalaré IIS antes que Visual Studio.
  10. Siempre instalaré IIS antes que Visual Studio.


Y si es que no… ¡A sufrir se ha dicho! Cada vez que formateo y tengo que organizar las extensiones del IIS me vuelvo loca para volver a lo que tenía configurado y pensé que nunca más volvería a sufrir. Este error pasa justamente por esto y, antes de volvemos locos de remate, abrimos una línea de comandos y ejecutamos lo siguiente:

%system root%Microsoft.NETFrameworkversionNumberaspnet_regiis.exe -i

Por ejemplo:

C:WINDOWSMicrosoft.NETFrameworkv2.0.50727>aspnet_regiis.exe -i

Sin irnos muy lejos, es posible que si justamente hemos instalado IIS después del Visual Studio, tampoco tengamos las extensiones svc  y nuestras aplicaciones WCF no funcionen. Os dejo también este otro comando para matar dos pájaros de un tiro:

C:WINDOWSMicrosoft.NETFrameworkv3.0Windows Communication Foundation>ServiceModelReg.exe -i


¡Suerte y Saludos! 

Creando un Web Service con WCF

Windows Communication Foundation fue una de las novedades de .NET Framework 3.0, la cual permite la creación de sistemas distribuidos orientados a servicios.
Con Visual Studio 2008, disponemos de una plantilla que nos genera todo lo necesario para empezar a trabajar con ello. No obstante, en esta ocasión, dejaremos de lado la misma para poder visualizar claramente qué es lo necesario para que WCF funcione.

CREACIÓN DEL PROYECTO

Creamos un nuevo proyecto de tipo librería:

Incluimos las librerías System.ServiceModel y System.Runtime.Serialization.

EL CONTRATO (CONTRACT)

Lo primero que debemos crear es una interfaz que tendrá como misión ser el Contrato del servicio web. Lo que nos indica el mismo es qué funcionalidades tiene operativas el servicio de cara a las aplicaciones que lo van a consumir.
Creamos una interfaz llamada IService.cs y codificamos las siguientes funcionalidades:

using System.ServiceModel;
using System.ServiceModel.Web;
using System.Runtime.Serialization;

namespace WCF
{
    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        [WebGet]
        Resultado Suma(int a, int b);

        [OperationContract]
        [WebGet]
        Resultado Resta(int a, int b);
    }
   [DataContract]
    public class Resultado
   {
       [DataMember]
       public int Result { get; set; }
   }
}

Tenemos los siguientes atributos:

  • ServiceContract, el cual indica que nuestra interfaz va a hacer las veces de contrato.
  • OperationContract por cada método que queramos exponer.
  • Por último, dentro del mismo archivo (No es recomendable) hemos creado una pequeña clase con el atributo DataContract que será el objeto serializado que viajará como respuesta a las peticiones tanto de la Suma como la Resta. Por cada miembro dentro del contrato de datos, contiene un DataMember.

Es una clase perfectamente normal que contiene los métodos que definimos en el contrato. Si creamos código adicional, para realizar cualquier otra operación, no sería visible al no estar definido en la interfaz del servicio.

EL ARCHIVO SVC

Un archivo importante a tener muy en cuenta es el archivo con extensión svc, el cual erá de utilidad a IIS cuando publiquemos el servicio. Añadimos un documento en blanco, llamado Service.svc, con el siguiente contenido:

<%@ ServiceHost Service=»WCF.Service» %>

Le indicamos el namespace de la  implementación del contrato como valor de Service para que pueda localizarlo.

DLL FUERA DE DEBUG Y RELEASE

Para que IIS pueda localizar correctamente las librerías del servicio web, debemos cambiar las propiedades de Build en nuestro proyecto y dejar nuestro «Output path» de la siguiente forma:

Por último, quizás la parte más compleja, necesitamos configurar el archivo web.config con los endpoints necesarios para aceptar peticiones. Dependiendo de los distintos tipos de comunicacion que tengamos, deberemos implementar más o menos endpoints.

¿Qué es un Endpoint?

Un endpoint está compuesto por tres valores: Address (¿Dónde?), Binding (¿Cómo?) y Contract (¿Qué?). La suma de ellos genera una serie de requisitos para poder establecer una conexión con nuestro servidor. Un servicio con WCF puede disponder de varios endpoints distintos, por lo que el número de clientes de diferentes características pueden consumirlo.

Creamos pues un archivo Web.config y eliminamos el contenido. En este post, voy a crear un endpoint para un cliente JSON.

<?xml version=»1.0″?>
<configuration>
  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name=»webBinding»>
        </binding>
      </webHttpBinding>
    </bindings>
    <services>
      <service name=»WCF.Service»
               behaviorConfiguration=»MiBehavior»>
        <endpoint address=»json»
                  binding=»webHttpBinding»
                  bindingConfiguration=»webBinding»
                  behaviorConfiguration=»jsonBehavior»
                  contract=»WCF.IService»/>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name=»jsonBehavior»>
          <enableWebScript/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name=»MiBehavior»>
          <serviceMetadata httpGetEnabled=»true»/>
          <serviceDebug includeExceptionDetailInFaults=»True»/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Dentro de la sección system.serviceModel tenemos:

Por un lado, la sección de los bidings disponibles, que en este caso sólo tenemos el necesario para una configuración de JSON; services donde indicamos el address, el nombre de nuestro binding, el behavior (indicado más abajo)  y el nombre del contrato que queremos utilizar.

Llegados a este punto, podemos crear una aplicación que tenga hosteado el servicio que acabamos de crear o bien utilizar IIS, configurando como documento de inicio Service.svc.

IMPLEMENTACIÓN DEL CONTRATO

El siguiente paso es crear una clase que implemente el contrato que acabamos de definir.

namespace WCF
{
    public class Service : IService
    {
        public Resultado Suma(int a, int b)
        {
            var resultado = new Resultado {Result = a + b};
            return resultado;
        }

        public Resultado Resta(int a, int b)
        {
            var resultado = new Resultado {Result = a – b};
            return resultado;
        }
    }

}

Si accedemos a las dos direcciones que indico abajo a través del explorador, debería devolvernos un archivo en formato JSON por cada petición.

http://localhost/WCF/Service.svc/json/Suma

http://localhost/WCF/Service.svc/json/Resta

Ambas devolverían cero porque no se les está pasando ningún parámetro.
En el siguiente post de WCF, crearé un cliente que realice y reciba la respuesta con JSON para poder acceder a nuestro servicio web y pasarle los parámetros necesarios.

¡Saludos!