C#

Lazy C#

Desde las ultimas versiones del framework (desde la version 4) existe el objeto Lazy que podemos ocupar para diferir la inicialización de un objeto para mejorar el performance de la aplicación. Es decir, que podemos inicializar un objeto sin inicializar las demas propiedades hasta el momento en que se usen. De esta forma podríamos tener un objeto que cuando se inicializa (o se hace una instancia) difiera las inicializaciones de colecciones u otros objetos.

Un ejemplo muy sencillo:

Lazy<Orders> _orders = new Lazy<Orders>(() => new Orders(100));

if (displayOrders)
{
    DisplayOrders(_orders.Value.OrderData);
}

Se crea una instancia de este objeto sobre _orders, en ese momento el objeto Orders no existe hasta que se manda llamar la propiedad _order.Value, en este momento el objeto se inicializa como se indico en el constructor con la expresion lambda.

Un ejemplo real:

Imaginemos que el modelo de dominio en la aplicación que estamos desarrollando tenemos varios objetos con cierta profundidad por ejemplo tenemos una entidad Order que tiene una colección de OrderItem, donde existe una relación de 1 a N.

Al momento de cargar una entidad Order desde la base de datos se tiene que inicializar el objeto Order inicializando tambien todas sus propiedades para que la entidad se encuentre en un estado valido, o por lo menos listo para operar cualquier regla de negocio del dominio, y esto incluye cargar la colección de ItemOrder, que quizas si fueran pocos no habría problema pero podrían ser suficientes mas como para que pudiera haber problemas de memoria.

El negocio dice que tenemos que calcular los impuestos de una orden (Order); como lo resolveríamos es ir a buscar una orden por un identificador unico y después sobre el monto total calcular los impuestos necesarios. Aqui en realidad la unica propiedad que necesitamos de nuestra entidad Order es el monto y el identificador unico, todas las demas propiedades no las ocupamos, y si por cada vez que realizamos esta operación tan basica tenemos que cargar todas las dependencias del objeto Order seria costoso.

Aplicando el uso de inicializaciones diferidas con el objeto Lazy podríamos resolver este escenario.

Comenzado con el modelo de dominio, que es una Orden (class Order) y es el objeto principal.

    public class Order
    {
        private Lazy<List<OrderItem>> _items = null;

        public List<OrderItem> Items
        {
            get
            {
                if (_items != null)
                    return _items.Value;

                throw new InvalidOperationException("Items no inicializados");
            }
        }

        public int Id { get; set; }
        public double Total { get; set; }

        public Order()
        {
        }

        public Order(Lazy<List<OrderItem>> items)
        {
            _items = items;
        }

        public static Order CreateOrderWithItemsFactory(Func<List<OrderItem>> valueFactory)
        {
            return new Order(new Lazy<List<OrderItem>>(valueFactory));
        }
    }

Notemos primero las propiedades que requerimos para este objeto, que son:

Id: Identificador unico.
Total: El valor total de la orden.
Items (Colección de OrdeItem): Es una colección con el detalle de elementos de una orden.

Todos los definimos como propiedades, y veamos que la propiedad que exponemos como Items cambia un poco pues es lo que queremos diferir en la inicialización del objeto Order.

Lo que se hizo fue colocar un atributo privado _item definido como un objeto Lazy del tipo colección de OrderItem, de esta forma vamos a controlar cuando y como se inicializara esta colección. Después se expuso la propiedad Items solo de lectura donde obtendremos la colección ya inicializada del objeto Lazy, esto es el cuando. Ahora nos falta poder indicar al objeto como es que va a crear la colección. Para esto definimos un constructor que recibe un un objeto Lazy del tipo colección de OrderItem, este objeto trae la forma en la que se va a generar la colección, como el constructor por su naturaleza no es descriptivo creamos un metodo estatico CreateOrderWithItemsFactory que nos permite crear una orden definiendo como se deberá generar la colección de OrderItem por medio del parametro que recibe.

Como adicional a nuestro modelo tenemos la definición de OrderItem:

    public class OrderItem
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public double Price { get; set; } 
    }

Solo con algunas propiedades que lo definen.

