Category Archives: ASP.NET MVC

[ASPNET MVC] Redirect tipado con MVC Futures

Hola a todos, un problema común cuando en una acción en MVC se requiere hacer una redirección hacia una acción de un determinado controlador es que el método RedirectToAction(…) trabaja con cadenas de texto, por lo tanto es muy sensible a errores, ya que podemos escribir mal ya sea el nombre de la acción y/o el nombre del controlador, y dicho error solo podemos determinarlo en tiempo de ejecución.

Por ejemplo, si tenemos el siguiente controlador:

public class HomeController : Controller
{
	public ActionResult Index()
	{
		return RedirectToAction("Contacto", "Home");
	}

	public ActionResult Contact()
	{
		return View();
	}
}

Vamos a tener un problema cuando se ejecute RedirectToAction(“Contacto”, “Home”); ya que el nombre de la acción está mal escrita y en runtime obtenemos el siguiente error:

mvcfutures
Para solucionar dicho problema, MVC Futures nos da la posibilidad de tener en tiempo de compilación detección de ese tipo de problemas además de intellisense, lo primero es instalar el paquete usando Nuget con el siguiente comando:

PM> Install-Package Microsoft.AspNet.Mvc.Futures

Una vez instalado, referenciamos el namespace Microsoft.Web.Mvc y a continuación ya tenemos disponible un RedirectToAction tipado, reescribiendo entonces ahora tenemos:

return this.RedirectToAction<HomeController>(c => c.Contact());  

Y como les comente antes, también tenemos intellisense:

mvcfutures1

Importante: MVC Futures es desarrollador por el equipo de MVC más no está oficialmente soportado, el mensaje del sitio Nuget del paquete:

ASP.NET MVC Futures includes unsupported prototype features for ASP.NET MVC, from the MVC team.

Personalmente he utilizado el paquete varias veces y no he tenido problemas hasta el momento, así que espero les sea de utilidad.

Saludos!

[ASPNET MVC] Personalizando helpers en ASPNET MVC

Hola, anteriormente vimos como es posible personalizar las pantillas tanto para ASPNET MVC como para Web API, así que hoy vamos a ver como personalizar los helpers en MVC, para que cumplan mejor con lo que nuestra aplicación requiere y revisaremos par opciones para llevar a cabo dicha personalización.

Los helpers son una excelente característica cuando trabajamos con ASPNET MVC los cuales permiten generar un determinado HTML que pueda ser enlazado con una propiedad de una clase por ejemplo, sin embargo en algunas ocasiones puede ser necesario personalizar el HTML que es generado por algún determinado helper o crear uno nuevo.

Para iniciar, creamos un nuevo proyecto Web (para el ejemplo he seleccionado la plantilla en blanco y adicionado únicamente la referencia a MVC) y luego una sencilla clase que será el modelo:

public class Author
{
	public int Id { get; set; }

	public string Name { get; set; }

	public string LastName { get; set; }

	public string Bio { get; set; }

	[DataType("Gender")]
	public string Gender { get; set; }
}

Ahora, creamos un controlador AuthorsController utilizando la plantilla que crea las acciones y las vistas usando Entity Framework, desde ahora solo vamos a trabajar con la vista Create.cshtml.

Los helpers generan el HTML basado en el tipo de dato del campo, por lo tanto vamos a personalizar la plantilla para el tipo cadena (string), para ello creamos una carpeta llamada EditorTemplates en la ruta Views/Shared, y allí agregamos una vista parcial llamada String.cshtml, el código de dicha vista es bastante sencillo:

@model string
@Html.TextBox("",
    ViewData.TemplateInfo.FormattedModelValue,
    htmlAttributes: new { @class = "form-control" })

En la vista anterior el primer parámetro hace referencia al nombre del campo, el segundo al y para no estar repitiendo la clase css asociada en cada helper, acá la dejamos centralizada, entonces pasamos de tener un helper:

@Html.EditorFor(model => model.Name, 
	new { htmlAttributes = new { @class = "form-control" } })

a tener:

@Html.EditorFor(model => model.Name)

El helper ya no tiene la necesidad de referenciar/definir la clase css asociada.

