Como todo programador de ASP.NET sabe, la mayor parte de las API de esta plataforma de desarrollo web están basadas en el modelo de proveedores. Para explicarlo de manera rápida, básicamente esto significa que entre la funcionalidad que el programador utiliza y el almacenamiento relacionado con ésta, existe un elemento intermedio llamado "proveedor" que desacopla ambas partes. De esta manera, si queremos utilizar otro tipo de almacenamiento basta con cambiar el proveedor en la configuración y listo. no es necesario tocar el código en absoluto, por lo que resulta muy cómodo y útil.

El siguiente esquema (sacado de MSDN) ilustra la arquitectura de este modelo:

ModeloProveedores

Como vemos muchos servicios como los de seguridad (Membership y Roles), la personalización (Profile) u otros como el almacenamiento de la sesión o los WebParts, están basados en este modelo, representados por las cajas de la parte superior. Así, la información de los usuarios, los roles, los perfiles, las sesiones, etc.... se pueden almacenar en cualquier ubicación para la que haya un proveedor apropiado: SQL Server, archivos XML, archivos de texto, al memoria del servidor... Lo que une una de estas API de la parte superior con el almacenamiento de la parte inferior son los proveedores, que aparecen en la figura en la franja intermedia. Así, por ejemplo, el proveedor SqlMembershipProvider sirve para almacenar la información de los usuarios en una base de datos SQL Server mientras que el ActiveDirectoryMembershipProvider utiliza el directorio activo como almacenamiento para los usuarios.

Los proveedores más utilizados son los de Sql Server, que nos permiten almacenar los datos en una base de datos de SQL Server 2005 o superior. Es posible escribir proveedores para otros sistemas de gestión de bases de datos relacionales como MySQL por ejemplo, pero básicamente estamos solos para utilizarlos pues no tienen soporte por parte de Microsoft.

Proveedores "universales"

Últimamente hemos visto como se está popularizando el uso de otros sistemas de almacenamiento dentro de la esfera de Microsoft. En concreto uno que toma cada vez más fuerza es SQL Server Azure,la versión en la nube del gestor de datos de Microsoft, que nos permitiría tener accesible para múltiples aplicaciones los datos de nuestros proveedores (por ejemplo una base de datos común de usuarios y roles).

Otro que tiene mucho interés es SQL Server Compact 4.0, la base de datos embebida, compatible con SQL Server, y que viene incluida con Visual Studio 2010. Es una opción ideal para desplegar en un hosting en el caso de aplicaciones que no tengan miles de usuarios ya que toda la información se despliega dentro de un único archivo con extensión .sdf, no necesita licencias ni configuración, no hay que instalar un gestor de datos y además es compatible con SQL Server en cuanto a tipos de datos y consultas, por lo que migrar más tarde a su hermano mayor es "pan comido".

Por defecto ASP.NET no ofrece soporte para ninguno de estos dos gestores de datos. Sin embargo en Junio de 2011 Microsoft liberó una versión alfa de los "ASP.NET Universal Providers". La versión 1.0 real apareció el 19 de agosto, y el mismo día liberaron una versión 1.0.1 que corregía algunos pequeños errores. Estos proveedores universales son una implementación 100% compatible con los proveedores nativos pero que nos permite elegir de manera muy sencilla qué gestor de datos queremos usar para el almacenamiento: SQL Server 2005 o superior (como los nativos), SQL Server Azure o SQL Server Compact.

Obviamente eso de "universal" es un poco exagerado ya que sólo dan soporte para estos tres gestores, pero imagino que Microsoft pretende con ellos dar soporte en el futuro a otros sistemas de almacenamiento. Además sólo implementan las APIs de Membership,Roles, Profile y Session, así que hay que tenerlo en cuenta.

Su principal ventaja es que, en lugar de cambiar el proveedor en la configuración de la aplicación, lo único que necesitas hacer para cambiar el almacén de datos es modificar la cadena de conexión. Al cambiar la cadena de conexión, automáticamente se cambia el almacén de datos. Así, trabajar contra la versión completa de SQL Server, la versión Azure o la Compact es un mero cambio de parámetros de conexión.

Vamos a verlo con un ejemplo.

Añadir los proveedores universales a un proyecto

Para añadir estos proveedores a nuestro proyecto debemos usar el gestor de paquetes integrado en Visual Studio, NuGet. Podemos hacerlo abriendo la línea de comandos de Nuget así:

ProveedoresUniversales_1
Pulsa para aumentar

Y luego escribiendo el comando resaltado en la siguiente figura desde la consola de NuGet:

ProveedoresUniversales_2
Pulsa para aumentar

Si preferimos una interfaz más visual podemos abrir el gestor de paquetes de NuGet (el segundo elemento del menú anterior), y buscar los proveedores universales con el buscador:

ProveedoresUniversales_3
Pulsa para aumentar

Tras instalarlos, sea un método u otro, obtenemos una referencia al ensamblado System.Web.Providers en nuestro proyecto:

ProveedoresUniversales_4

Este ensamblado tiene las clases nuevas que usaremos para sustituir a las nativas. La siguiente tabla muestra la equivalencia entre los proveedores "nativos" y los "universales":