Ahora, descifrando un poco la arquitectura de nuestra aplicación alrededor de nuestro dominio deberíamos tener un componente responsable de obtener los datos desde el recurso de persistencia que estemos ocupando. Este componente sera nuestro repositorio (muy simple) que tiene como responsabilidad obtener los datos y mapearlo a nuestras entidades de dominio, entre otras cosas.

Como una de las responsabilidades de nuestro repositorio es mapear las propiedades de nuestra entidad es necesario que al momento de obtener una orden (Order) indique como es que se debe resolver la creación de ese objeto y como se deben obtener la propiedades diferidas, pues al final la colección de OrderItem desde donde se deben de obtener es desde el recurso de persistencia (base de datos relaciona, archivo, NoSQL).

Veamos como funciona el repositorio OrerRepositoty.

    public class OrderRepository
    {
        public Order FinOrderById(int id)
        {
            var order = Order.CreateOrderWithItemsFactory(() => FindItemsByOrderId(id));

            //Despues ejecutamos las operaciones necesarias para obtener
            //la orden desde el recurso que estemos ocupando para persistir.
            //Podria verse asi, si ocupamos EF :

            //var dbOrder = _context.Orders.FirstOrDefault(o => o.IdOrder == id);

            //Mapeamos propiedades
            //order.Id = dbOrder.IdOrder;
            //order.Total = dbOrder.Total;
            //...

            return order;
        }

        private List<OrderItem> FindItemsByOrderId(int id)
        {
            var itemsList = new List<OrderItem>();

            //Ejecutamos operaciones necesarias para obtener
            //todos los items de una orden.

            //var orderItems = _context.OrderItems.Where(i => i.IdOrder == id);
            //foreach(var item in itemsList)
            //{
            //  mapeamos propiedades
            //}

            return itemsList;
        }
    }

Nuestro repositorio expone dos metodos, para buscar ordenes por su identificador FindOrderById y otro para buscar todos los elementos de la orden por el identificador de la orden FindItemsByOrderId.

Dentro del metodo donde obtenemos la orden es donde debemos implementar como se van a resolver la propiedades diferidas, para nuestro caso queremos que la colección de OrderItem este diferida, para eso en la primera linea del metodo creamos una instancia del objeto Order por medio del metodo estatico que se expone Order.CreateOrderWithItemsFactory que internamente crea una instancia del objeto Lazy, de esta forma por medio de una expresion indicamos como es que se va a resolver la creación de la colección de OrderItem, y aqui mismo indicamos que el repositorio por medio del metodo FindItemsByOrderId va a obtener la colección.

Y el metodo FindItemsByOrderId lo unico que hace es obtener todos lo elementos de una orden por su identificador, mapear y devolver la colección.

De esta forma el repositorio es responsable de obtener y mapear las propiedades del objeto Order, y para las demás clases que ocupan el repositorio como servicio es transparente todo el proceso de inicialización.

Finalmente veamos como se ocupan esto desde la aplicación (en esta ocasión una consola):

        static void Main(string[] args)
        {
            var orderService = new OrderService();

            var order = orderService.FindOrderById(123);

            var tax = CalculateTax(order);

            var items = order.Items;
            foreach (var item in items)
            {
                //.....
            }

            System.Console.ReadKey();
        }

        static double CalculateTax(Order orer)
        {
            return orer.Total * 1.16;
        }

Iniciamos creando una instancia de OrderServices (esta clase se encuentra en una capa entes del acceso a datos que es responsable de orquestar, para el ejemplo simplemente funciona como espejo sobre los metodos que expone el repositorio) que manda a llamar el metodo FindOrderById para obtener una orden y calcular los impuestos, que es el escenario que se queria mostrar. Hasta este punto después de que se obtiene la orden y se calcula los impuestos por el metodo CalculateTax no existe ninguna colección de OrderItem. Hasta el momento donde obtenemos la colección por medio de order.Items es cuando objeto Lazy resuelve generar la colección desde el repositorio como ya lo explicamos.

De esta forma es transparente el como se resuelve la inicialización y cuando ocupamos la entidad Order no se crea la colección hasta que se ocupe.

Descargar Código

Post Get Redirect Pattern – ASP .NET MVC

Cuando estamos desarrollando una aplicación web es muy común que nos encontremos con el siguiente escenario que representa un problema, no tan grave pero si nos pude causar problemas.

