Blog dedicado a la programación .NET y la informática en general

Entradas etiquetadas como ‘ASP.NET’

Iniciar servicios WCF alojados en IIS Express sin abrir la depuración en VS

Me he topado con algún proyecto web ASP.NET que hacía referencia a un proyecto de librerías WCF. Cuando quería iniciar la aplicación sin asociarlo a la depuración (Ctrl+F5) la aplicación daba error nada más iniciar ya que hacía la llamada correspondiente a uno de los servicios alojados en WCF.

image

Para poder iniciar la aplicación web sin entrar en modo depuración es necesario arrancar los servicios WCF. Aquí voy a explicar un par de formas de hacerlo pero si alguien encuentra alguna más será bienvenido.

Método 1 Amago de referenciar un servicio al proyecto

Este método consiste en hacer un “amago” de referencia a un servicio WCF desde un proyecto antes de lanzar la aplicación sin la depuración, ya que el asistente de las referencias de servicio arranca de forma automática los servicios WCF alojados en el proyecto cuando se navega a ellos.

image

Para que arranque el servicio primero seleciónalo en las direcciones detectadas y luego navega presionando el botón “Ir”.

Cuando se cierre el asistente se mantendrá la aplicación “Host de servicio WCF” y por tanto se podrá lanzar la aplicación ASP.NET sin entrar en el modo depuración.

Método 2 Creando un Acceso Directo

Investigando un poquito más a fondo se puede comprobar que la aplicación “Host de servicio WCF” puede ser invocado de forma manual mediante el ejecutable “WcfSvcHost.exe” ubicado en la carpeta IDE dentro de la instalación de Visual Studio.

Pasándole los parámetros de la ubicación de la dll del proyecto WCF y su fichero de configuración será capaz de lanzarlo sin problemas.

WcfSvcHost.exe /service:<pathToServiceDll> /config:<pathToServiceConfig> [/client:<pathToClientApp>] [/clientArgs:<argumentsToBePassedToClientApp>]

Para mí la forma más sencilla de invocarlo, teniendo en cuenta que va a usarse bastantes veces durante el desarrollo del proyecto, es crear un acceso directo desde el escritorio que pueda invocar directamente los servicios del proyecto. Para ello basta con ir a la localización del fichero “WcfSvcHost.exe” (normalmente en la carpeta C:\Program Files (x86)\Microsoft Visual Studio XX.0\Common7\IDE cambiando la XX por la versión correspondiente) y crearlo el acceso en el escritorio como indico en la imagen.

image

Ahora hay que editarlo para indicarle los parámetros para el arranque del servicio. Os recomiendo cambiar la ruta indicada en “Iniciar En” poniendo la del proyecto, así os ahorraréis espacio a la hora de poner los parámetros de configuración de “WcfSvcHost.exe”.

image

Con esto estaría listo, acordaros de lanzarlo antes de darle al Ctrl+F5 y también de que si depuráis la aplicación cuando se detenga detendrá también los servicios WCF asociados al proyecto.

Anexo I – Cómo depurar un servicio WCF sin pasar por la IU

Y como una cosa lleva a la otra, descubrí con todo esto que existía una aplicación (“WcfTestClient.exe”) que viene muy bien para depurar el código a partir de un servicio WCF sin tener que lanzar la aplicación cliente, lo cual puede ahorrarnos mucho tiempo.

Está ubicado en la misma carpeta que “WcfSvcHost.exe”. Para usarlo bastaría con poner el proyecto WCF como inicio de la depuración. Cuando arranque la depuración se iniciarán los servicios WCF.

Una vez arrancado el modo depuración hay que abrir la aplicación “WcfTestClient.exe” y agregar la ruta web del servicio para poder descubrirlo y usarlo.

image

Se hace doble clic sobre el método a probar y se rellenan los parámetros a lanzar. Antes de invocar al método de WCF habrá que asociar la aplicación con la depuración desde Visual Studio.

image

Una vez hecho se detendrá en los punto de interrupción que se hayan definido en Visual Studio. Lanzar la invocación y depurar.

