martes, 17 de febrero de 2015
Hace sólo unos días comentábamos la próxima desaparición del Global.asax a partir de ASP.NET Core y su sustitución por la clase Startup
, pero no es esto lo único que va a dejar de acompañarnos durante nuestras andanzas digitales. Como vimos también hace algún tiempo, el nuevo enfoque de ASP.NET hace que se prescindan de muchos elementos que ya no tienen sentido.Y en esta ocasión hablaremos sobre la desaparición del Web.config, el célebre archivo de configuración que lleva con nosotros desde los inicios de ASP.NET. Nacido en momentos en que se pensaba que XML era la panacea y muy ligado al denostado System.Web, ha sido útil durante años para configurar aspectos relativos a la compilación y ejecución de las aplicaciones web en el servidor, así como el “sitio oficial” para introducir de settings como cadenas de conexión y otros valores configurables de nuestros sistemas.
Pero, antes de continuar, un disclaimer: ASP.NET Core está aún en desarrollo, y parte de lo que se diga aquí puede no ser del todo cierto mañana mismo, aunque posiblemente los conceptos fundamentales sí lo serán. O eso espero ;)
Está claro que los tiempos han cambiado: ahora ASP.NET es multiplataforma (tanto en tiempo de ejecución como a la hora de desarrollar sobre él), tenemos a Roslyn proporcionando servicios de compilación sobre la marcha, hay un nuevo modelo de ejecución de peticiones, existen nuevas tendencias, queremos librarnos de System.Web ;) … son demasiados cambios para poder mantener al viejo Web.config y por eso era hora de jubilarlo, o al menos casi totalmente.
Poco más o menos, en las configuraciones que usábamos en un proyecto (y usamos aún a día de hoy) encontramos las siguientes tipologías:
- Settings personalizados o de aplicación, como una cadena de conexión, la dirección de correo a la que vamos a enviar mensajes de notificación, o la clave del API de un servicio externo. Las encontrábamos en la sección
<appSettings>
o en custom settings del Web.config.
- Opciones de compilación que indicaban cómo había de ser compilado el código desplegado al servidor (vistas, código en App_Code, y similares).
- Opciones de servidor y runtime, como los handlers o módulos que procesan las peticiones, opciones de seguridad o de comportamiento del framework.
- Configuraciones destinadas a tiempo de diseño e IDEs, como las referencias del proyecto, los archivos incluidos en el mismo, o el modo de compilación a utilizar durante la build.
Como se puede observar en la captura de pantalla de la derecha, nuestro viejo conocido Web.config ya no existirá en la carpeta raíz de nuestros proyectos, aunque tendremos nuevas fórmulas, mucho más potentes, para introducir las configuraciones:
- Existirán configuraciones de las herramientas, como los archivos de configuración de Bower, Grunt o Npm, aunque cada una de ellas estará normalmente en su propio archivo. En la captura anterior podéis verlas en bower.json, gruntfile.js y package.json respectivamente.
- Todo lo relativo a la compilación del proyecto, lenguajes, referencias, metadatos, frameworks usados, etc., se mueve al archivo project.json, de existencia obligatoria en toda aplicación ASP.NET Core.
- Todo lo relativo al runtime, como los módulos que procesarán las peticiones o configuración de seguridad se desplaza, como ya sabemos, a la clase
Startup
y los middlewares que en ella establezcamos. Es decir, este tipo de configuración se realizará totalmente mediante código en la clase de inicialización.
- Los settings personalizados propios de nuestra aplicación pasarán a definirse en uno o varios archivos de configuración, que podrán encontrarse escritos usando prácticamente cualquier origen, formato o sintaxis, desde archivos locales .json, .ini, .xml u otros, hasta orígenes remotos, bases de datos, o incluso las variables de entorno del equipo en que se ejecute la aplicación.
Project.json
Este archivo, obligatorio en toda aplicación ASP.NET Core, contiene la configuración necesaria para construir, empaquetar y ejecutar el proyecto. En esta dirección de Github podéis encontrar mucho más detalle sobre su contenido, pero a grandes rasgos, encontraremos en él:- Las dependencias con otros paquetes que presenta nuestro proyecto.
- Las configuraciones de compilación disponible (por ejemplo, Debug o Release), con opciones de compilación para cada una de ellas.
- Los frameworks que emplearemos en el proyecto y las referencias a ensamblados incluidas para cada uno de ellos.
- Las carpetas y archivos que contienen código a compilar.
- Dónde se encuentra la carpeta que actuará como “raíz” en el servidor web, normalmente wwwroot.
- Opciones de compilación (defines, versión de lenguaje, etc.) para Roslyn.
- Comandos disponibles en la aplicación.
- Scripts a ejecutar antes o después de la build del sistema.
- Algunos metadatos, como el nombre del proyecto, versión o autor.
Definición de settings personalizados
En los settings personalizados encontramos otras de las grandes novedades de ASP.NET Core, la capacidad de tener múltiples archivos u orígenes de configuración, y prácticamente en cualquier formato.En primer lugar, el hecho de tener más de un archivo de configuración, además de permitirnos “trocear” las configuraciones extensas de forma lógica, va a simplificar y facilitar enormemente la utilización de componentes de terceros. Ya no será necesario, como hasta ahora, retocar nuestro archivo de configuración principal cada vez que instalamos un componente externo, sino que cada componente podrá traer su propio archivo.
La carga de los distintos archivos de configuración se realiza, como no podía ser de otra forma, en la clase
Startup
. La siguiente porción código carga en el constructor de la clase de inicialización los settings contenidos en varios archivos JSON en el que se encuentran los settings de la aplicación:Más adelante veremos un ejemplo de archivo de settings escrito en JSON. De momento, es interesante destacar que si el mismo setting se encuentra en varios archivos de configuración, el último valor será el que prevalezca, en el orden en que los orígenes de datos hayan sido configurados. Podemos usar esta característica para crear una estructura de valores por defecto que puedan ser sobrescritos de forma sencilla sin modificar las configuraciones iniciales.
En segundo lugar, el hecho de que podamos utilizar prácticamente cualquier formato se debe a que el sistema de configuración es muy extensible, lo que abre la puerta a posibilidades que anteriormente eran bastante más difíciles de implementar y, sobre todo, utilizando un interfaz de programación común. En el siguiente código vemos cómo podríamos añadir varios orígenes más de configuración, como un archivo .ini adicional o las variables de entorno del sistema:
Aunque aún están trabajando en ello y podría variar un poco, ASP.NET Core incorpora de momento los siguientes orígenes de configuración:
- Archivos .ini
- Archivos .json
- Archivos .xml
- Parámetros de línea de comandos, si arrancamos la aplicación usando esta opción. Serían parámetros que pasamos en la llamada como “/key=value” o “--key=value”
- Variables de entorno del sistema.
Microsoft.Framework.ConfigurationModel.
IConfigurationSource
y añadiéndolo en la clase de inicialización :)¿Y cómo accedo a los settings desde mi código?
Desde el punto de vista del consumidor, es decir, de los procesos que deben obtener los valores de configuración, por supuesto que no utilizaremosConfigurationManager
ni otras clases ligadas a las versiones anteriores de ASP.NET. El framework nos ofrece un mecanismo genérico mediante el cual podremos acceder a los valores de los settings independientemente del lugar o formato desde donde se hayan obtenido.Para ello, sólo tenemos que usar el método
Get()
de una instancia de IConfiguration
, definido en el espacio de nombres Microsoft.Framework.ConfigurationModel,
que podríamos recibir, por ejemplo, inyectado en el constructor del controlador:El código anterior serviría para obtener el valor del correo electrónico en un archivo de settings creado en formato JSON o INI como se muestra en los cuadros. Observad que para acceder a una propiedad que se encuentra en una sección (como MySettings/Email) se ha utilizado como separador los dos puntos.
Obviamente, para que esto funcione antes tendremos que haber registrado en el contenedor de inyección de dependencias de ASP.NET Core que la instancia de
Configuration
sobre la que hemos añadido los distintos orígenes será la ofrecida cuando se solicite un objeto IConfiguration
, pero eso es harina de otro costal ;)Eh, pero… ¡aún estoy viendo un Web.config al publicar el proyecto!
Efectivamente, así es, y por eso antes hablaba de “jubilación casi total”: al publicar un el proyecto con la herramienta Publish de Visual Studio, o simplemente al empaquetarlo mediante línea de comandos (kpm pack
), se puede ver un bonito Web.config en la carpeta wwwroot
. Esto es así porque hay configuraciones que deben seguir siendo desplegadas y son usadas por servidores como IIS para poder ejecutar correctamente la aplicación. De hecho, si publicamos o empaquetamos un proyecto MVC creado directamente desde la plantilla por defecto, en la carpeta wwwroot encontraremos el Web.config con el siguiente contenido a día de hoy:Son las opciones básicas para que el host pueda ejecutar la aplicación, y es generado automáticamente cada vez que hacemos un despliegue o empaquetamos el proyecto para enviarlo a un servidor.
Aún así, si quisiéramos añadir alguna configuración adicional a este archivo, podemos hacerlo creando un Web.config en la carpeta wwwroot de nuestro proyecto e introduciendo en él únicamente lo que necesitemos. Los procesos de empaquetado lo tendrán en cuenta y lo utilizarán como base a la hora de generar el Web.config que irá finalmente al servidor.
Pero observad que en cualquier caso, este archivo no forma parte del raíz de nuestro proyecto, sino que se encuentra en wwwroot, que, como sabemos, es la carpeta donde se encuentra el contenido estático que subiremos al servidor en ASP.NET Core.
Bueno, y vamos a dejarlo aquí. Espero que este vuelo a vista de pájaro sobre la configuración de aplicaciones ASP.NET Core os sea de utilidad para iros orientando en este nuevo entorno que se avecina.
Publicado en Variable not found.
5 Comentarios:
Buenos días, la pregunta no esta directamente relacionada con el post.
Cree un proyecto asp.net mvc (visual studio 2013) con soporte para web api.
utilizo el membership con owin para mvc, pero trato de utilizarlo de la misma forma en web api, y no funciona.
Después hice un proyecto de solo web api y veo que para el membership usa clases diferentes en la plantilla que crea visual studio.
Hay alguna forma que se pueda utilizar el memebership en web api y mvc en el mismo proyecto?
Gracias
Hola,
en principio deberías poder hacerlo sin problema, pues ambos utilizan la infraestructura Owin/Katana.
Por ejemplo, una vez autenticado el usuario, las cookies viajarán en las peticiones (puedes comprobarlo con Fiddler o network tools del browser) y la información del usuario debería encontrarse en la propiedad User del controlador (Controller/ApiController) sin problema. También deberías poder usar el atributo Authorize (eso sí, cada framework tiene el suyo propio).
Saludos.
Gracias por el tiempo y la respuesta.
Lo que estoy tratando de hacer es registrar un usuario por medio de una petición Post a Web api.
En el código de mvc
se llama esta linea:
var result = await UserManager.CreateAsync(user, model.Password);
para crear el usuario,
pero cuando trato de hacer lo mismo en la acción de web api, no sirve porque en la linea que obtiene el UserManager dice que el objeto HttpContext no existe
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager();
}
private set
{
_userManager = value;
}
}
e importado los paquetes de owin y tampoco reconoce el HttpContext.
Gracias
HttpContext no esta accesible tal cual desde un controlador webapi.
Esto te puede ayudar:
http://stackoverflow.com/questions/24001245/cant-get-usermanager-from-owincontext-in-apicontroller
Saludos.
Buenas tardes,
después de buscar mucho encontré como se hace igual que en mvc
ApplicationUser user = new ApplicationUser { UserName = "asdasd@gmail.com", Email = "asdasd@gmail.com" };
UserManager manager = new UserManager(new UserStore(context));
// el contexto es el que se crea para el membership
manager.Create(user, "123456");
public UserManager UserManager { get; private set; }
Gracias por la ayuda!
Enviar un nuevo comentario