23/01/09

Creando secciones de configuracion personalizadas en web config

Hola Gente,

En este post implementaremos una clase que administre secciones de configuración personalizadas en el web.config.

Escenario:

Sucede que mi aplicación tiene una parte de los archivos de mapeo(hbm) incrustados y otra parte en una carpeta, esto debido a que los que están en la carpeta contienen consultas nombradas y es un requerimiento personalizar y cambiar esas consultas nombradas sin necesidad de un re-build a la aplicación. 
Ahora mediante el BuildSessionFactory() se cargan automaticamente los archivos de mapeo hbm incrustados y mediante el cfg.AddDirectory(path) cargo los archivos de mapeo que se encuentran dentro de una carpeta. 
Lo que estaba haciendo hasta ahora es crear una clave en el registro y colocar la ruta de la carpeta en la clave de registro , luego leer la clave de registro para obtener el carpeta en donde estan los hbm y el archivo de configuracion de NH (hibernate.cfg.xml para mi caso) 
Sucede que por "seguridad" se ha decidido cambiar esto

Problema: 
Ahora en mi capa de acceso a datos tengo una clase que me administra las sesiones de NH (NhibernateHelper) y obtiene la ruta del archivo de configuracion y ruta de la carpeta de los hbm no incrustados, y construye mis sesiones 
a partir de eso. 
Lo que se  quiere hacer es: Crear una seccion dentro del web.config con dos propiedades, una donde apunte a la ruta de mi archivo de configuracion y otra propiedad donde apunte a mi carpeta que contiene los hbm no 
incrustados. 
Construyendo:

Clase: NHibernateConfigurationSection

Esta clase hereda de ConfigurationSection y ademas es "No heredable" , su trabajo sera administrar las secciones de configuración que yo cree dentro mi web.config

Imports System.Configuration

