¿Cómo hacer que todas las cadenas en todos los ViewModel en un proyecto en MVC .Net se les aplique Trim o ToUpper? DefaultModelBinder

Cuando se trabaja en un equipo de desarrollo que sobre pasa los 3 programadores muchas veces se debe obligar a que se realicen tareas básicas como recortar los espacios en las cadenas por medio de Trim, o quizá si existe un requerimiento del cliente de que todas las cadenas estén en mayúsculas realizar un ToUpper o por lo contrario un ToLower, bueno, cualquier función sobre algún tipo de dato en todos nuestros modelos de nuestra aplicación.

Para asegurarnos de que siempre sean ejecutadas este tipo de operaciones existe en MVC .Net algo llamado Binder o ModelBinder el cual trabaja como cubierta de la información y puede transformarla a lo que deseemos, validar o realizar una operación.

A continuación incluyo una clase la cual hará que todas las cadenas que existan en nuestros View Model se les aplique una función Trim y una función ToUpper, así evitamos ponerlas en todos los controles, haciendo que esto ya sea un proceso por defecto en toda la aplicación.


namespace Sistema.Models.Binders
{
    public class TrimToUpperBinder : DefaultModelBinder
    {

        protected override void SetProperty(ControllerContext controllerContext,
         ModelBindingContext bindingContext,
         System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
        {
             //Solo modificaremos los string, por lo cual detectamos el tipo de dato
            if (propertyDescriptor.PropertyType == typeof(string))
            {
                var stringValue = (string)value;
                if (!string.IsNullOrEmpty(stringValue))
                {
                    stringValue = stringValue.Trim(); //trimeamos
                    stringValue = stringValue.ToUpper(); //mayuscula
                }

                value = stringValue;
            }

            base.SetProperty(controllerContext, bindingContext,
                                propertyDescriptor, value);
        }
    }
}

Y para que sea ejecutado en toda la aplicación debemos inicializar nuestra clase en el archivo Global.asax en el método Application_Start() de la siguiente manera:


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

            //Aquí remplazamos el binder por defecto con el nuestro
            ModelBinders.Binders.DefaultBinder = new Sistema.Models.Binders.TrimToUpperBinder();
        }

Borrar el cache al subir una imagen y mostrarla en el navegador en MVC .Net #Razor

Cuando hacemos un módulo para actualizar una imagen, ya sea el logotipo o una galería, muchas veces tenemos el problema de que sigue saliendo en el navegador la imagen vieja hasta que borramos el cache del navegador.

Lamentablemente los usuarios no saben que es el cache y esperan ver su imagen nueva, al seguir viendo la imagen vieja, el usuario piensa que no se ha subido con éxito la nueva imagen.

En el caso de Mvc .Net esto re se resuelve con un truco, e igual puede resolverse con su equivalencia en cualquier otro lenguaje de programación.

Para esto vamos a hacer uso de la funcionalidad Random, funcionalidad que existe en todo lenguaje de programación y basta con hacerlo de la siguiente manera, en el caso de MVC .Net lo haremos en razor (en la vista):


@{
    //creamos el objeto random y asignamos a una variable string
    Random r = new Random();
    string a = r.Next().ToString();
}

<img src='http://unsitio.com/unaimagen.jpg?a=@a'>

Al poner una variable con un valor nuevo al final de nuestra url de la imagen, obligamos al navegador a volver a cargarla y no utilizar la que tiene en cache.

Un truco viejo, pero que pocos conocen.

¿Cómo enviar un valor en ViewBag por RedirectToAction en C# MVC .Net?

Algunas veces tenemos la necesidad de llamar un método por medio de otro, y para ello hacemos uso de RedirectToAction.

RedirectToAction nos sirve para redirigir al usuario a otro controlador o a otro método dependiendo de la lógica de negocio, pero aparte, a veces necesitamos recibir en nuestro elemento destino algún valor para mostrarle al usuario o para realizar alguna validación. Para ello lo primero que se nos viene a la mente es por medio de ViewBag.

Lamentablemente ViewBag no tiene un tiempo de vida más allá del dominio del método, pero podemos apoyarnos de otro diccionario llamado TempData el cual se mantiene en toda la vida de la solicitud HTTP.

A continuación muestro un ejemplo sencillo de cómo quedaría:


public ActionResult Accion1 {
 TempData["mensaje"] = "Un mensaje feliz :)";

 //redirigimos a la Accion2 del mismo controlador
 return RedirectToAction("Action2");

}

public ActionResult Accion2 {

  if(TempData["mensaje"])
     ViewBag.mensaje = TempData["mensaje"].ToString();

  //de esta manera nuestra vista recibiria el ViewBag.mensaje solo cuando TempData no sea null
  return View();
}

¿Cómo obtener todos los parámetros enviados a un controller? C# MVC .Net

Cuando estamos utilizando MVC .Net muchas veces es necesario guardar lo que el usuario está enviando en logs o en la base de datos para poder monitorear errores de usuario final (Ver log sencillo en c# .Net).

De la siguiente forma obtenemos todos los parámetros enviados y ordenados en una variable cadena:


string parametros="";

//recorremos todos los parametros
 foreach (var parameter in Request.Params.AllKeys)
                {
                    parametros += parameter + ": " + Request.Params[parameter]+"\n";
                }

//se ira guardando de la siguiente forma
//parametro1: pato
//parametro2: pato2

Creación de archivo PDF en C# a partir de un archivo HTML (sin crystal report, sin itextsharp)

Creación de un archivo pdf sin utilizar ni crystal report ni itextsharp, de esta manera no dependemos de dll engorrosas como Crystal Reports.

Liga de libreria: https://wkhtmltopdf.org/

¿Cómo ponerle una contraseña a un pdf en c#?

Para poner un password a un pdf en C# podemos hacer uso de la librería iTextSharp(la cual pueden instalar con nuget, ¿Cómo utilizar nuget?) la cual tiene muchas funcionalidades para el manejo de archivos pdf.
Partiendo de un archivo pdf ya existente con el siguiente código:


 using (var input = new FileStream("C:/archivoOriginal.pdf", FileMode.Open, FileAccess.Read, FileShare.Read))
 using (var output = new FileStream("C:/archivoConContrasena.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    var reader = new PdfReader(input);
                    PdfEncryptor.Encrypt(reader, output, true,"tucontraseña", "tucontraseña", PdfWriter.ALLOW_PRINTING);
                }

¿Cómo parsear el formato dd-mm-yy en un DateTime en C# .Net?

Para poder parsear el formato dd-mm-yy en c# .Net, el problema radica que en el año solo tenemos 2 dígitos, pero esto no impide que se pueda realizar de manera fácil, para hacerlo basta con utilizar el método ParseExact de DateTime de la siguiente forma:


DateTime fecha = DateTime.ParseExact("30-01-16", "dd-MM-yy", CultureInfo.InvariantCulture);

¿Cómo concatenar un TimeSpan a un DateTime en c# .Net?

Por alguna circunstancia tenemos un TimeSpan y un DateTime y requerimos concatenarlos, es decir tenemos un TimeStam con la hora “13:30:00” y tenemos un DateTime con “2016-01-01 00:00:00”. Para ello tenemos que hacerlo de la siguiente forma:


DateTime fecha = DateTime.Parse("2016-01-01");
TimeSpan tiempo = TimeSpan.Parse("13:30:00");
DateTime fechaConcatenada = fecha.Value.Add(tiempo);

//fechaConcatenada = 2016-01-01 13:30:00

Corregir el error “in a frame because it set ‘X-Frame-Options’ to ‘SAMEORIGIN’” en #MVC .Net

MVC .Net por defecto no permite que sea visto en un iframe, pero a veces surge la necesidad de que sea visto en un iframe (o en mi caso el hospedaje invocaba un iframe el cual cargaba el sitio, no sé porque diablos así lo hace).

Para permitir que MVC .Net permita ser cargado en un iframe debemos ir al archivo Global.asax.cs y en el método Application_Start() debemos agregar la siguiente línea:

AntiForgeryConfig.SuppressXFrameOptionsHeader = true;

A su vez debemos agregar el namespace: System.Web.Helpers

Con esto se soluciona el problema. Espero les ahorre dolores de cabeza.