Category Archives: ASP.NET MVC

[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!

[ASP.NET MVC] Implementando el helper chart de Kendo UI

Hola a todos, hoy quiero mostrarles como es de sencillo crear un chart utilizando los helpers de Kendo UI para ASP.NET MVC, lo primero es referenciar la dll Kendo.Mvc:

referencia kendo

Luego los archivos JavaScript y CSS:

css.js.kendo

Creamos los bundles correspondientes en la clase BundleConfig:

bundles.Add(new ScriptBundle(&quot;~/bundles/kendo&quot;).Include(
	&quot;~/Scripts/kendo/kendo.all.min.js&quot;,
	&quot;~/Scripts/kendo/kendo.aspnetmvc.min.js&quot;));

bundles.Add(new StyleBundle(&quot;~/Content/kendocss&quot;).Include(
	&quot;~/Content/kendo.common.min.css&quot;,
	&quot;~/Content/kendo.flat.min.css&quot;,
	&quot;~/Content/kendo.dataviz.flat.min.css&quot;));

Y los referenciamos en la sección head del layout:

@Styles.Render(&quot;~/Content/css&quot;)
@Styles.Render(&quot;~/Content/kendocss&quot;)
@Scripts.Render(&quot;~/bundles/modernizr&quot;)

@Scripts.Render(&quot;~/bundles/jquery&quot;)
@Scripts.Render(&quot;~/bundles/bootstrap&quot;)
@Scripts.Render(&quot;~/bundles/kendo&quot;)

Ahora, un sencillo modelo:

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

	public int Value { get; set; }

	public DateTime Date { get; set; }
}

Luego en el controlador retornamos una colección de elementos:

public class HomeController : Controller
{
	private List&lt;Values&gt; values = new List&lt;Values&gt;()
	{
		new Values (){ Id = 1, Date = DateTime.Now, Value = 10},
		new Values (){ Id = 2, Date = DateTime.Now.AddMinutes(10), Value = 5},
		new Values (){ Id = 2, Date = DateTime.Now.AddMinutes(20), Value = 15},
		new Values (){ Id = 2, Date = DateTime.Now.AddMinutes(30), Value = 0},
		new Values (){ Id = 2, Date = DateTime.Now.AddMinutes(40), Value = 20}
	};

	public ActionResult Index()
	{
		return View(values);
	}
}

Y finalmente la vista:

@using Kendo.Mvc.UI;
@model IEnumerable&lt;KendoUIChartMvcWrapper.Models.Values&gt;

@{
    ViewBag.Title = &quot;Index&quot;;
}

@(Html.Kendo().Chart(Model)
    .Name(&quot;chart&quot;)
    .Title(&quot;Kendo UI Chart&quot;)
    .Legend(legend =&gt; legend
        .Position(ChartLegendPosition.Bottom)
    )
    .ChartArea(chartArea =&gt; chartArea
        .Background(&quot;transparent&quot;)
    )
    .SeriesDefaults(seriesDefaults =&gt;
        seriesDefaults.Line()
    )
    .Series(series =&gt;
    {
        series.Line(model =&gt; model.Value)
            .Name(&quot;Cantidad&quot;)
            .Labels(true)
            .Opacity(0.8);
    })
    .CategoryAxis(axis =&gt; axis
        .Categories(model =&gt; model.Date)
        .MajorGridLines(lines =&gt; lines.Visible(false))
        .Labels(labels =&gt; labels.Rotation(-90))
        .Date()
        .BaseUnitStep(10)
        .MinorGridLines(lines =&gt; lines.Visible(true))
    )
    .Tooltip(tooltip =&gt; tooltip
        .Visible(true)
        .Format(&quot;{0}&quot;)
    )
)

En la vista hacemos uso del helper Html.Kendo().Chart(Model) y simplemente le pasamos el modelo que estamos usando, que en este caso es una colección de elementos, luego solo parametrizamos algunas propiedades del helper como el nombre (Name), el título (Title) entre otras…. y finalmente el resultado:

chart kendo

Espero les sea interesante, saludos!

[ASP.NET MVC] Inyectando dependencias con Microsoft Unity

Hola a todos, en el anterior post (míralo acá) vimos como podemos crear una factoría de controladores personalizada para poder instanciar controladores que tienen un constructor que recibe parámetros, hoy vamos a ver algo muy parecido, solo que en este caso vamos a utilizar un DI Container (contenedor de inyección de dependencias).

El ejemplo, básicamente consiste en que vamos a inyectar un objecto que nos va a permitir escribir en un log, entonces en el controlador tenemos:

public class HomeController : Controller
{
	private ILog log;

	public HomeController(ILog log)
	{
		this.log = log;
	}

	public ActionResult Index()
	{
		log.Log(&quot;Escribiendo en el log&quot;);
		return View();
	}
}

Revisando el anterior código, vemos que HomeController requiere un objeto de tipo ILog, es decir que vamos a poder inyectar cualquier clase que implemente dicha interfaz, recuerden que uno de los principios de la inyección de dependencias es trabajar contra abstracciones y no implementaciones.

Ahora vamos con la interfaz ILog:

public interface ILog
{
	void Log(string str);
}

Y ahora una clase que implementa dicha interfaz (la lógica para el ejemplo no es importante):

public class LogFile : ILog
{
	public void Log(string str)
	{
		Debug.Write(str);
	}
}

Ahora viene lo interesante, como DI Container vamos a utilizar Microsoft Unity, así que añadimos por Nuget el paquete Unity.MVC4:

Unity

La ventaja de añadir dicho paquete es que en la raíz del sitio nos añade la clase Bootstrapper donde vamos a poder registrar los componentes:

public static class Bootstrapper
{
	public static IUnityContainer Initialise()
	{
	  var container = BuildUnityContainer();
	  DependencyResolver.SetResolver(new UnityDependencyResolver(container));

	  return container;
	}

	private static IUnityContainer BuildUnityContainer()
	{
	  var container = new UnityContainer();
	  RegisterTypes(container);

	  return container;
	}

	public static void RegisterTypes(IUnityContainer container) {}
}

Ahora es tiempo de registrar nuestras dependencias, para ello hacemos uso del método RegisterTypes de la clase Bootstrapper, para ello usamos container.RegisterType:

public static void RegisterTypes(IUnityContainer container)
{
	container.RegisterType&lt;ILog, LogFile&gt;();
}

Finalmente solo resta realizar el llamado a nuestro DI Container, en este caso usamos el evento Application_Start del Global.asax:

protected void Application_Start()
{
	AreaRegistration.RegisterAllAreas();
	FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
	RouteConfig.RegisterRoutes(RouteTable.Routes);
	BundleConfig.RegisterBundles(BundleTable.Bundles);

	Bootstrapper.Initialise();
}

Y eso es todo, la dependecia es inyectada gracias al uso del DI Container!

[ASP.NET MVC] Creando una factoria de controladores personalizada

Hola a todos, como ya sabemos, un controlador en ASP.NET MVC no es más que una clase, la cual hereda de la clase Controller, sin embargo dicha clase no tiene un constructor definido, o bueno no al menos uno que podamos ver, dicho esto cuando una clase no tiene un constructor definido (o varios) por defecto si se tiene un constructor para esa clase que no recibe parámetros, ahora bien, en MVC tenemos algo que se conoce como factoría de controladores, cuya principal función es inicializar los controladores usando ese constructor vacío que todos tienen…y de que va todo esto? simple, que pasa cuando tenemos un controlador pero este requiere un constructor personalizado? Por ejemplo, si tenemos el siguiente controlador con un constructor personalizado:

public class HomeController : Controller
{
	private string username = string.Empty;
	public HomeController(string username)
	{
		this.username = username;
	}
}

Ahora si intentamos ejecutar, vamos a obtener el siguiente error:

controllererror

El error anterior se da porque el controlador no tiene un constructor sin parámetros por lo tanto no es posible inicializarlo. Pero y el constructor vacío que tienen todas las clases? Bueno, pues resulta que eso solo aplica cuando no se ha definido ningún constructor en la clase, y como nuestro controlador le definimos uno el otro ahora si desaparece.

Debido al problema anterior, necesitamos definir una nueva forma de inicializar el controlador HomeController y pasarle el parámetro que requiere, y para ello podemos crear una factoría personalizada, básicamente debemos crear una nueva clase que implemente la interfaz IControllerFactory, y en la función CreateController definimos como inicializar el controlador anterior.

Por organización vamos a crear una nueva carpeta llamada Factory, y allí dentro una nueva clase con el nombre CustomControllerFactory que implementa IControllerFactory:

public class CustomControllerFactory : IControllerFactory
{
	public IController CreateController(RequestContext requestContext, string controllerName)
	{
		// TODO: Implement this method
		throw new NotImplementedException();
	}

	public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
	{
		// TODO: Implement this method
		throw new NotImplementedException();
	}

	public void ReleaseController(IController controller)
	{
		// TODO: Implement this method
		throw new NotImplementedException();
	}
}

Ya con la clase creada, vamos a iniciar a definir lógica para cada método, iniciemos con ReleaseController, cuya función es liberar recursos:

public void ReleaseController(IController controller)
{
	var disposable = controller as IDisposable;
	if (disposable != null)
		disposable.Dispose();
}

Luego vamos con GetControllerSessionBehavior, por el momento vamos a dejar el comportamiento por defecto:

public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
{
	return SessionStateBehavior.Default;
}

Y finalmente CreateController, donde vamos a especificar la nueva forma de instanciar el controlador que hemos modificado anteriormente:

public IController CreateController(RequestContext requestContext, string controllerName)
{
	if (controllerName.ToLower() == &quot;home&quot;)
	{
		var controller = new HomeController(&quot;julitogtu&quot;);
		return controller;
	}

	var defaultFactory = new DefaultControllerFactory();
	return defaultFactory.CreateController(requestContext, controllerName);
}

Lo que hace el código anterior es validar si el controlador que se esta requiriendo en Home, en caso afirmativo lo instanciamos usando el constructor que hemos creado, en caso que no sea el controlador Home, entonces dejamos que la factoría por defecto haga su trabajo. Ahora el código completo de nuestra factoría:

public class CustomControllerFactory : IControllerFactory
{
	public IController CreateController(RequestContext requestContext, string controllerName)
	{
		if (controllerName.ToLower() == &quot;home&quot;)
		{
			var controller = new HomeController(&quot;julitogtu&quot;);
			return controller;
		}

		var defaultFactory = new DefaultControllerFactory();
		return defaultFactory.CreateController(requestContext, controllerName);
	}

	public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
	{
		return SessionStateBehavior.Default;
	}

	public void ReleaseController(IController controller)
	{
		var disposable = controller as IDisposable;
		if (disposable != null)
			disposable.Dispose();
	}
}

Finalmente, para que la factoría funcione, la llamamos en el evento Application_Start de el Global.asax:

ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());

Espero el ejemplo les sea interesante, saludos!

1 2 3 4