Ahora vamos a ver otra posible forma de cambiar el HTML generado, en el modelo se ha definido una propiedad con el nombre Bio, dicha propiedad puede tener bastantes caracteres, por lo cual necesitamos hacer uso de una caja de texto multilinea, así que primero agregamos una nueva vista parcial con el nombre TextArea.cshtml dentro de EditorTemplates con el siguiente código:

@model string
@Html.TextArea("", 
    ViewData.TemplateInfo.FormattedModelValue.ToString(),
    htmlAttributes: new { @class = "form-control", rows = 10 })

Muy parecido al creado anteriormente, sin embargo hemos añadido la propiedad rows = 10 para que sea más alto el campo, ahora para que el helper EditorFor relacionado a la propiedad Bio haga uso de la plantilla creada, utilizamos una de las sobrecargas de dicho helper la cual permite establecer el nombre de la plantilla a usar, en este caso TextArea:

@Html.EditorFor(model => model.Bio, "TextArea")

Y para finalizar, otra forma para personalizar la plantilla a utilizar es definiendo un tipo de dato diferente en la propiedad, como en el caso de la propiedad Gender que se ha decorado con el atributo DataType(“Gender”) y creando una vista parcial llamada Gender.cshtml, el código de dicha vista parcial es:

@model string
@{
    var options = new List<string>() { "Male", "Female" };
}
@Html.DropDownList("", new SelectList(options), htmlAttributes: new { @class = "form-control" })

La vista anterior simplemente crea un combo para seleccionar el género con dos posibles valores.

Finalmente, la vista se ve correctamente:

customhelpers

Espero el post sea interesante y no te olvides de compartir!

Saludos!

[ASP.NET] Personalización de plantillas en MVC y Web API

Hola a todos, hoy quiero mostrar un pequeño “tip” con el cual es posible personalizar los templates que usamos tanto en ASP.NET MVC y Web API para que se adecuen más a lo que necesitamos.

Por ejemplo, es bastante común que se defina una clase base de la cual hereden los controladores, dicha clase base es la que hereda de Controller para MVC o de ApiController cuando es Web API.

Lo primero es que vamos a crear una clase base llamada BaseController, la cual para el demo solo va a hereder de Controller pero puedes tener objetos que requieras en todos tus controladores:

public abstract class BaseController : Controller {}

Luego de definir la clase, creamos una nueva carpeta llamada CodeTemplates en la cual vamos a tener la pantilla personalizada. Ahora, debemos ir a la ruta de instalación de Visual Studio y allí buscar las plantillas, generalmente la ruta es: C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates, allí por cada plantilla existe una carpeta que contiene la definición tanto C# como para Visual Basic del template, dichos archivos son plantillas T4.

Para el ejemplo vamos a personalizar la plantilla que genera un  MVC Controller vacío, para ello copiamos la carpeta MvcControllerEmpty a la carpeta CodeTemplates que creamos en el punto anterior, como vamos a seguir usando C# podemos eliminar de nuestro proyecto la plantilla que corresponde a Visual Basic, es decir el archivo Controller.vb.t4, la solución se debe ver:

customtemplates

Ahora, para personalizar la plantilla abrimos el archivo T4 que inicialmente luce:

<#@ template language="C#" HostSpecific="True" #>
<#@ output extension="cs" #>
<#@ parameter type="System.String" name="ControllerName" #>
<#@ parameter type="System.String" name="ControllerRootName" #>
<#@ parameter type="System.String" name="Namespace" #>
<#@ parameter type="System.String" name="AreaName" #>
<#
string routePrefix;
if (String.IsNullOrEmpty(AreaName))
{
    routePrefix = ControllerRootName;
}
else
{
    routePrefix = AreaName + "/" + ControllerRootName;
}
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace <#= Namespace #>
{
    public class <#= ControllerName #> : Controller
    {
        // GET: <#= routePrefix #>
        public ActionResult Index()
        {
            return View();
        }
    }
}

Los cambios que vamos a hacer son:

  • Cambiar la clase para que hereden de BaseController
  • Añadir el atributo [Authorize] al controlador
  • A la acción Index añadirle los atributos [HttpGet] y [AllowAnonymous]

Luego de implementar los cambios anteriores la T4 se ve como:

<#@ template language="C#" HostSpecific="True" #>
<#@ output extension="cs" #>
<#@ parameter type="System.String" name="ControllerName" #>
<#@ parameter type="System.String" name="ControllerRootName" #>
<#@ parameter type="System.String" name="Namespace" #>
<#@ parameter type="System.String" name="AreaName" #>
<#
string routePrefix;
if (String.IsNullOrEmpty(AreaName))
{
    routePrefix = ControllerRootName;
}
else
{
    routePrefix = AreaName + "/" + ControllerRootName;
}
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace <#= Namespace #>
{
	[Authorize]
    public class <#= ControllerName #> : BaseController
    {
        [HttpGet]
		[AllowAnonymous]
        public ActionResult Index()
        {
            return View();
        }
    }
}

Para validar que los cambios sean correctos, añadimos un nuevo controlador usando la plantilla  MVC 5 Controller – Empty:

customtemplates2

Luego asignamos un nombre al controlador, una vez finalizado el proceso lo que tenemos es un nuevo controlador que tiene los cambios realizados sobre la plantilla:

[Authorize]
public class HomeController : BaseController
{
	[HttpGet]
	[AllowAnonymous]
	public ActionResult Index()
	{
		return View();
	}
}

Espero el post les sea interesante y no te olvides de compartir!

Saludos!

[ASP.NET MVC] Crear un helper en ASP.NET MVC

Hola a todos, hace un buen tiempo escribí un post sobre como es posible encapsular lógica en helpers, y en esa ocasión básicamente se creo un método de extensión (mira el post acá), así que en esta ocasión la idea es crear un helper aprovechando razor.

La idea es crear un sencillo helper que permita renderizar video aprovechando HTML5, así que lo primero es crear una nueva vista en la carpeta App_Code, vamos a llamarla VideoHelper.cshtml:

helpers1

Ahora el código de la vista, para definir hacemos uso de @helper, luego el nombre del helper, los parámetros que recibe y finalmente el html que vamos a generar, noten que para usar los parámetros se debe usar la @:

@helper Video(string id, string src, bool autoplay, bool controls)
{
    <video id="@id" src="@src"
		autoplay="@autoplay" controls="@controls">                                                                                                                                                                                                               ">
    </video>
}

Y finalmente para hacer uso del helper, desde cualquier vista:

@VideoHelper.Video("video1", "/Videos/simpsons.mp4", true, false)

Espero les sea de utilidad, saludos!

[ASP.NET MVC] Llamando métodos con WebActivator

Hola a a todos, generalmente cuando se necesita ejecutar algún método al inicio de alguna aplicación se hace uso del método Application_Start del Global.asax, adicionalmente a esa opción es posible utilizar WebActivator que permite hacer el llamado a un método en tres diferentes momentos:

  • PreApplicationStartMethod
  • PostApplicationStartMethod
  • ApplicationShutdownMethodAttribute

Para crear una clase con WebActivator, lo primero es añadir el paquete WebActivator mediante Nuget:

WebActivator1

Luego de agregar el paquete, agregamos una clase en el folder App_Start, para el demo la he llamado TestWebActivator, con tres sencillos métodos:

public class TestWebActivator
{
	public static void Start()
	{
		Debug.Write("Pre applicayion start");
	}

	public static void Started()
	{
		Debug.Write("Post application start");
	}

	public static void Shutdown()
	{
		Debug.Write("Application shutdown");
	}
}

Y ahora, para que esos métodos puedan ser llamados mediante WebActivator, antes del namespace definimos el evento y la función asociada:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(TestWebActivator), "Start")]
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(TestWebActivator), "Started")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(TestWebActivator), "Shutdown")]

Finalmente la clase quedaría:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(TestWebActivator), "Start")]
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(TestWebActivator), "Started")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(TestWebActivator), "Shutdown")]

namespace WebActivatorClass
{
    public class TestWebActivator
    {
        public static void Start()
        {
            Debug.Write("Pre applicayion start");
        }

        public static void Started()
        {
            Debug.Write("Post application start");
        }