Tenemos una vista que dispara una petición por medio de POST donde se envían datos para realizar algún proceso (como naturalmente sucede), y esta vista después de que se realiza la petición regresa a la misma vista y el usuario decide hacer un “refresh”; esto ocasiona que se vuelva a enviar la petición anterior. Esto podría ocasionar algún problema, quizás registros duplicados con la misma información.

Podemos prevenir esto aplicando el patrón Post/Get/Redirect:

1. Asumamos que tenemos una vista con un formulario muy simple donde guardamos 2 valores (name y mail).

  <div>
        <form action="/Client/Create" method="post">
            Name:
            <input type="text" name="name" />

            <br />

            Mail:
            <input type="text" name="mail" />

            <br />

            <input type="submit" value="Save" />
        </form>
        
        <%: Model??string.Empty %>
    </div>

2. Navegamos hacia esta vista por medio de la acción Create sobre un controlador llamado Client, la url se veria asi {host}/Client/Create.

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

3. Y tenemos una acción que responde al submit del formulario por medio de POST.

 [HttpPost]
public ActionResult Create(string name, string mail)
{
    //creamos un nuevo client

    object result = "Saved " + name;

    return View(result);
}

Eso es lo que naturamente hariamos cuando queremos guardar datos desde un formulario.

Cuando hacemos click en el boton Save se hace una petición por medio de POST (ocurre on post-back) donde se envían todos campos que definimos del formulario, y los recibe la acción Create (con el atributo HttpPost) y ahi es donde guardaríamos la información invocando algún servicio de aplicación y devolveríamos un mensaje de respuesta, en nuestro caso de volvemos como respuesta la palaba “Saved” concatenando el valor del campo name. Probamos y funciona como lo esperado.

create

Ahora esto es lo que sucede cuando hacemos refresh de la pagina o presionamos F5.

create2

Si el navegador lo detecta muestra una modal indicando que se enviara de nuevo la petición anterior, si no lo detecta o el usuario inexperto (la mayoría) da click en continuar se enviaría la misma petición con los datos que previamente capturamos, provocando quizás un problema en la aplicación.

Aplicando el patrón para evitar este tipo de escenarios hacemos lo esto:

1. Dentro de nuestra acción Create que recibe los datos realizamos un redirect hacia la acción que devuelve la vista (esta acción responde a una petición GET). De esta forma regresamos a la vista de la misma forma como lo teníamos antes.

2. Para responder con el mismo mensaje que indica que se guardo correctamente, ocupamos el diccionario TempData que podemos ocupar para pasar información entre distintas acciones sobre el mismo contexto de la peticion que esta en curso.

Así se verían los metodos de las acciones:

        public ActionResult Create()
        {
            object result = TempData["ResultValue"];

            return View(result);
        }

        [HttpPost]
        public ActionResult Create(string name, string mail)
        {
            //creamos un nuevo client

            object result = "Saved " + name;

            TempData["ResultValue"] = result;

            return RedirectToAction("Create");
        }

De esta forma si el usuario presiona F5 o hace un refresh no ocurre nada, simplemente se recarga la pagina y no se envía nada. Seria una buena practica para cualquier formulario de esta naturaleza.

Código

C#

Reflection y métodos genéricos C#

Posted on

Algunas veces cuando estamos resolviendo una tarea por medio de reflection se tiene la necesidad de invocar un metodo de alguna clase pero resulta que este metodo tiene una firma donde espera parametros de forma generica, algo asi:

        private static T ReadResultsIntoList<T>(XDocument xmlData)
        {
            .
            .
            .
            .      

            return (T)resultList;
        }

Ahora cuando quiera invocar el método con el nombre ReadResultsIntoList lo obtengo con reflecton de esta manera:


var current = typeof(DataParser);//Clase donde existe la firma del metodo.

var method = current.GetMethod("ReadResultsIntoList", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);

var genericMethod = method.MakeGenericMethod(typeof(int));//Asigno tipo que va a tomar el método genérico.

var result = genericMethod.Invoke(null, new object[] { XDocument.Parse("<texto></texto>") });//Invoco el metodo y le envio el argumento que espera, notar que es un metodo estatico por eso no se le envia el objeto de instancia.