API Proveedor "nativo" Proveedor "universal"
Membership System.Web.Security.SqlMembershipProvider System.Web.Providers.DefaultMembershipProvider
Roles System.Web.Security.SqlRoleProvider System.Web.Providers.DefaultRoleProvider
Profile System.Web.Profile.SqlProfileProvider System.Web.Providers.DefaultProfileProvider
Session Gestionado internamente por ASP.NET System.Web.Providers.DefaultSessionStateProvider

Además la instalación de paquete NuGet introduce unas líneas de configuración nuevas en nuestro web.config para definir los nuevos proveedores:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
    <add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\aspnet.mdf;Integrated Security=True;User Instance=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login.aspx" timeout="2880" />
    </authentication>
    <membership defaultProvider="DefaultMembershipProvider">
      <providers>
        <clear />
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
        <add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
      </providers>
    </membership>
    <profile defaultProvider="DefaultProfileProvider">
      <providers>
        <clear />
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
        <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </profile>
    <roleManager enabled="true" defaultProvider="DefaultRoleProvider">
      <providers>
        <clear />
        <add connectionStringName="ApplicationServices" applicationName="/"
          name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" />
        <add applicationName="/" name="AspNetWindowsTokenRoleProvider"
          type="System.Web.Security.WindowsTokenRoleProvider" />
        <add connectionStringName="DefaultConnection" applicationName="/"
          name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </providers>
    </roleManager>
    <sessionState mode="InProc" customProvider="DefaultSessionProvider">
      <providers>
        <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </sessionState>
  </system.web>
</configuration>

Básicamente redefinen los proveedores nativos y añaden nuevas líneas para os proveedores contenidos en el ensamblado System.Web.Providers.

Hay dos cadenas de conexión que por defecto apuntan a la misma base de datos de SQL Server Express:

  • ApplicationServices: es la cadena de conexión que usaremos en caso de emplear los proveedores nativos. Si nuestra intención es usar los nuevos "universales" entonces podemos borrarla directamente.
  • DefaultConnection: es la que usaremos con los proveedores universales.

Esta última, por defecto, apunta a la base de datos aspnetdb.mdf que se crea automáticamente en la carpeta App_Data por parte de ASP.NET y por lo tanto si no la modificamos obtendremos el mismo comportamiento que los proveedores nativos.

Si quisiésemos emplear una base de datos de Windows Azure bastaría con cambiar la cadena de conexión y poner algo similar a esto:

<add name="DefaultConnection" connectionString="Data Source=miSqlAzure;InitialCatalog=miBBDD;UserID=miUsuario;Password=miClave;Encrypt=true;Trusted_Connection=false;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />

Como vemos es prácticamente idéntica a la cadena de conexión de una base de datos de SQL Server pero cambiando el nombre del servidor por la URL de nuestra instancia de SQL Azure.

Como ejemplo vamos a utilizar SQL Server Compact y veremos la base de datos resultante.

Cambia la cadena de conexión por algo como esto:

<add name="DefaultConnection" connectionString="Data Source=|DataDirectory|\aspnet.sdf" providerName="System.Data.SqlServerCe.4.0" />

Ahora compila la aplicación antes de nada (Menú "Build" y luego "Build nombre de tu proyecto"):

ProveedoresUniversales_5

A continuación pulsa el botón de "Configuración de ASP.NET" en el explorador de soluciones o bien en el menú "Proyecto":

ProveedoresUniversales_6
Pulsa para aumentar

Esto abrirá la aplicación Web de configuración de tu aplicación. Ahora ve a la parte de "Seguridad" y habilita la funcionalidad de "Roles":

ProveedoresUniversales_7
Pulsa para aumentar

Vete a la pestaña "Provider" ("Proveedor" en castellano) y elige la opción "Seleccionar un proveedor diferente para cada características (avanzado)". Verás que cada API tiene asignada el proveedor "Default" que es el universal:

ProveedoresUniversales_8

Vuelve a "Seguridad" y crea un rol o dos, así como un par de usuarios. Cierra la configuración.

En el explorador de soluciones pulsa elbotón de ver todos los archivos y busca dentro de la carpeta "App_Data" un nuevo archivo llamado "aspnet.sdf". Pulsa con el botón derecho sobre éste y elige la opción de "Incluir en el proyecto":

ProveedoresUniversales_9

Ahora ya lo tenemos en el proyecto y cuando lo despleguemos se moverá con él.

Para ver su contenido simplemente haz doble-clic sobre él. Se creará una nueva conexión en el explorador de datos y podremos examinar sus tablas y registros:

ProveedoresUniversales_10
Pulsa para aumentar

Por lo demás podremos utilizar Membership, Roles y Profile de la forma habitual, al igual que todos los controles de Login de la barra de herramientas, etc... sólo que la información en lugar de guardarse en un SQL Server convencional podrá almacenarse en SQL Server Azure o en SQL Server Compact.

Esperemos que más adelante Microsoft ofrezca más APIs y más opciones de almacenamiento, pero este es un buen primer paso en el buen camino.

¡Espero que te resulte útil!

💪🏻 ¿Este post te ha ayudado?, ¿has aprendido algo nuevo?
Pues NO te pido que me invites a un café... Te pido algo más fácil y mucho mejor

Escrito por un humano, no por una IA