[ASP.NET] Separar los Settings de nuestras librerías de clases en nuestro web.config en archivos individuales y encriptarlos

Vamos a empezar viendo un ejemplo de lo que se pretende para que nos quede más claro. Tenemos la siguiente solución ficticia compuesta por 3 proyectos (La aplicación web y 2 librerías de clases para acceder a diferentes servicios web):

image

Como podéis observar, cada librería de clases tienes su propio fichero de Settings, donde almacenamos por ejemplo la url del servicio y las credenciales en el caso que se necesiten. Por ejemplo vamos a ver como quedaría el fichero de Settings del servicio web de Paypal:

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

<configuration>

    <configSections>

        <sectionGroup name="applicationSettings" 

                      type="System.Configuration.ApplicationSettingsGroup, System,  >

                      Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

            <section name="SettingsExample.WebServices.Paypal.Properties.Settings" 

                     type="System.Configuration.ClientSettingsSection,  

                     System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

                     requirePermission="false" />

        </sectionGroup>

    </configSections>

    <applicationSettings>

        <SettingsExample.WebServices.Paypal.Properties.Settings>

            <setting name="PaypalUser" serializeAs="String">

              <value>paypal</value>

            </setting>

            <setting name="PaypalPassword" serializeAs="String">

                <value>paypal</value>

            </setting>

            <setting name="SettingsExample_WebServices_Paypal_Paypal_AplicacionesWebService"

                serializeAs="String">

                <value>http://www.paypal.com/services/paypal.asmx</value>

            </setting>

        </SettingsExample.WebServices.Paypal.Properties.Settings>

    </applicationSettings>

</configuration>

El siguiente paso una vez terminados las librerías de los servicios sería consumirlas desde nuestra aplicación web de eCommerce y como no, nos harían falta estas Settings en nuestro web.config para que funcionen correctamente.

Lo que mucha gente hace por desconocimiento (Creo yo) es, o bien poner las settings como Embebed Resource de la dll o ponerlas directamente en el Web.Config, haciendo a este crecer en tamaño y complicar su mantenimiento por parte de administradores.

Para mí la solcuión ideal es meter estas Settings en ficheros .config independientes con un nombre descriptivo y hacer referencia a ellos en el Web.config y a continuación vamos a ver como lo hacemos:

Abrimos nuestro Web.Config y localizamos el elemento <configSections> y metemos un nuevo sectionGroup para hacer referencia a nuestros Settings como se muestra en el siguiente código:

 

<sectionGroup name="applicationSettings" 

                    type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, >

                    Culture=neutral, PublicKeyToken=b77a5c561934e089"

        <section name="SettingsExample.WebServices.Paypal.Properties.Settings" 

                 type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0,  

                 Culture=neutral, PublicKeyToken=b77a5c561934e089"

                 requirePermission="false" />

        <section name="SettingsExample.WebServices.Products.Properties.Settings" 

                 type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0,  

                 Culture=neutral, PublicKeyToken=b77a5c561934e089"

                 requirePermission="false" />

      </sectionGroup>

Una vez hecho esto, vamos a añadir nuestro nuevo sectionGroup al Web.Config, haciendo referencia a nuestros ficheros .config especificando el atributo configSource:

<applicationSettings>

  <SettingsExample.WebServices.Paypal.Properties.Settings 

    configSource="PaypalSettings.config" />

  <SettingsExample.WebServices.Products.Properties.Settings 

    configSource="ProductsSettings.config" />

</applicationSettings>

Y por último añadimos los ficheros .config a nuestra aplicación web (Junto con el Web.Config):

PaypalSettings.config

<?xml version="1.0"?>

<SettingsExample.WebServices.Paypal.Properties.Settings>

  <setting name="PaypalUser" serializeAs="String">

    <value>paypal</value>

  </setting>

  <setting name="PaypalPassword" serializeAs="String">

    <value>paypal</value>

  </setting>

  <setting name="SettingsExample_WebServices_Paypal_Paypal_AplicacionesWebService"

      serializeAs="String">

    <value>http://www.paypal.com/services/paypal.asmx</value>

  </setting>