        public static void Shutdown()
        {
            Debug.Write("Application shutdown");
        }
    }
}

Y eso es todo, espero les sea de utilidad, saludos!

[ASP.NET MVC] Iniciando con las plantillas ASP.NET Boilerplate

Hola a todos, una de los temas que más discusión tiene cuando se va a iniciar un proyecto Web es el tipo de aplicación que se va a desarrollar así como la arquitectura sobre la cual se va a construir la aplicación, luego de definir esos puntos comenzamos a crear una estructura básica de nuestra solución, donde generalmente creamos algunos proyectos que casi siempre vamos a utilizar, proyectos y/o componentes como la capa de presentación, el acceso a datos, la lógica de negocio, el dominio y algunos elementos transversales como seguridad, logging, etc.

Adicional a lo anterior, usualmente agregamos algunos componentes/herramientas en cada uno de los proyectos creados con los cuales vamos a trabajar ya sea porque son los que más conocemos, los que más nos gustan, el que esta de moda, en fin, podemos tener un sin fin de motivos para usarlos, algunos de esas herramientas pueden incluir un contenedor de de inyección de dependencias, una herramienta de log para los errores, algunas librerías/framework JavaScript entre otros.

Para solucionar el problema anterior, podemos trabajar con algo que se conoce como plantillas ASP.NET Boilerplate, el cual nos ofrece un marco de trabajo inicial que ya viene con varias características comunes necesarias en la mayoría de los proyectos, así entonces tenemos:

En el lado del servidor:

  • ASP.NET MVC
  • ASP.NET Web API
  • Castle Windsor
  • Log4Net
  • AutoMapper
  • ASP.NET Boilerplate

En el lado cliente:

  • Twitter Bootstrap
  • jQuery
  • jQueryUI
  • jQuery.Validation
  • jQuery.blockUI
  • jQuery.Spinjs
  • Moment.js
  • Modernizr
  • ASP.NET Boilerplate

boilerplate3

Para iniciar a trabajar, debemos ir a la página oficial ASP.NET Boilerplate y lo primero será escoger entre una aplicación de tipo SPA con Angularjs o con Durandaljs (depende lo que más te guste) y una clásica aplicación Web, luego viene la elección del ORM, acá es posible escoger entre Entity Framework o NHibernate, y finalmente el nombre del proyecto, una vez que hemos realizado esos tres sencillos pasos seleccionamos Create My Project:

boilerplate1

Una vez descargo el proyecto, al abrirlo desde Visual Studio vamos a encontrar una aplicación construida que contiene 5 proyectos:

boilerplate2

Y listo, ya tenemos un muy buen punto de partida sobre el cual seguir desarrollando nuestra aplicación, por el momento dejo el post hasta acá, sin embargo publicaré otro sobre como seguir trabajando con este template.

Espero les haya gustado y aprovechen está excelente herramienta, saludos.

[ASP.NET MVC] Integrando ASPNET MVC con MongoLab

 

Hola a todos, en esta ocasión quiero mostrarles como podemos integrar una aplicación Web construida con ASP.NET MVC a una base de datos MongoDB en MongoLab, para la base de datos vamos a hacer uso del Add-in disponible en Microsoft Azure que nos ofrece una opción gratuita de hasta 0.5 Gb de espacio.

Lo primero es activar MongoLab en Microsoft Azure, para ello seleccionamos  New -> Store y allí buscamos MongoLab:

Crear MongoLab en Azure

En la siguiente ventana del wizard seleccionamos el plan gratuito (a menos que requieras mayores features), la suscripción a usar, el nombre y en donde va a estar ubicado:

intromongolab2

Finalmente en la última ventana del wizard solo tenemos que confirmar los datos para activar el servicio, luego en el portal de Azure en la panel de la izquierda escogemos Add-ons y allí vamos a ver el servicio de MongoLab que acabamos de crear:

intromongolab3

Por el momento vamos a dejar hasta ahí la parte de Azure, ahora en el proyecto de ASPNET MVC vamos a agregar una referencia al driver de MongoDB para poder conectarnos a la base de datos creada, para ello podemos buscarlo por el el UI de Nuget:

intromongolab4