Public NotInheritable Class NHibernateConfigurationSection

    Inherits ConfigurationSection


    Private Shared _Properties As ConfigurationPropertyCollection

    Private Shared strHibernateFile As New ConfigurationProperty("HibernateFile", GetType(String), "hibernate.cfg.xml", ConfigurationPropertyOptions.IsRequired)

    Private Shared strMappingPath As New ConfigurationProperty("MappingPath", GetType(String), "", ConfigurationPropertyOptions.IsRequired)


    Public Sub New()

        _Properties = New ConfigurationPropertyCollection()

        _Properties.Add(strHibernateFile)

        _Properties.Add(strMappingPath)

    End Sub


    Public Shared ReadOnly Property CurrentConfiguration() As NHibernateConfigurationSection

        Get

            Return CType(ConfigurationManager.GetSection("nh"), NHibernateConfigurationSection)

        End Get

    End Property



    Protected Overrides ReadOnly Property Properties() As ConfigurationPropertyCollection

        Get

            Return _Properties

        End Get

    End Property


    Protected Overrides Function GetRuntimeObject() As Object

        Return MyBase.GetRuntimeObject()

    End Function


    <StringValidator(InvalidCharacters:=" ~!@#$%^&*()[]{}/;'|\", MinLength:=1, MaxLength:=60)> _

    Public Property HibernateFile() As String

        Get

            Return CStr(Me("HibernateFile"))

        End Get

        Set(ByVal value As String)

            Me("HibernateFile") = value

        End Set

    End Property


    <StringValidator(InvalidCharacters:=" ~!@#$%^&*()[]{};'|", MinLength:=1, MaxLength:=60)> _

    Public Property MappingPath() As String

        Get

            Return CStr(Me("MappingPath"))

        End Get

        Set(ByVal value As String)

            Me("Mapping") = value

        End Set

    End Property

End Class

Ahora en Nuestro NhibernateHelper:

Utilizamos la propiedad estatica "CurrentConfiguration" para obtener una instancia de la clase y muy importante esta propiedad apunta directamente al nombre de la seccion que vamos a crear , para nuestro caso "nh"

Public Class NHibernateHelper

Private Const CurrentSessionKey As String = "nhibernate.current_session"

Public Shared SessionFactory As ISessionFactory

Shared Sub New()

Try

Dim cf As NHibernateConfigurationSection = NHibernateConfigurationSection.CurrentConfiguration

log4net.Config.XmlConfigurator.Configure()

Dim cfg As Configuration = New Configuration

cfg.Configure(cf.HibernateFile)

Dim path As New DirectoryInfo(CStr(cf.MappingPath))

cfg.AddDirectory(path)

SessionFactory = cfg.BuildSessionFactory

Catch ex As Exception

Throw New Exception("NHibernate initializacion failed", ex)

End Try

End Sub

...

End Class

En El Web.Config:

<?xml version="1.0" encoding="utf-8"?><configuration>

<configSections>

<section name="nh" type="Demo.NHibernateConfigurationSection,Demo" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true" />

</configSections>

...

<nh HibernateFile="C:\Proyectos\demo\hibernate.cfg.xml" MappingPath="C:\Proyectos\demo\Mappings"/>

</configuration>

Y Listo ahora podemos mover nuestro archivo de configuración y nuestra carpeta que contiene los hbm sin mayor problema , solo nos bastara con  modifcar la ruta en el tag "nh" y listo¡¡¡
Muchas Gracias , espero les haya servido

Jose Fabricio Rojas

PS: Gracias  a Sergio Castillo por la ayuda.

21/01/09

NHibernate: Aplicando Patrones de diseño a una aplicación que utiliza NHibernate – Parte 2

Hola a todos, siguiendo con el post anterior, en este nuevo post implementaremos la Capa de Logica de Negocios de nuestra aplicación de ejemplo.

(*) Los Archivos de mapeo (hbm) lo pueden generar a partir de MyGeneration como es mi caso. en todo caso no los puse en el post anterior.

Bueno regresemos, Al igual que en nuestra capa de datos, donde se implemento abstract factory , en nuestra capa de negocios tambien implementaremos abstrac factory de manera similar.

image

Entonces la implementación seria la siguiente:

La Interfaz IGenericController:

La interfaz declara los metodos genericos para la manipulación de nuestras entiades de negcios.

using System.Collections;
using System.Collections.Generic;

namespace NHBussines
{
public interface IGenericController<T,Id>
{
T FindByid(Id id);

IList<T> FindAll();

IList<T> FindAllOrdered(IList<string> propertyNames);

IList<T> FindByExample(T entity);

IList<T> FindBydExampleOrdered(T entity, IList<string> propertyNames);

IList<T> FindLikeExample(T entity);

IList<T> FindLikeExampleOrdered(T entity, IList<string> propertyNames);

IList<T> FindLikeExampleIgnoreCase(T entity);

IList<T> FindLikeExampleIgnoreCaseOrdered(T entity, IList<string> propertyNames);

IList<T> FindByQuery(string query);

IList<T> FindByQuery(string query, string[] parameters, object[] values);

IList<T> FindByNamedQuery(string query);

IList<T> FindByNamedQuery(string query, string[] parameters, object[] values);

IList FindObjectsByQuery(string query);

IList FindObjectsByNamedQuery(string query);

IList FindObjectsByNamedQuery(string query, string[] parameteres, object[] values);

IList FindObjectsBySQLQuery(string query, string[] parameters, object[] values);

T Save(T entity);

T Update(T entity);

void DeleteById(Id id);

void Delete(T entity);

Id GetMax(string propertyName);
}
}

GenericController:

Implementa la Interfaz IGenericController, atravez del GenericDAO, Tambien implementa el Metodo Instance , como la clase GenericControler es una clase abstracta esta no puede instarciarse utilizando el operador new(), utilizando este Metodo podemos instanciar esta clase abstracta.

Tambien es importante mencionar que para los metodos de CRUD, utilizamos los métodos de transaccionalidad de Nhibernate, estos metodos estan provistos por la clase estatica NHibernateHelper, Estos Metodos son:

BeginTransacction(); Inicializa una transaccion

EndTransacction(); Finaliza la trasaccion y reliza el repectivo commit

RollbackTransacction(); Hace una vuelta atras o rollback a la transaccion.

using System;
using System.Collections.Generic;
using System.Collections;
using NHDao;
using NHDataAccess;
namespace NHBussines
{
public abstract class GenericController<T,Id> : IGenericController<T,Id>
{
private DAOFactory daoFactory = DAOFactory.Instance(DAOFactory.DAO_FACTORY);

public DAOFactory DaoFactory
{
set
{
daoFactory = value;
}
get
{
return daoFactory;
}
}

public IGenericDAO<T, Id> GenericDao { get; set; }

public T FindByid(Id id)
{
return GenericDao.FindByid(id);
}

public IList<T> FindAll()
{
return GenericDao.FindAll();
}

public IList<T> FindAllOrdered(IList<string> propertyNames)
{
return GenericDao.FindAllOrdered(propertyNames);
}

public IList<T> FindByExample(T entity)
{
return GenericDao.FindByExample(entity);
}

public IList<T> FindBydExampleOrdered(T entity, IList<string> propertyNames)
{
return GenericDao.FindBydExampleOrdered(entity, propertyNames);
}

public IList<T> FindLikeExample(T entity)
{
return GenericDao.FindLikeExample(entity);
}

public IList<T> FindLikeExampleOrdered(T entity, IList<string> propertyNames)
{
return GenericDao.FindBydExampleOrdered(entity, propertyNames);
}

public IList<T> FindLikeExampleIgnoreCase(T entity)
{
return GenericDao.FindLikeExampleIgnoreCase(entity);
}

public IList<T> FindLikeExampleIgnoreCaseOrdered(T entity, IList<string> propertyNames)
{
return GenericDao.FindLikeExampleIgnoreCaseOrdered(entity, propertyNames);
}

public IList<T> FindByQuery(string query)
{
return GenericDao.FindByQuery(query);
}

public IList<T> FindByQuery(string query, string[] parameters, object[] values)
{
return GenericDao.FindByQuery(query, parameters, values);
}

public IList<T> FindByNamedQuery(string query)
{
return GenericDao.FindByNamedQuery(query);
}

public IList<T> FindByNamedQuery(string query, string[] parameters, object[] values)
{
return GenericDao.FindByNamedQuery(query, parameters, values);
}

public IList FindObjectsByQuery(string query)
{
return GenericDao.FindObjectsByQuery(query);
}

public IList FindObjectsByNamedQuery(string query)
{
return GenericDao.FindObjectsByNamedQuery(query);
}

public IList FindObjectsByNamedQuery(string query, string[] parameteres, object[] values)
{
return GenericDao.FindObjectsByNamedQuery(query,parameteres,values);
}

public IList FindObjectsBySQLQuery(string query, string[] parameters, object[] values)
{
return GenericDao.FindObjectsBySQLQuery(query, parameters, values);
}

public T Save(T entity)
{
T newEntity;
try
{
NHibernateHelper.BeginTransaction();
newEntity = GenericDao.Save(entity);
NHibernateHelper.EndTransaction();
}
catch (Exception ex)
{
NHibernateHelper.RollBackTransaction();
throw ex;
}
finally
{
NHibernateHelper.CloseSession();
}
return newEntity;
}

public T Update(T entity)
{
T newEntity;
try
{
NHibernateHelper.BeginTransaction();
newEntity = GenericDao.Update(entity);
NHibernateHelper.EndTransaction();
}
catch (Exception ex)
{
NHibernateHelper.RollBackTransaction();
throw ex;
}
finally
{
NHibernateHelper.CloseSession();
}
return newEntity;
}

public void Delete(T entity)
{
try
{
NHibernateHelper.BeginTransaction();
GenericDao.MakeTransient(entity);
NHibernateHelper.EndTransaction();
}
catch (Exception ex)
{
NHibernateHelper.RollBackTransaction();
throw ex;
}
finally
{
NHibernateHelper.CloseSession();
}
}
public void DeleteById(Id id)
{
try
{
NHibernateHelper.BeginTransaction();
GenericDao.MakeTransient(FindByid(id));
NHibernateHelper.EndTransaction();
}
catch (Exception ex)
{
NHibernateHelper.RollBackTransaction();
throw ex;
}
finally
{
NHibernateHelper.CloseSession();
}
}

public Id GetMax(string propertyName)
{
return GenericDao.GetMax(propertyName);
}
}
}

NHBussinessFactory:

Esta clase hereda de la clase BussinessFactory, que es la clase abstracta que provee los metodos abstractos que nos retornan de objetos de nuestras entidades de negocios

using NHBussines.Implementations;
using NHBussines.Interfaces;
namespace NHBussines
{
public class NHBussinesFactory : BussinesFactory
{
public override IRoleController GetRoleController()
{
return new RoleController();
}
public override IUserController GetUserController()
{
return new UserController();
}
public override IUserRoleController GetUserRoleController()
{
return new UserRoleController();
}
}
}

BussinessFactory

using System;
using NHBussines.Interfaces;

namespace NHBussines
{
public abstract class BussinesFactory
{
public static Type BUSSINESS_FACTORY = typeof (NHBussinesFactory);
public static NHBussinesFactory Instance(Type factory)
{
try
{
return (NHBussinesFactory) Activator.CreateInstance(factory);
}
catch (Exception)
{
throw new Exception("No se pudo crear BussinessFactory:"+factory);
}
}
public abstract IRoleController GetRoleController();
public abstract IUserController GetUserController();
public abstract IUserRoleController GetUserRoleController();
}
}

Nuestros Objetos de Negocios: Para nuestro Ejemplo User, UserEntity

image

Interfaz: IUserController

using NHEntity;

namespace NHBussines.Interfaces
{
public interface IUserController : IGenericController<UserEntity, int>
{

}
}

Clase de Negocio: UserController:

using NHBussines.Interfaces;
using NHEntity;

namespace NHBussines.Implementations
{
public class UserController : GenericController<UserEntity, int>, IUserController
{
public UserController()
{
GenericDao = DaoFactory.GetUserDAO();
}
}
}

Así nuestra Factoria de Objetos de Negocios, funciona con el intellisense de Visual Studio:

image

Asi Accedemos a los metodos comunes de nuestra entidad:

image

Espero les haya ayudado con este aporte.

Muchas Gracias.

Jose Fabricio Rojas

Post Similares:
[1] Aplicando Patrones de Diseño a una aplicacion que utiliza NH
[2] Persistencia en .NET

05/01/09

Reunión por mi cumple

Según les comente por MSN o personalmente por motivo de un cumpleaños más, nos estaremos reuniendo con algunos amigos que estamos actualmente en Lima; El Día Miércoles 7 del presente.

Espero que todos puedan asistir.

Lugar: LIBAR.

Dirección: Av.. La Paz 646 Int: 11 Pasaje "El Suche" – MIRAFLORES

PS: Para llegar rápido preguntar por el Pasaje "El Suche" existen varios locales "bohemios" en ese pasaje.

Hora: 8:00 pm

Punto de Encuentro: Parque Kennedy , frente a la calle de las pizzas.(minutos antes de las 8:00 pm)