image

Espero que sea de utilidad, al menos para mí lo es.

Saludos.

Anuncio publicitario

Autenticación con Membership ASP.NET Identity

La autenticación Membership tradicional de ASP.NET tiene algunas limitaciones que ahora gracias a WIF (Windows Identity Foundation) se mejora. No voy a entrar en detalles técnicos y en definiciones ya que estoy introduciéndome en esta tecnología y todavía no estoy capacitado para ello.

Por tanto la intención de estos apuntes son los de mostrar un ejemplo de cómo integrar este tipo de autenticación en una aplicación web vacía, ya que las plantilla que VS2013 incluye traer otro módulos que no tienen por qué servirnos y por tanto es muy útil saber qué necesitamos para implementarlo desde cero sin depender de esta plantilla. Se da por supuesto que se tiene una base de datos SQL Server donde poder realizar las pruebas.

Lo primero es instalar mediante NuGet los siquitentes paquetes:

  • Microsoft ASP.NET Identity EntityFramework
  • Microsoft ASP.NET Identity Owin
  • Microsoft.Owin.Host.SystemWeb

Captura

El segundo paso es modificar el web.config. Para ello previamente debemos tener la cadena de conexión con la BBDD sobre la que se van a hacer las pruebas. Dicha base de datos no tiene porqué tener previamente las tablas de Membership generadas, sino que el mismo aplicativo cuando intenta acceder a éste las crea de forma automática.

Por tanto se agrega la cadena de conexión y se incluye el tag “sessionState” indicándole la cadena de conexión a la que debe conectarse.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- ... -->
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Investigando;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<!-- ... -->
<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" />
</providers>
</sessionState>
</system.web>
</configuration>

El tercer paso es agregar una clase que asocie la aplicación con el tipo de autenticación. Para ello hay que incluir en la raiz de la aplicación una clase llamada “Starup.cs”.

image

El código a incluir puede ser el siguiente:

using Microsoft.Owin;
using Owin;

namespace WebApplication2
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}

Para que funcione también hay que incluir otra clase dentro de la carpeta “App_Start” de la aplicación web:

image

Y que contenta el siguiente código:

using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;

namespace WebApplication2
{
public partial class Startup
{

// Para obtener más información sobre la configuración de la autenticación, visite http://go.microsoft.com/fwlink/?LinkId=301883
public void ConfigureAuth(IAppBuilder app)
{
// Habilitar la aplicación para que use una cookie para almacenar la información del usuario que inició sesión
// y almacenar también información acerca de un usuario que inicie sesión con un proveedor de inicio de sesión de un tercero.
// Es obligatorio si la aplicación permite a los usuarios iniciar sesión
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

// Quitar las marcas de comentario de las líneas siguientes para habilitar el inicio de sesión con proveedores de inicio de sesión de terceros
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");

//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");

//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");

//app.UseGoogleAuthentication();
}
}
}

Se debe tener en cuenta que se ha cambiado el espacio de nombres y se le ha quitado “App_Start”. Y OJO con las rutas que se le están indicando, se supone que luego se van a crear para la autenticación, lo digo por este código –> LoginPath = new PathString(«/Account/Login»).

El cuarto paso va a consistir en comprobar que efectivamente podemos tener acceso a la base de datos y crear usuarios y roles. En este caso se crea una nueva clase para gestionar las identidades. Como se está usando EntityFramework mediante CodeFirst se generará un contexto de acceso, una clase para manejar los usuarios y un gestor de operaciones sobre los mismos. Este código lo podéis sacar de los proyectos plantilla de ASP.NET. El código para gestionar los roles los he obtenido en el siguiente enlace.

La clase quedaría de la siguiente forma:

image

using System;
using WebApplication2.Models;
using System.Collections.Generic;