</SettingsExample.WebServices.Paypal.Properties.Settings>

 

Quedando la solución de esta manera:

image

Ahora te dicen:

– ¿Pero los usuarios y contraseñas se ven en el fichero?

A lo que puedes responder:

– No hay problema, vamos que te enseñe a encriptarlos 🙂

Para ello vamos a hacer uso de una utilidad que yo creo que ya es conocida por todos aspnet_regiis

  1. Sí estas en tú máquina de desarrollo (En mi caso) podemos arrancar la consola de VS como administrador (Visual Studio 2008 Command Prompt)
  2. Sí estas en un server de desarrollo, preproducción, producción, depende de la versión de NET que estas ejejcutando y depende de sí es 32 ó 64 bits:

C:WindowsMicrosoft.NETFramework64vXXXXXX (64)

C:WindowsMicrosoft.NETFrameworkvXXXXXX (32)

y ponemos la siguiente instrucción para encriptar la section concreta con ruta física de directorio (Para más información sobre aspnet_regiis):

aspnet_regiis –pef “applicationSettings” “ruta física de tu aplicación web”

image

Y al ejecutar nos fallará:

image

El porque del fallo es que no es una section sino un sectionGroup y por tanto tenemos que especificar la section que queremos encriptar (En este caso el archivo config de Paypal):

image

Vamos a nuestro fichero Paypal.Config y sorpresa:

<?xml version="1.0"?>

<SettingsExample.WebServices.Paypal.Properties.Settings configProtectionProvider="RsaProtectedConfigurationProvider">

  <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"

    xmlns="http://www.w3.org/2001/04/xmlenc#">

    <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />

    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">

      <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">

        <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />

        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">

          <KeyName>Rsa Key</KeyName>

        </KeyInfo>

        <CipherData>

          <CipherValue>ZoeRp7/................=</CipherValue>

        </CipherData>

      </EncryptedKey>

    </KeyInfo>

    <CipherData>

      <CipherValue>/+Pk/AvWFXhTqNFOciGR7A/...........==</CipherValue>

    </CipherData>

  </EncryptedData>

</SettingsExample.WebServices.Paypal.Properties.Settings>

Y para desencriptarlo:

image

 Espero que os sirva 😉

Saludos.

[EntLib 5.0 Validation Block] Validación encadenada de entidades

Una de las cosas que nos ofrece el Validation Block es la posibilidad de validar entidades que a su vez tienen entidades con validaciones que a su vez… vamos una validación encadenada y que es facilmente configurable a través de los siguientes atributos:

  • ObjectValidator –> Una entidad
  • ObjectValidatorCollection –> Una colección de entidades

Y como no, lo mejor es ver un ejemplo sencillo:

namespace ConsoleApplicationValidation

{

    class Order

    {

        public Guid Id { get; set; }

        [ObjectCollectionValidator]

        public List<OrderDetail> OrderDetails { get; set; }

    }

 

    class OrderDetail

    {

        public Guid Id { get; set; }

        [StringLengthValidator(1,100)]

        public string Description { get; set; }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            Order order = new Order

            {

                OrderDetails = new List<OrderDetail>

                {

                    new OrderDetail{

                        Id = Guid.NewGuid()

                    }

                }

            };

 

            Validator validator = ValidationFactory.CreateValidator<Order>();

            ValidationResults results = validator.Validate(order);

 

            Console.WriteLine(results.Count > 0 ? "Not Valid" : "Valid");

            Console.Read();

        }

    }

}

Lo ejecutamos:

image

Para que sea válida la entidad Order, nuestras entidades OrderDetail deben tener una descripción con longitud comprendida entre 1 y 100:

Order order = new Order

{

    OrderDetails = new List<OrderDetail>

    {

        new OrderDetail{

            Id = Guid.NewGuid(),

            Description = "OrderDetail1"

        }

    }

};

image

Intentaré escribir algún artículo con validaciones más complejas 🙂

Un saludo