O por la consola de Nuget ejecutar Install-Package mongocsharpdriver:

intromongolab5

Para el demo solo vamos a trabajar con una entidad, así que vamos a crearla, en este caso es necesario tener en cuenta que en MongoDB los datos se guardan en formato BSON, y una se sus característica es que el id por defecto es un ObjectId y su nombre es _id, este campo podemos pensar que es como un GUID (espero luego hablar más de MongoDB), por lo anterior el id de la entidad será de tipo string (y no int como se hace generalmente con Entity Framework) y estará decorada con BsonRepresentation(BsonType.ObjectId):

public class Customer
{
	[BsonRepresentation(BsonType.ObjectId)]
	public string Id { get; set; }

	public string Name { get; set; }

	public string Email { get; set; }
}

Ahora vamos a crear una clase llamada AppContext que será la encargada de inicializar el cliente de MongoDB, para luego poder obtener el servidor y finalmente una instancia de MongoDatabase que representa la base de datos, para obtener la cadena de conexión en el porta de Azure, en el item de MongoLab en la parte inferior seleccionar Connection Info y allí podemos ver la cadena de conexión:

Connection Info MongoLab

Y entonces la clase AppContext:

public class AppContext
{
	public MongoDatabase Database;
	readonly string connnectionstring = @"mongodb://DemoMvcMongoLab:z25DOUq0grml4Wy6uLwN3Wlg.ZZWdyGXkxIc0A5Hh0s-@ds045077.mongolab.com:45077/DemoMvcMongoLab";
	readonly string databaseName = "DemoMvcMongoLab";

	public AppContext()
	{
		var mongoClient = new MongoClient(connnectionstring);
		var server = mongoClient.GetServer();
		Database = server.GetDatabase(databaseName);
	}
}

Ahora vamos a crear un controlador con el nombre CustomerController, lo primero en el controlador es que vamos a declarar un objeto que será del tipo AppContext y una variable para trabajar contra la colección de entidades Customer que vamos a tener, la colección va a tener el nombre Customers:

private readonly AppContext context = new AppContext();
private readonly MongoCollection<Customer> customersCollection = null;

public CustomerController()
{
	customersCollection = context.Database.GetCollection<Customer>("Customers");
}

Lo primero que vamos a hacer es la creación, así que añadimos dos acciones Create, una para el método Get y la otra para el método Post, y será en el Post en donde vamos a guardar el nuevo objeto; para generar un nuevo Id utilizamos ObjectId.GenerateNewId().ToString() y finalmente con el método Save de la colección se guarda la entidad:

[HttpGet]
public ActionResult Create()
{
	return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Name,Email")] Customer customer)
{
	customer.Id = ObjectId.GenerateNewId().ToString();
	customersCollection.Save(customer);

	return RedirectToAction("Index");
}

Para validar que la creación fué exitosa, en el portal de Azure tenemos la opción de administrar la base de datos, al seleccionar esa opción se abre el sitio en MongoLab y allí podemos ver la colección Customers y el número de documentos que tiene:

intromongolab7

Al dar click sobre la colección podemos ver los documentos que tiene:

Detalles colección Customers

Listo, ya tenemos la creación funcionando, ahora vamos a crear el método Index en donde vamos a listar todos los customers:

[HttpGet]
public ActionResult Index()
{
	return View(customersCollection.FindAll());
}

Y en la vista efectivamente vemos los documentos almacenados:

Action list

Ahora para ver el detalle de un documento, creamos la acción Details que recibe como parámetro el id del documento, para realizar la búsqueda por el id utilizamos el método FindOneById pero debemos parsear el id a un ObjectId de MongoDB:

[HttpGet]
public ActionResult Details(string id)
{
	if (id == null)
	{
		return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
	}
	Customer customer = customersCollection.FindOneById(ObjectId.Parse(id));
	if (customer == null)
	{
		return HttpNotFound();
	}
	return View(customer);
}

Para eliminar el documento, vamos a tener dos acciones, la primera en donde mostramos el detalle del documento (Get) y la segunda para eliminarlo (Post), aquí hacemos uso del método Remove, si quieren eliminar todos los documentos de la colección se tiene el método RemoveAll:

[HttpGet]
public ActionResult Delete(string id)
{
	if (id == null)
	{
		return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
	}
	Customer customer = customersCollection.FindOneById(ObjectId.Parse(id));
	if (customer == null)
	{
		return HttpNotFound();
	}
	return View(customer);
}

[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(string id)
{
	customersCollection.Remove(Query.EQ("_id",ObjectId.Parse(id)));
	return RedirectToAction("Index");
}

Finalmente solo queda la actualización, de nuevo tenemos dos acciones, una para obtener la información actual del documento y la otra para confirmar la actualización, en la confirmación de la actualización se debe crear un UpdateBuilder con los datos a actualizar, y luego hacer uso del método Update de la colección:

[HttpGet]
public ActionResult Edit(string id)
{
	if (id == null)
	{
		return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
	}
	Customer customer = customersCollection.FindOneById(ObjectId.Parse(id));
	if (customer == null)
	{
		return HttpNotFound();
	}
	return View(customer);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Name,Email")] Customer customer)
{
	var updateBuilder = Update
			.Set("Name", customer.Name)
			.Set("Email", customer.Email);

	customersCollection.Update(Query.EQ("_id", ObjectId.Parse(customer.Id)), updateBuilder);
	return RedirectToAction("Index");
}

Y por fin hemos finalizado el CRUD sobre la entidad Customer.

No olvides que el código del ejemplo lo puedes ver en mi repositorio de GitHub

Espero está introducción les haya gustado y no se olviden de compartirla!

Saludos.

[ASP.NET MVC] Validando modelos con IValidatableObject

Una de las técnicas más conocidas para añadir reglas/validaciones a los modelos cuando trabajamos con ASP.NET MVC es utilizar Data Annotations, no obstante, otra posible opción es utilizar la interfaz IValidatableObject, así entonces nuestro modelo debe implementar dicha interfaz y en el método Validate añadir las validaciones necesarias.

Por ejemplo, partamos de un sencillo modelo:

public class Customer
{
	public int Id { get; set; }

	public string Name { get; set; }

	public string Email { get; set; }

	public int Age { get; set; }
}

Ahora se debe implementar la interfaz IValidatableObject:

public class Customer : IValidatableObject
{
	public int Id { get; set; }

	public string Name { get; set; }

	public string Email { get; set; }

	public int Age { get; set; }

	public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
	{
		throw new NotImplementedException();
	}
}

Y en el método Validate vamos a definir las reglas/validaciones que requiera nuestro modelo:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
	var errors = new List<ValidationResult>();
	if (string.IsNullOrEmpty(Name))
	{
		errors.Add(new ValidationResult("El nombre es requerido"));
	}

	if (string.IsNullOrEmpty(Email))
	{
		errors.Add(new ValidationResult("El email es requerido"));
	}

	if (Age < 18)
	{
		errors.Add(new ValidationResult("Debe tener más de 18 años para poder registrarse"));
	}

	return errors;
}

Y luego al probar efectivamente las reglas se aplican correctamente:

IValidatableObject

Espero les sea de interés y no te olvides compartir!

[ASP.NET MVC] Implementando un CustomUserValidator en ASPNET Identity

Hola, en el post anterior vimos como implementar un CustomPasswordValidation para implementar de reglas de negocio adicionales para el password cuando trabajamos con ASPNET Identity, así que hoy vamos a ver como lo podemos hacer sobre el resto de propiedades del usuario.

Si vamos a la clase IdentityConfig, método Create podemos encontrar la siguiente porción de código

// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
	AllowOnlyAlphanumericUserNames = false,
	RequireUniqueEmail = true
};

Y allí tan solo tenemos dos propiedades disponibles:

  • AllowOnlyAlphanumericUserNames: Si el nombre de usuario solo puede tener letras y números o no.
  • RequireUniqueEmail: Si el email debe ser único o no.

Ahora para poder extender dichas reglas, vamos a crear una clase CustomUserValidation, que debe heredar de UserValidator<T>, donde T es la clase que define las propiedades del usuario, esa hereda de IdentityUser, si quieres ver como es posible agregar nuevas propiedades al usuario revisa el post del crack Eduard TomásCambiar el esquema con ASP.NET Identity.

Luego de tener la clase creada, sobreescribimos el método ValidateAsync y allí usando el objeto item (de tipo ApplicationUser) es posible acceder a las propiedades del usuario y hacer las validaciones respectivas, en el ejemplo solo se valida que el email no tenga test, para que no nos vayan a trollear.

public class CustomUserValidation : UserValidator<ApplicationUser>
{
	public CustomUserValidation(ApplicationUserManager applicationUserManager)
		: base(applicationUserManager)
	{}

	public override async Task<IdentityResult> ValidateAsync(ApplicationUser item)
	{
		IdentityResult result = await base.ValidateAsync(item);
		if (item.Email.ToLower().Contains("test"))
		{
			var errors = result.Errors.ToList();
			errors.Add("Email invalid, this is a serious app!");
			result = new IdentityResult(errors);
		}
		return result;
	}
}

Ahora, volvemos al método Create de IdentityConfig y utilizamos la clase creada anteriormente:

// Configure validation logic for usernames
manager.UserValidator = new Infrastructure.CustomUserValidation(manager)
{
	AllowOnlyAlphanumericUserNames = false,
	RequireUniqueEmail = true
};

Ahora si probamos:

emailvalidation

Espero les sea interesante y no te olvides compartir!

[ASP.NET MVC] Implementando un CustomPasswordValidator en ASPNET Identity

Hola, desde ASP.NET MVC 5 se tiene una nueva opción para el manejo de seguridad en las aplicaciones (si, se ha dejado de lado Membership y Simplemembership) que se conoce ASPNET Identity, el cual tienes varias características interesantes, dentro de ellas una que me parece muy interesante es que ya viene implementada mediante OWIN.

Ahora, es posible setear algunas propiedades básicas para establecer algunas reglas para definir el password, sin embargo si esas opciones no son suficientes siempre podemos extender dicha configuración para que cumpla con nuestra necesidad puntual.

Para ejemplificar vamos a crear una nueva aplicación de tipo ASP.NET Web Application:

webapp

Luego seleccionamos el template MVC y nos aseguramos que en la parte de autenticación se tenga seleccionado Invidual Users Accounts, la idea de usar este template es porque ya tiene implementado ASPNET Identity (pero si quieren luego lo hacemos desde ceros):

template

Una vez creado el proyecto, vamos a ir a App_Start -> IdentityConfig.cs, y en el método Create nos fijamos en la siguiente parte de código:

CODIGO Configure validation logic for passwords

// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
	RequiredLength = 6,
	RequireNonLetterOrDigit = true,
	RequireDigit = true,
	RequireLowercase = true,
	RequireUppercase = true,
};

El código anterior lo que hace es establecer algunas reglas para el password, pero como se ve son limitadas, así que vamos a extender dicha configuración, para ello creamos una clase llamada CustomPasswordValidator, dicha clase debe heredar de PasswordValidator, y alli sobre-escribimos el método ValidateAsync, en dicho método agregamos la validación que nosotros requerimos (para el ejemplo vamos a validar que no se tengan espacios en blanco):

public class CustomPasswordValidator : PasswordValidator
{
	public override async Task<IdentityResult> ValidateAsync(string item)
	{
		var result = await base.ValidateAsync(item);
		if (item.Contains(" ")) {
			var errors = result.Errors.ToList();
			errors.Add("El password no puede contener espacios en blanco");
			result = new IdentityResult(errors);
		}
		return result;
	}
}

Una vez lista la clase con la validación necesaria, volvemos al archivo IdentityConfig, método Create, y en el manager.PasswordValidator ahora usamos la clase personalizada que hemos  creado:

// Configure validation logic for passwords
manager.PasswordValidator = new Infrastructure.CustomPasswordValidator
{
	RequiredLength = 6,
	RequireNonLetterOrDigit = true,
	RequireDigit = true,
	RequireLowercase = true,
	RequireUppercase = true,
};

Y eso es todo, ahora solo es probar, y la siguiente imagen muestra que la lógica si se está cumpliendo:

pass

Espero les sea interesante y no te olvides de compartir!

1 2 3 4