namespace WebApplication2.Models
{
// Para agregar datos del usuario, agregue más propiedades a su clase de usuario. Visite http://go.microsoft.com/fwlink/?LinkID=317594 para obtener más información.
public class ApplicationUser : IdentityUser
{
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
}

public class UserManager : UserManager<ApplicationUser>
{
public UserManager()
: base(new UserStore<ApplicationUser>(new ApplicationDbContext()))
{
}
}

public class IdentityManager
{
public bool RoleExists(string name)
{
var rm = new RoleManager<IdentityRole>(
new RoleStore<IdentityRole>(new ApplicationDbContext()));
return rm.RoleExists(name);
}

public bool CreateRole(string name)
{
var rm = new RoleManager<IdentityRole>(
new RoleStore<IdentityRole>(new ApplicationDbContext()));
var idResult = rm.Create(new IdentityRole(name));
return idResult.Succeeded;
}

public bool CreateUser(ApplicationUser user, string password)
{
var um = new UserManager<ApplicationUser>(
new UserStore<ApplicationUser>(new ApplicationDbContext()));
var idResult = um.Create(user, password);
return idResult.Succeeded;
}

public bool AddUserToRole(string userId, string roleName)
{
var um = new UserManager<ApplicationUser>(
new UserStore<ApplicationUser>(new ApplicationDbContext()));
var idResult = um.AddToRole(userId, roleName);
return idResult.Succeeded;
}

public void ClearUserRoles(string userId)
{
var um = new UserManager<ApplicationUser>(
new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = um.FindById(userId);
var currentRoles = new List<IdentityUserRole>();
currentRoles.AddRange(user.Roles);
foreach (var role in currentRoles)
{
um.RemoveFromRole(userId, role.Role.Name);
}
}
}
}

namespace WebApplication1
{
public static class IdentityHelper
{
// Se utilizan para XSRF al vincular inicios de sesión externos
public const string XsrfKey = "XsrfId";

public static void SignIn(UserManager manager, ApplicationUser user, bool isPersistent)
{
IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = manager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

public const string ProviderNameKey = "providerName";
public static string GetProviderNameFromRequest(HttpRequest request)
{
return request[ProviderNameKey];
}

public static string GetExternalLoginRedirectUrl(string accountProvider)
{
return "/Account/RegisterExternalLogin?" + ProviderNameKey + "=" + accountProvider;
}

private static bool IsLocalUrl(string url)
{
return !string.IsNullOrEmpty(url) && ((url[0] == '/' && (url.Length == 1 || (url[1] != '/' && url[1] != '\\'))) || (url.Length > 1 && url[0] == '~' && url[1] == '/'));
}

public static void RedirectToReturnUrl(string returnUrl, HttpResponse response)
{
if (!String.IsNullOrEmpty(returnUrl) && IsLocalUrl(returnUrl))
{
response.Redirect(returnUrl);
}
else
{
response.Redirect("~/");
}
}
}
}

Aquí tengo que hacer hincapié en que dentro del código hay referencias a rutas de autenticación que van a ser desarrolladas supuestamente a posteriori y que no se incluye en este ejemplo.

Por último queda consumir esta última clase que se ha construido y comprobar que se han creado correctamente el usuario administrador y su rol correspondiente.

Se agrega en Global.asax.cs el siguiente código:

protected void Session_Start(object sender, EventArgs e)
{
// Comprueba que hay un rol de administrador y un usuario asociado
IdentityManager identMgr = new IdentityManager();
if (!identMgr.RoleExists(ROLADM))
{
identMgr.CreateRole(ROLADM);
var user = new ApplicationUser() { UserName = "Administrador" };
if (identMgr.CreateUser(user, "c1@v3~"))
{
identMgr.AddUserToRole(user.Id, ROLADM);
}
}
}

Para terminar comprobando que una vez que se lanza la aplicación se han creado las tablas de forma automática y se ha generado el usuario y rol correspondientes:

image

He realizado un video con todo el proceso completo, pero la calidad del mismo deja mucho que desear debido al escaso tiempo que le he podido dedicar. Pero como una imagen vale más que mil palabras os lo dejo a vuestra disposición, ya que no disponemos de mucha información en este sentido en español.

Ejemplo de implementación de Membership con ASP.NET Identity

 

Un saludo.

A %d blogueros les gusta esto: