Performancing Metrics

November 2009 - Artículos - Return(GiS);

Return(GiS);

November 2009 - Artículos

Service Bus En Windows Azure Platform AppFabric

Después de la introducción en el post anterior a AppFabric, me arriesgo a adentrarme un poco más en cada uno de los elementos que la componen. A continuación, voy a centrarme en Service Bus y en cómo podemos crear un pequeño ejemplo para involucrarlo.

En primer lugar, cabe mencionar el patrón ESB (Enterprise Service Bus)  para poder entender el mecanismo. De una forma simplificada, podemos decir que este patrón está basado en mensajes y unas normas a seguir por los integrantes en la comunicación. Necesitamos un sistema por el cual seamos capaces de enviar un mensaje o petición al otro extremo, siendo conscientes de la existencia de firewalls, dispositivos NATs, etc. ¿Y si existiera la posibilidad de contar con un intermediario que enviara por nosotros ese mensaje? Aquí es donde entra en juego Service Bus.



En la actualidad, existen SDK's para .NET, Java y Ruby. En .NET nos resultará bastante familiar si alguna vez hemos trabajado con WCF. Para poder comenzar en nuestro entorno de Visual Studio, es necesario bajar el siguiente SDK para .NET. Además, antes de empezar a trabajar con Service Bus, debemos completar los pasos citados en el anterior post desde el portal de AppFabric.

En este post, voy a crear tres aplicaciones: Un servicio con WCF, que será la forma de comunicarse una aplicación con otra, un proyecto de consola que actuará como servidor y una aplicación winform que enviará y recibirá mensajes.

CREAR UN SERVICIO CON WCF

En primer lugar, necesitamos generar un contrato y su implementación como si de servicio web se tratara. Para ello, he creado un proyecto de tipo WCF Service Application llamado ServiceBusAppFabric.

Renombro la interfaz IService1.cs por IServiceBus.cs y la actualizo con el siguiente código:

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

namespace ServiceBusAppFabric
{
[ServiceContract]
public interface IServiceBus
{
[OperationContract]
void SendMessage(string msg, string sender, string receiver);

[OperationContract]
CompositeType ReceiveMessage(string receiver);
}


[DataContract]
public class CompositeType
{
[DataMember]
public string Sender { get; set; }

[DataMember]
public string InstantMessage { get; set; }
}
}


Modifico el nombre de Service1.svc por ServiceBus.svc e implemento la interfaz que acabamos de crear.

using System;
using System.Linq;

namespace ServiceBusAppFabric
{
public class ServiceBus : IServiceBus
{
public void SendMessage(string msg, string sender, string receiver)
{
var imEntities = new InstantMessagesDB();
MessageIM iM = new MessageIM { InstantMessage = msg, Receiver = receiver, Sender = sender };
imEntities.AddToMessageIMSet(iM);
imEntities.SaveChanges();
Console.WriteLine("Received Message from:" + sender);
}

public CompositeType ReceiveMessage(string receiver)
{
var imEntities = new InstantMessagesDB();
var IMs = (from i in imEntities.MessageIMSet.ToList()
where i.Receiver == receiver
select i).FirstOrDefault();
if (IMs != null)
{
Console.WriteLine(string.Format("Sending Message: {0} from {1}", IMs.InstantMessage, IMs.Sender));
return new CompositeType { InstantMessage = IMs.InstantMessage, Sender = IMs.Sender };
}
return new CompositeType { InstantMessage = "No Messages", Sender = "No one" };
}
}
}

Como podemos ver, en la llamada SendMessage estoy recibiendo el mensaje, el remitente y el destinatario del mismo. En esta demo estoy utilizando Entity Framework para acceder a una base de datos en SQL Express llamada IM con una tabla como esta:


Creo un objeto del tipo MessageIM y lo guardo en base de datos. Por último, muestro un mensaje por consola informando del nuevo mensaje recibido.
El método ReceiveMessage recibe el nombre del destinatario y busca entre los mensajes guardados cual le corresponde. De no obtener ningún resultado informa al usuario que nadie envió nada para él.

CREACIÓN DEL SERVIDOR

Una vez que tenemos la forma de comunicarnos, necesitamos crear una aplicación que tenga el rol de servidor. Para ello, he creado la siguiente aplicación de consola:

using System.ServiceModel;
using ServiceBusAppFabric;

namespace ServerAppFabric
{
class Program
{
static void Main(string[] args)
{
System.Console.WriteLine("Waiting a response from AppFabric...");
ServiceHost host = new ServiceHost(typeof(ServiceBus));
host.Open();

System.Console.WriteLine("I'm ready =)");
System.Console.WriteLine("Press [Enter] to exit");
System.Console.ReadLine();

host.Close();
}
}
}

Es necesario importar la dll que generó nuestro proyecto de WCF y además System.ServiceModel para poder crear un objeto de tipo ServiceHost.


Ahora lo que necesitamos es configurar un endpoint de la misma manera que podríamos hacerlo para un servicio en WCF, con algunos pequeños cambios. Añadimos un archivo de tipo App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="InstantMessagesDB" connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\SQLEXPRESS;Initial Catalog=IM;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>
<system.serviceModel>
<services>
<service name="ServiceBusAppFabric.ServiceBus" >
<endpoint address="sb://gisendpoint.servicebus.windows.net/ServiceBus"
behaviorConfiguration ="sharedSecretClientCredentials"
binding="netTcpRelayBinding"
contract="ServiceBusAppFabric.IServiceBus" />
</service>
</services>
<behaviors>
<endpointBehaviors >
<behavior name ="sharedSecretClientCredentials">
<transportClientEndpointBehavior credentialType="SharedSecret">
<clientCredentials>
<sharedSecret issuerName="[Issuer Name]"
issuerSecret="[Issuer Key]"/>
</clientCredentials>
</transportClientEndpointBehavior>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>


Dentro de la sección configuration tenemos un connectionString, para poder conectar con la base de datos IM, y  la sección system.serviceModel con la configuración necesaria para la parte services. En el post anterior, comentaba que era posible visualizar el detalle del namespace del servicio que acabamos de crear. Si volvemos a aquel apartado podemos localizar los valores necesarios para completar el endpoint.

  • En la propiedad address añadiremos sb://serviceNamespace.servicebus.windows.net
  • El binding  será de tipo netTcpRelayBinding. Para poder utilizar este tipo de binding sólo es necesario tener en cuenta que utiliza SSL a través del puerto 828. Por este motivo, es necesario abrir dicho puerto en nuestro router para que pueda funcionar correctamente.
  • El contrato sería la interfaz de nuestro servicio WCF creado anteriormente

Para finalizar, hemos creado un behavior un tanto especial. Esta información también es particular del namespace del servicio que creamos en AppFabric y serán necesarios tanto Default Issuer Name como Default Issuer Key.

Si arrancamos la aplicación, vemos que en un primer momento espera la contestación por parte de AppFabric y, a los pocos segundos, está listo para su uso.



CREACIÓN DEL CLIENTE

La última aplicación pendiente sería un cliente winform con el siguiente aspecto:

En realidad es bastante simple. La primera parte sería para el envío de mensajes, escribiendo tanto el remitente, como el destinatario y el mensaje en sí, y en la parte inferior podemos pasarle el nombre del usuario del cual queremos recuperar el mensaje pendiente.

using System.ServiceModel;
using System.Windows.Forms;
using ServiceBusAppFabric;

namespace ClientForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void btnSend_Click(object sender, System.EventArgs e)
{
ChannelFactory<IServiceBus> channel = new ChannelFactory<IServiceBus>("RelayEndpoint");
IServiceBus client = channel.CreateChannel();

client.SendMessage(txtMessage.Text, txtSender.Text, txtReceiver.Text);

lblResultSend.Text = "Sent It!";

channel.Close();
}

private void btnReceived_Click(object sender, System.EventArgs e)
{
ChannelFactory<IServiceBus> channel = new ChannelFactory<IServiceBus>("RelayEndpoint");
IServiceBus client = channel.CreateChannel();
var result = client.ReceiveMessage(txtReceiverName.Text);

lblMessagesResult.Text = "Message: " + result.InstantMessage + " From:" + result.Sender;

channel.Close();
}
}
}

En el codebehind del formulario tenemos un evento para cada botón. En ambos, abrimos un canal a través de ChannelFactory especificando el contrato de nuestro servicio y utilizamos el envío o la recepción de mensajes según el caso. El endpoint del cliente sería similar al anterior.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address ="sb://gisendpoint.servicebus.windows.net/ServiceBusAppFabric"
binding="netTcpRelayBinding"
contract="ServiceBusAppFabric.IServiceBus"
behaviorConfiguration="sharedSecretClientCredentials"
name="RelayEndpoint" />
</client>
<behaviors>
<endpointBehaviors >
<behavior name="sharedSecretClientCredentials">
<transportClientEndpointBehavior credentialType="SharedSecret">
<clientCredentials>
<sharedSecret issuerName="[Issue Name]"
issuerSecret="[Issuer Secret]" />
</clientCredentials>
</transportClientEndpointBehavior>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

Si arrancamos el servidor y acto seguido el cliente, comprobaríamos que efectivamente podemos enviar y recibir mensajes:

Incluyo los tres proyectos a este post.

¡Saludos!

Posted: 29/11/2009 3:20 por Gisela | con 6 comment(s) |
Archivado en: ,
AppFabric

En post anteriores sobre Windows Azure, comencé a hablar de cloud computing como un concepto conocido por todos cuando realmente no es tan... sencillo. Me gustaría poder tocar poco a poco todos los servicios disponibles por Microsoft en este aspecto, para poder valorar todas las posibilidades que están ofreciendo actualmente. En esta ocasión, voy a centrarme en AppFabric, anteriormente conocido como .Net Services. Comentar que he encontrado poca información al respecto y es posible que no sea consciente aún de todas las posibilidades que ofrece.

¿QUÉ ES APPFABRIC?

Service Bus y Access Control son los servicios que componen AppFabric y que están apoyados en Windows Communication Foundation (WCF). Estos dos componentes trabajan de manera conjunta, para conseguir la conexión de forma bidireccional entre aplicaciones, facilitando el acceso a redes protegidas de una manera segura y sencilla. Access Control nos ayudará a crear conexiones seguras entre nuestras aplicaciones y servicios y Service Bus será útil para conectarnos a través de la red a organizaciones con protecciones como Firewalls, NATs, etcétera.

¿POR DÓNDE EMPIEZO?

Como expliqué en el post sobre Cómo obtener una cuenta para Windows Azure, AppFabric (.NET Services en el momento del post) no precisa de invitación y con el registro sería más que suficiente para poder comenzar.
Accedemos al portal de AppFabric y lo primero que vemos es lo siguiente:

Un proyecto en AppFabric es simplemente un contenedor donde se organizarán todos nuestros namespaces relacionados con Service Bus y Access Control. Lo veremos más adelante.
Creado el mismo y pulsando Ok, se nos muestra un listado con los proyectos creados hasta el momento. Pulsamos sobre el único que tenemos ;) para acceder a él.

Pulsamos sobre Add Service Namespace.

 

 

En este punto, tenemos que escribir un nombre para el namespace del servicio. Este nombre es público por lo que debemos conocer su disponibilidad en la red. Una vez introducimos el nombre, podemos pulsar en Validate Name para comprobar si está en desuso. Pulsamos en crear y debemos esperar a que el status aparezca Active. Solamente tardará unos segundos.


Una vez queda activado puedes seleccionarlo y visualizar los detalles del mismo:

En los próximos posts, explicaré cómo montar un ejemplo para cada elemento.

¡Saludos!

Posted: 27/11/2009 14:45 por Gisela | con 2 comment(s)
Archivado en: ,
Efectos básicos con JQuery

Para poder mejorar la experiencia de usuario, tenemos a nuestra disposición una serie de efectos listos para usar con JQuery. Es increíble la cantidad de plugins que circulan ya por la red pero, por el momento, me parece importante ir conociendo poco a poco la base de esta gran librería para poder hacer nuestro pinitos más adelante :)

En primer lugar, para no ser repetitiva, comentar que todos los efectos aceptan como parámetro una función de callback, la cual se lanzará una vez haya finalizado la animación. Veremos algunos ejemplos. Además, como primer parámetro, se puede especificar una velocidad para manipular el tiempo que durará la animación. Los valores que aceptan son: slow, normal, fast el tiempo en milisegundos.
Por otro lado, los efectos show, hide y toggle pueden ser invocados sin parámetros, obviando la velocidad de la animación.

  • Show: Muestra aquellos elementos, localizados a través del selector, modificando el estilo de display a block con un tiempo de duración específico.
    $("#btnShow").click(function() {
    $("#divEffect").show("slow", function() { alert("Terminó el efecto show") });
    });

  • Hide: Oculta los elementos seleccionados.
    $("#btnHide").click(function() {
    $("#divEffect").hide();
    });

  • Toggle: Es la función perfecta para no tener que implementar show & hide. En realidad, comprueba el valor de display y realiza la opuesta a la actual. También es posible utilizar una condición que actue de switch donde true muestra todos los elementos involucrados y false los oculta.
    $("#btnToggle").click(function() {
    $("#divEffect").toggle(1500);
    });

  • SlideDown: El efecto consiste en aumentar la altura (height)
    $("#btnSlideDown").click(function() {
    $("#divEffect").slideDown("fast");
    });

  • SlideUp: Produce el efecto contrario que slideDown, disminuyendo la altura de los elementos.
    $("#btnSlideUp").click(function() {
    $("#divEffect").slideUp(3000);
    });

  • SlideToggle: Determina el efecto a realizar entre, slideDown y slideUp.
    $("#btnSlideToggle").click(function() {
    $("#divEffect").slideToggle(200);
    });

  • FadeIn: En este caso, estamos jugando con la opacidad de los elementos. Con fadeIn podemos mostrar uno o varios elementos a la velocidad indicada aumentando la propiedad opacity de su style.
    $("#btnFadeIn").click(function() {
    $("#divEffect").fadeIn("slow");
    });

  • FadeOut: De manera contraria, disminuye la opacidad de los elementos hasta su desaparición.
    $("#btnFadeOut").click(function() {
    $("#divEffect").fadeOut(5000);
    });

  • FadeTo: Si solamente queremos llegar a un grado de opacidad, sin que desaparezca del todo, podemos utilizar fadeTo. Además de utilizar la velocidad como primero, tenemos la posibilidad de pasarle el grado de opacidad que necesitamos para nuestros elementos. Al igual que el resto, tendría un tercer parámetro para la función de callback.
    $("#btnFadeTo").click(function() {
    $("#divEffect").fadeTo(5000, 0.20);
    });

  • Animate: En realidad, si pensamos en todos los efectos anteriores, lo que estamos haciendo es jugar con los estilos de los elementos y, como valor añadido, dándole una velocidad o duración. Si quisiéramos componer nuestro propio efecto o animación la función animate podría ser bastante útil. Existen dos formas de configurar las animaciones: todos los cambios de estilo al unísono o bien de forma secuencial.
    $("#btnAnimate").click(function() {
    $("#divEffect").animate({
    width: "500px",
    height: "400px"
    }, 2000);
    });
    $("#btnAnimateSec").click(function() {
    $("#divEffect").animate({
    width: "200px"
    }, 2000)
    .animate({
    height: "200px"
    }, 2000, function() { alert("Animación finalizada!!") });
    });

  • Stop: Permite detener la animación antes de que finalice.
    $("#btnStop").click(function() {
    $("#divEffect").stop();
    });

  • jQuery.fx.off: Si actualizamos la siguiente variable global a true, deshabilitamos todas las animaciones de nuestra aplicación. Esto no significa que el cambio de estilo no se lleve a cabo pero no se tendrá en cuenta la velocidad del efecto.
    $("#btnAnimationOff").click(function() {
    jQuery.fx.off = true;
    });
    $("#btnAnimationOn").click(function() {
    jQuery.fx.off = false;
    });


Os dejo el proyecto con todas las demos de este post ;)

¡Saludos!

Posted: 24/11/2009 21:40 por Gisela | con 4 comment(s) |
Archivado en:
MAD.NUG: "A rey muerto rey puesto ó que hay de nuevo en Visual Studio 2010"

En esta ocasión, tengo el placer de anunciar el próximo evento de MAD.NUG sobre las nuevas funcionalidades de Visual Studio 2010 orientadas al mundo de ALM y los cambios en los nombres de los productos, donde la principal novedad es la desaparición del nombre de Team System.
Podéis registraros en el siguiente enlace. El evento será de la mano de Bruno Capuano y Luis Fraile el jueves de la semana que viene :)

¡Esperamos veros por allí!

¡Saludos!

Posted: 19/11/2009 0:00 por Gisela | con 4 comment(s) |
Archivado en:
Las Vistas de ASP.NET MVC

Cuando creamos un controlador y asignamos una vista, automáticamente se genera una carpeta en el apartado Views, con el nombre del controlador, sin Controller,  y cada una de las vistas generadas  con el nombre de la acción (por convención) que hemos elegido al crearla.

Si añadimos la vista de forma automática con el cuadro de diálogo "Add View", el código se generará en función de lo que hayamos señalado en la ventana de creación. Existen varias opciones:


Aún así, debemos conocer la forma de generar el contenido de nuestras propias vistas, ya que en más de una ocasión será necesario cambiar totalmente el look que nos ofrecen en la plantilla. En este post solamente vamos a hablar de la versión ASP.NET MVC 1.0 que es la que se encuentra en release actualmente. Posteriormente, me gustaría centrarme en las mejoras que se están presentando en las previews de ASP.NET MVC 2.

Puntos a tener en cuenta:

  1. No existen los controles como tal de WebForms (Los controles no son de servidor, se acabó el runat = "server").
  2. Tenemos la posibilidad de utilizar helpers para generar una serie de elementos estándar (textbox, radiobuttons, formularios, etc.)
  3. No existe el ViewState.
  4. Disponemos de dos mecanismos para recuperar datos del servidor (Model y ViewData).
  5. Recuperamos el uso de las etiquetas <% %> (antiguo ASP)


CONTROLES EN MVC


Si en una vista cualquiera ponemos la sentencia <%=Html. + Control + J , podemos ver una serie de helpers que nos ayudarán a simplificar el código. Los controles estándar podrían ser los siguientes:

  • ActionLink: Renderiza una referencia a la cual debemos pasarle, al menos, el texto que figurará en el link y la acción que necesitamos invocar. Se entiende que la acción que le estamos imponiendo es una del mismo controlador (Dentro de su contexto).
    <%= Html.ActionLink("Create New", "Create") %>

    Otro caso muy común sería pasarle además el Id de un registro que queremos modificar, ver el detalle, etc.

    <%= Html.ActionLink("Details", "Details", new {  id=item.Id })%>
  • RouteLink: Es similar al helper anterior salvo que se utiliza como parámetro el nombre de la ruta en vez del nombre de la acción que queremos invocar. Se puede utilizar para redirigirnos a un controlador distinto desde una referencia.
    <%=Html.RouteLink("Cambio de controlador","NombreDeLaRuta") %>
  • BeginForm: Renderiza un formulario al cual podemos indicarle qué acción lo va a procesar de nuestro controlador, el controlador donde se encuentra, el verbo que va a utilizar en la llamada al servidor (sólo admite GET y POST), etc.
    <%=Html.BeginForm( "Accion","Controlador",FormMethod.Post){ %>
  • BeginRouteForm: Funciona de la misma manera que BeginForm pero en este caso podemos especificar el nombre de la ruta.
    <%=Html.BeginRouteForm("NombreDeLaRuta") %>
  • RenderPartial: Se le pasa como parámetro el nombre de una vista parcial para poder visualizarla (renderizarla) dentro de la vista actual.
    <% Html.RenderPartial("LogOnUserControl"); %>

Además, dentro de Html, también disponemos de controles básicos como Textbox, DropDownList, TextArea, etcétera, los cuales no tienen mayor complicación.

Ok, tenemos los controles más básicos y en muchas ocasiones son suficientes, pero... ¿Qué pasa si necesitamos algún control que no esté por defecto? Sería tan fácil como utilizar Extension Methods e implementar un nuevo control utilizando por ejemplo TagBuilder.

using System.Web.Mvc;
using System.Web.Routing;

namespace HelpersMVC.Helpers
{
public static class CustomHelpers
{
public static string ImageLink(this HtmlHelper htmlHelper, string id, string controller,string action, string image, object attributes)
{
var tagBuilder = new TagBuilder("a");
var tagBuilderImg = new TagBuilder("img");
tagBuilderImg.MergeAttribute("src",image);
tagBuilder.GenerateId(id);
tagBuilder.MergeAttribute("href", controller + "/" + action);
tagBuilder.InnerHtml = tagBuilderImg.ToString();
tagBuilder.MergeAttributes(new RouteValueDictionary(attributes));
return tagBuilder.ToString();
}
}
}

En este caso, en pocos minutos, puedo crearme un nuevo control que está compuesto por una referencia y una imagen... Nada nuevo la verdad :)

Por último, existen dos propiedades que nos serán de utilidad a la hora de pasar información entre el controlador y la vista:

  • Model: Cuando creamos una vista fuertemente tipada, la propiedad Model es casteada al tipo seleccionado. De tal manera que, si yo especifico que mi vista va a ser fuertemente tipada con la clase Movie, y retornamos un objeto de este tipo en la acción del controlador, la propiedad Model será rellenada con los datos del objeto en cuestión. En el caso de que queramos listar un conjunto de objetos de la misma clase, Model será un IEnumerable del objeto. Para ser conscientes en todo momento del tipo que está devolviendo model, podemos fijarnos en el Inherits de la vista en cuestión.
  • ViewData: Hay ocasiones en las que, además de pasar un objeto en concreto utilizando Model, es posible que necesitemos retornar a la vista otro tipo de información. Para ello podemos utilizar ViewData. En realidad, esta propiedad es un diccionario donde podemos meter cualquier tipo de información.

Aún quedan muchas cosas por ver... espero poder ampliar más dentro de poco :)

¡Saludos!

Posted: 18/11/2009 17:00 por Gisela | con no comments
Archivado en:
Controladores de ASP.NET MVC

Los controladores son los elementos que forman la capa que actúa como intermediaria entre el modelo y la vista, en la estructura de un proyecto con ASP.NET MVC.
Podemos usar tanto el ejemplo de NHibernate como el de Entity Framework para este ejemplo.
El objetivo de este post será crear un controlador y conocer la forma de asociar las vistas.
En primer lugar, me gustaría eliminar todos los elementos innecesarios que generó la plantilla de ASP.NET MVC:

  • MovieManager/Controllers/HomeController.cs
  • MovieManager/Controllers/AccountController.cs
  • MovieManager/Views/Home
  • MovieManager/Views/Account
  • MovieManager.Tests/Controllers

La creación de estos archivos se puede realizar de una forma automática. Si hacemos click con el botón derecho sobre la carpeta Controllers y nos posicionamos en la opción Add, podremos ver lo siguiente:


Tenemos una nueva opción para crear el elemento Controlador que, en realidad, es una clase que hereda de Controller . Pulsamos sobre ella para crear uno nuevo.


El nombre de un controlador, por convención, se compone de un nombre personalizado + Controller. Cuando tengamos que referirnos a este elemento en alguna parte del código, solamente utilizaremos para nombrarlo el nombre personalizado. En esta ventana, además, se nos sugiere añadir una serie de Actions por defecto, como pueden ser Crear, Actualizar y Detalles. Seleccionamos el checkbox y pulsamos en Add.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;

namespace MovieManager.Controllers
{
public class MovieController : Controller
{
//
// GET: /Movie/

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

//
// GET: /Movie/Details/5

public ActionResult Details(int id)
{
return View();
}

//
// GET: /Movie/Create

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

//
// POST: /Movie/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
try
{
// TODO: Add insert logic here

return RedirectToAction("Index");
}
catch
{
return View();
}
}

//
// GET: /Movie/Edit/5

public ActionResult Edit(int id)
{
return View();
}

//
// POST: /Movie/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection collection)
{
try
{
// TODO: Add update logic here

return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
}

Este es el código generado por la plantilla, donde solo aparecen una serie de métodos llamados acciones (Actions) los cuales retornan un ActionResult. Existen varios tipos de retorno:

  • ViewResult, renderiza una vista.
  • PartialViewResult, renderiza una vista parcial.
  • RedirectResult, redirige a otra acción del propio controlador.
  • RedirectToRouteResult, redirige a una acción en concreto, especificada en la tabla de rutas, indicando el nombre de la ruta y los parámetro necesarios.
  • ContentResult, devuelve un contenedor definido por el usuario.
  • JsonResult, retorna un objeto JSON.
  • JavaScriptResult, retorna un script para ser ejecutado en el cliente.
  • FileResult, devuelve un archivo como respuesta.
  • EmptyResult, sería equivalente a un resultado nulo.
           

Para mostrar un ejemplo de cómo se implementa una acción, voy a crear las acciones Index y Details.

NHibernate:

//
// GET: /Movie/

public ActionResult Index()
{
var movieRepository = new MovieRepository(MvcApplication.SessionFactory);
return View(movieRepository.ListMovies());
}

//
// GET: /Movie/Details/5

public ActionResult Details(int id)
{
var movieRepository = new MovieRepository(MvcApplication.SessionFactory);
Movie movie = movieRepository.GetMovie(id);
return View(movie);
}

Entity Framework:

//
// GET: /Movie/

public ActionResult Index()
{
var entityFramework = new MovieManagerEntities();
return View(entityFramework.MoviesSet.ToList());
}

//
// GET: /Movie/Details/5

public ActionResult Details(int id)
{
var entityFramework = new MovieManagerEntities();
var movie = (from m in entityFramework.MoviesSet
where m.Id == id
select m).FirstOrDefault();
return View(movie);
}


En  ambos casos estamos devolviendo un ActionResult del tipo Vista, al cual le pasámos como parámetro un objeto(s)  Movie. Para comprender cómo la vista puede interpretar ese objeto, echemos un vistazo a la forma de asociarlas al controlador.


ASOCIACIÓN DE LAS VISTAS

Una vista en ASP.NET MVC corresponde, por convención, a una acción de un controlador. Para crearlas, pulsamos con el botón derecho en una de las acciones.

 

Podemos crear una Vista o bien ir a la que ya tiene asociada. Seleccionamos Add View... para crear una nueva.

Las opciones que nos ofrece son las siguientes:

  • Crear un Partial View, para poder ser reutilizada, para mejorar la experiencia de usuario con AJAX (renderizando solo el contenido de partial view), etc.
  • Crear una vista fuertemente tipada. Significa que nosotros podemos indicarle el tipo de objeto que vamos a mostrar en esta vista. En realidad, la vista heredará del objeto que le digamos.
  • Seleccionar una master page. Por defecto, añadirá la generada por la plantilla en Views/Shared.

En el caso de NHibernate (En Entity framework sería muy similar), selecciono que la clase que voy a utilizar es Movie (MovieManager.Models.Movie). Como Content elijo la opción List, para que me muestre todas las peliculas disponibles. Si en algún momento necesitamos crear una vista con unas características en concreto, podemos seleccionar también Empty para conseguir una vista que herede de la clase pero sin contenido en sí.
Si echamos un vistazo a la cabecera de la vista que vamos a crear sería parecída a la siguiente:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<MovieManager.Models.Objects.Movie>>" %>

Vemos que la vista está heredando de la clase Movie y, como además queremos un listado de todas las películas disponibles, nos añade un IEnumerable.

¿Cómo es posible acceder al listado de películas desde la vista? Para ello utilizamos el objeto Model.

<% foreach (var item in Model) { %>

<tr>
<td>
<%= Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) %> |
<%= Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ })%>
</td>
<td>
<%= Html.Encode(item.Id) %>
</td>
<td>
<%= Html.Encode(item.Name) %>
</td>
<td>
<%= Html.Encode(item.Genre) %>
</td>
<td>
<%= Html.Encode(item.Synopsis) %>
</td>
<td>
<%= Html.Encode(String.Format("{0:g}", item.Year)) %>
</td>
</tr>
<% } %>

El objeto Model está almacenando el objeto(s) del cual está heredando nuestra vista.

Por último, para que la acción Details sea funcional necesitamos modificar las líneas donde se utiliza ActionLink. Podemos eliminar sin problemas la establecida para la acción Edit y modificamos Details de la siguiente manera:

<td>
<%= Html.ActionLink("Details", "Details", new { id=item.Id })%>
</td>

Si ahora arrancaramos la aplicación, no tendría sentido que funcionara.

El motivo es porque, al eliminar todos los archivos innecesarios que nombré al principio, no hemos modificado el controlador que se llamará por defecto al arrancar la aplicación. Nos dirigimos al archivo Global.asax y modificamos la ruta por defecto:

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

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

}

 

¡Saludos!

Posted: 15/11/2009 18:07 por Gisela | con 4 comment(s)
Archivado en:
Cambios en SQL Azure

Desde hace apenas dos días, tenemos a nuestra disposición  Microsoft SQL Server 2008 R2 November CTP. Si bien hace algún tiempo comentaba que existían algunos pequeños impedimentos para conectarse con Management Studio a SQL Azure, ¡Ahora podemos hacerlo sin problemas!
No he tenido tiempo aún de comprobar toda la funcionalidad que se ha podido mejorar, pero voy a comentar cómo es posible conectarnos a partir de ahora a las bases de datos que tenemos en la nube con Management Studio.

En primer lugar, debemos acceder a la página de SQL Azure ya que ha sufrido algún cambio (Se nos pide  aceptar de nuevo los términos de uso).

 

 

Una vez aceptados los términos, nos van a pedir introducir de nuevo las credeciales necesarias para administrar nuestras bases de datos.

 

Pulsamos en Create Server y se nos retorna al inicio del apartado de SQL Azure, donde podemos elegir el proyecto que acabamos de modificar. Si volvemos a entrar, este es el nuevo aspecto:

 


En la parte superior, tenemos los datos necesarios para conectarnos a SQL Azure. Además disponemos de dos botones, uno para resetear la password y el otro para borrar el contenido del servidor (Las bases de datos que hayamos podido crear). Viendo esto, lo primero que se nos ocurre es entrar en el nuevo SQL Management Studio de la R2, introducimos el nombre del servidor, seguido de database.windows.net y nuestras credenciales. El resultado será el siguiente:

 


¿Qué nos está diciendo? "El cliente con la ip XXXXXXXXX no tiene permitido el acceso al servidor." Pues si, una de las nuevas funcionalidades añadidas a esta nueva versión es que disponemos de un firewall, al que le debemos indicar qué ips pueden tener acceso a la administración de nuestro servidor de SQL Azure.

Si volvemos a la página web, vemos que efectivamente tenemos una pestaña llamada Firewall Settings donde podemos añadir reglas. Además aparece un checkbox que permite a Microsoft Service acceder también al servidor. Esta última parte, por el momento, sé que se puede utilizar para testear la conexión desde la web.

Así pues seleccionamos  Add Rule.

Podemos añadir un rango de ips o simplemente añadir la misma tanto al principio como al final. El nombre debe ser un nombre descriptivo para saber a qué lugar pertenece esa regla. Nos avisa de que aplicarla tardará unos 5 minutos hasta que la misma tenga efecto, y por lo que he podido comprobar es cierto ;)

Probamos de nuevo en Management Studio y efectivamente podemos acceder sin problemas, el explorador de objetos está funcionando y hasta aquí es lo que he podido comprobar por el momento.

Espero que os sirva,

¡Saludos!

Posted: 13/11/2009 16:59 por Gisela | con 6 comment(s)
Archivado en:
Los eventos en JQuery

Los enlaces a los eventos en JQuery son en realidad una composición de los selectores y una llamada a uno de los  métodos de esta librería, que nos ayudan a asignar uno o varios eventos, para uno o varios elementos, a la función o funciones especificadas.
Antes de mostrar la forma de asignar los eventos, me gustaría que se tuvieran presentes dos puntos:

  1. Para que estos bindeos sean efectivos, necesitamos ubicarlos en una función que los lance al comienzo de la aplicación, o bien en un momento determinado donde adquieran esa funcionalidad. Por norma general, si queremos manejar los eventos al comienzo de la aplicación, podemos utilizar a su vez el evento ready, el cual ejecuta la función enlazada una vez que el DOM esté listo (se haya terminado de cargar la página).
  2. $(document).ready(function() {

    $("span").text("La pagina ya esta cargada");
    })

  3. Existen dos formas de indicar qué función que queremos que se ejecute: Podemos crear una función anónima, la cual es definida en el momento del bindeo y por lo tanto no es necesario asignarle un nombre específico, o bien podemos escribir el nombre de la función que queremos que se lance en esa determinada acción y ubicar el comportamiento en otro lugar.
  4. $(document).ready(function() {

    alert("Esto es una función anónima")
    })

    $(document).ready(funcionConNombre);

    function funcionConNombre() {

    alert("Esto es una funcion declarada");
    }


Una vez comentado esto, podemos comenzar a ver las distintas funciones de bindeo :)
Con esta librería, existen varias formas de enlazar un elemento, o varios, a uno o más eventos:

  • Bind: Podemos asignar cualquier evento existente (onclick, onblur, etc.) a todos los elementos devueltos por el selector utilizado.
  • <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    var cont = 0;
    $(document).ready(function() {

    $("#btn").bind("click", function(e) {
    cont++;
    $("span").text(cont);
    })
    });
    </script>
    </head>
    <body>
    <input type="button" value="Bind" id="btn" />
    <br />
    <span></span>
    </body>
    </html>

 Bind acepta eventos personalizados y, además, podemos asignar varios eventos a la vez separados por un espacio.

  • One: La función enlazada al evento elegido solamente se ejecutará una vez.
  • <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    var cont = 0;
    $(document).ready(function() {

    $("#btn").one("click", function(e) {
    cont++;
    $("span").text(cont);
    })
    });
    </script>

    </head>
    <body>
    <input type="button" value="One" id="btn" />
    <br />
    <span></span>
    </body>
    </html>
  • Trigger: Se utiliza para ejecutar eventos desde el código. Si utilizamos trigger para invocar un evento soportado por el navegador, debemos tener en cuenta que ejecutará tanto el que hayamos manejado como el del propio navegador.
  • <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    var cont = 0;
    $(document).ready(function() {

    $("a").bind("dblclick", function(e) {
    $("#btn").trigger("click");
    });
    $("#btn").bind("click", function(e) {
    cont++;
    $("span").text(cont);
    })
    });
    </script>

    </head>
    <body>
    <input type="button" value="Bind" id="btn" />
    <a href="#">Trigger</a>
    <br />
    <span></span>
    </body>
    </html>
  • TriggerHandler: A diferencia del anterior, solamente lanza el evento que tenemos manejando (Si no existe mandaría undefined) y omite el evento por defecto del navegador.
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    var cont = 0;
    $(document).ready(function() {

    $("#textbox").bind("focus", function(e) {
    cont++;
    $("span").text(cont);

    });
    $("#btnTrigger").bind("click", function(e) {
    $("#textbox").trigger("focus");
    })
    $("#btnTriggerHandler").bind("click", function(e) {
    $("#textbox").triggerHandler("focus");
    })
    });
    </script>

    </head>
    <body>
    <input type="button" value="Trigger" id="btnTrigger" />
    <input type="button" value="TriggerHandler" id="btnTriggerHandler" />
    <input type="text" id="textbox" />
    <br />
    <span></span>
    </body>
    </html>

En este ejemplo estamos jugando con el evento focus. Si pulsamos el botón que utiliza la función trigger veremos que el cont rapidamente suma dos y en el segundo caso, con triggerHandler, solamente uno. Además podemos comprobar que con triggerHandler no posiciona el foco en el textbox, a diferencia de trigger.

  • Unbind: Se utiliza para realizar lo opuesto que con bind.
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    var cont = 0;
    $(document).ready(function() {

    $("#btn").bind("click", function(e) {
    cont++;
    $("span").text(cont);
    if (cont > 5) {
    $("#btn").unbind("click");
    }

    });
    });
    </script>
    </head>
    <body>
    <input type="button" value="Unbind" id="btn" />
    <br />
    <span></span>
    </body>
    </html>

  • Live: Esta función en particular permite enlazar eventos a uno o varios elementos como a todos los futuros emparejados con estos primeros. Por el momento, está restringido a los eventos click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, keydown, keypress y keyup y no es soportado por los eventos  blur, focus, mouseenter, mouseleave, change y submit.
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    $(document).ready(function() {
    $("a").live("click", function(e) {
    $(this).before("<a>Otra referencia</a>");
    });
    });
    </script>

    </head>
    <body>
    <a>Una referencia</a>
    <br />
    <span></span>
    </body>
    </html>
  • Nota: En este ejemplo he utilizado before que pertenece al apartado de Manipulación, del cual escribiré más adelante :)

  • Die: Sería el unbind de Live.
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    var cont = 0;
    $(document).ready(function() {

    $("a").live("click", function(e) {
    cont++;
    $(this).before("<a>Otra referencia</a>");
    if (cont > 5)
    $("a").die("click");
    });
    });
    </script>

    </head>
    <body>
    <a>Una referencia</a>
    <br />
    <span></span>
    </body>
    </html>
  • Hover: Simula el posicionamiento sobre un elemento.
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    $(document).ready(function() {

    $("li").hover(function() {
    $(this).css("color", "red");
    });
    });
    </script>

    </head>
    <body>
    <ol>
    <li>Uno</li>
    <li>Dos</li>
    <li>Tres</li>
    <li>Cuatro</li>
    </ol>
    </body>
    </html>
  • Toggle: Podemos usarlo para proporcionar al evento click varias funciones. Se tiene en cuenta el orden en el cual las definimos y la forma de ejecutar cada una de ellas es hacer tantos click como funciones hayamos declarado dentro de toggle.
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JQuery._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></title>

    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js" type="text/javascript"></script>

    <script type="text/javascript">
    $(document).ready(function() {

    $("span").toggle(
    function() {
    $(this).css("backgroundColor", "red");
    },
    function() {
    $(this).css("backgroundColor", "blue");
    },
    function() {
    $(this).css("backgroundColor", "yellow");
    }
    , function() {
    $(this).css("backgroundColor", "white");
    }
    );
    });
    </script>

    </head>
    <body>
    <span>Utilizando Toggle</span>
    </body>
    </html>

Por último, si lo único que necesitamos es enlazar una función a un evento en concreto, similar a como lo podiamos hacer antaño, podemos indicar el nombre del evento y  definir la función. Para este ultimo caso os dejo el enlace de eventos "helpers", además de todos los que he podido nombrar en este post.

¡Saludos!

Posted: 11/11/2009 19:30 por Gisela | con 12 comment(s)
Archivado en:
Entity Framework y ASP.NET MVC

En esta ocasión, y ya que lo prometido es deuda ;), voy a explicar qué pasos son necesarios para utilizar Entity Framework en una aplicación MVC.

Volviendo al ejemplo de NHibernate y MVC, voy a retomarlo para exponer el mismo caso: Una vez que tenemos creado nuestro proyecto y hemos generado la base de datos MovieManager en SQL Server, continuamos con el siguiente paso: Hacemos click con el botón derecho sobre la carpeta Models y seleccionamos la opción Add...



Para poder utilizar Entity Framework, es necesario crear un archivo de tipo ADO.NET Entity Data Model. Con él podremos modificar de una forma visual entidades, relaciones entre ellas, etc. El nombre de este archivo no tiene mayor relevancia por lo que en esta demo quedará con el nombre de Model.edmx.
Cuando lo agregamos, automáticamente aparecerá un asistente que nos ayudará a enlazar el edmx con una base de datos existente o bien con una vacía. En nuestro caso, como ya creamos la base de datos en un post anterior, deberíamos seleccionar la primera opción.


Ahora necesitamos especificar cuál es el servidor al que queremos conectarnos y la base de datos dentro de la instancia elegida. Pulsamos en la siguiente ventana el botón New Connection... y, al menos, debemos escribir el Server Name y seleccionar la base de datos en el combo que se auto recargará más abajo, una vez rellenado el nombre del servidor.


Pulsamos OK y se generará la cadena de conexión de forma automática.


En la parte inferior de esta ventana, tenemos un campo a nuestra disposición donde podemos especificar el nombre de la conexión que acabamos de crear. Este dato será  importante para manipular la base de datos en cuestión a través de nuestro código (Se corresponde con el nombre del objeto que debemos crear para este fin). Pulsamos Next y, para finalizar con el asistente, se nos pide que seleccionemos los objetos que queremos incluir en nuestro modelo.


En este ejemplo, seleccionaré únicamente la tabla Movies y finalizo el asistente. El archivo edmx se abrirá y podremos visualizar las entidades seleccionadas en modo diseño, directamente en Visual Studio, con lo que se conoce como ADO.NET Entity Data Model Designer.


No voy a extenderme mucho más por lo que salvamos el archivo generado y nos dirigimos al controlador Home, donde modificamos el método Index de la siguiente manera:

public ActionResult Index()
{
var entityFramework = new MovieManagerEntities();
return View(entityFramework.MoviesSet.ToList());
}

En realidad el acceso es bastante simple. En la primera línea estamos declarando un objeto de tipo MovieManagerEntities, el cual se corresponde con el nombre que dimos en el asistente a la conexión con la base de datos elegida. Si no recordamos el nombre, podemos obtenerlo de una de las entradas añadidas en la sección connectionStrings del web.config.

<connectionStrings>
<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient"/>
<add name="MovieManagerEntities" connectionString="metadata=res://*/Models.Model.csdl|res://*/Models.Model.ssdl|res://*/Models.Model.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=RETURNGIS\SQLEXPRESS;Initial Catalog=MovieManager;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient"/>
</connectionStrings>

Para finalizar, estamos retornando a View el resultado de MovieSet en forma de lista. ¿Qué es MoviesSet? En la parte de diseño del archivo edmx, teníamos una entidad llamada Movies que se corresponde con la tabla seleccionada de la base de datos. Si seleccionamos la misma en modo diseño comprobamos las propiedades:

 


Entity Set Name
es el nombre de la propiedad con la cual accederemos a la entidad Movies y, Name el propio nombre de la entidad.
Si ejecutamos la aplicación y no hemos modificado las vistas no podremos visualizar el listado que estamos solicitando, lo cual me sugiere que va siendo hora de escribir sobre las Vistas en MVC  :)

¡Saludos!

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!

Posted: 8/11/2009 0:00 por Gisela | con 2 comment(s)
Archivado en:
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!
Posted: 7/11/2009 0:00 por Gisela | con no comments
Archivado en:
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=localhost\sqlexpress;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!

Posted: 4/11/2009 9:30 por Gisela | con 10 comment(s)
Archivado en: ,
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 :D


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=localhost\sqlexpress;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!

Posted: 1/11/2009 15:27 por Gisela | con 13 comment(s)
Archivado en: ,