Mes: noviembre 2013

LINQ to SQL (IV): Modificación de datos


Antes de la aparición de LINQ, la filosofía de ADO.NET estaba orientada a datos. De este modo, cuando era necesario modificar o eliminar un registro, nuestro afán era detectar la clave primaria de ese elemento y generar, bien de forma estática, bien de forma dinámica, una sentencia UPDATE o DELETE para que la fuente de datos realizase la operación pertinente sobre ella.

La aparición de los mappers objeto-relacionales como LINQ to SQL intentan hacer algo difícil: desterrar ese concepto de nuestra cabeza y obligarnos a pensar exclusivamente en objetos.

Esta diferencia, al implicar un cambio de paradigma, puede resultar duro. Para ilustrar la diferencia entre ADO.NET básico y LINQ to SQL, veamos un ejemplo.

Anteriormente podíamos usar un DataAdapter para mapear una tabla de base de datos dentro de un DataTable. Y era posible, a partir de ese DataAdapter, obtener dos copias de un mismo conjunto de datos, es decir:


            //Obtenemos la cadena de conexión de App.config o Web.config
            string cadenaConexion = ConfigurationManager.ConnectionStrings["TestDb"].ConnectionString;

            // Creamos una conexión a partir de la cadena de conexión
            using (SqlConnection conexion = new SqlConnection(cadenaConexion))
            {
                // Declaramos una consulta
                string sqlSelect = "select * from Cliente";

                // Abrimos la conexión y generamos un SqlCommand con la conexión y la consulta
                // Instanciamos un SqlDataAdapter a partir del SqlCommand
                conexion.Open();
                SqlCommand commandSelect = new SqlCommand(sqlSelect, conexion);
                SqlDataAdapter dataAdapter = new SqlDataAdapter(commandSelect);

                //Declaramos dos DataTables y los rellenamos con el DataAdapter
                DataTable dt1 = new DataTable();
                DataTable dt2 = new DataTable();

                dataAdapter.Fill(dt1);
                dataAdapter.Fill(dt2);

                conexion.Close();
            }

(más…)

LINQ to SQL (III): Consultas compiladas, ejecución SQL y procedimientos almacenados


Compilación de consultas

En ocasiones podemos encontrarnos con consultas LINQ cuyo coste computacional puede ser alto, haciendo que el sistema se sobrecargue. LINQ to SQL proporciona algunas herramientas que mitigan, dentro de lo posible, el impacto de este tipo de operaciones sobre el rendimiento. Una de ellas es la compilación de consultas.

Es posible precompilar una consulta LINQ, de modo que durante su primera invocación realice un plan de ejecución que pueda mantenerse cacheado para ser reutilizado posteriormente. Así, la siguiente consulta:


            int idCliente = 2;

            var consulta = (from cliente in dbContext.Cliente
                            where (cliente.IdCliente == idCliente)
                            select cliente).FirstOrDefault();

Podría ser compilada y almacenada en una variable, que podrá ser reutilizada posteriormente como si fuese un método normal y corriente. Vemos, además, que la consulta puede parametrizarse, de modo que es posible asignarle cierto grado de generalización.


            var getClientePorId = CompiledQuery.Compile(
                (Testdb contexto, int id) =>
                    (from cliente in contexto.Cliente
                     where (cliente.IdCliente == id)
                     select cliente).FirstOrDefault()
                );

(más…)

LINQ to SQL (II): Relaciones


Ahora que ya sabemos cómo mapear una base de datos relacional en un conjunto de objetos, es momento de profundizar en algunos conceptos y procesos relacionados con esta transformación. El primero de ellos tiene que ver con la forma de tratar las relaciones entre las tablas.

Generalmente, una relación entre dos tablas se establece a través de un campo de la clase que referencia, al que denominamos clave foránea, que «apunta» (toma el valor) de la clave primaria (que identifica cada registro de forma única) de otra tabla.

Así, en el siguiente esquema, el campo IdCliente identifica de forma única a cada cliente, mientras que el campo IdPedido hace lo propio con cada pedido. Sin embargo, la tabla Pedido posee también un campo IdCliente, cuyo valor coincidirá con el campo IdCliente de la tabla Cliente perteneciente al registro que quiere referenciar.

Es decir. Si tenemos los siguientes registros:

Vemos que el campo IdCliente de la tabla Pedido «referencia» al campo IdCliente de la tabla Cliente indicando cuál es el cliente que ha realizado el pedido. A través de operaciones como joins, es posible, a partir del Id del cliente almacenado en el pedido, recuperar los datos del cliente, como su nombre o fecha de nacimiento.

(más…)

LINQ to SQL (I): Mapeo Objeto-Relacional


A estas alturas ya debemos de tener una idea bastante precisa del funcionamiento básico de LINQ. Hemos visto cómo lanzar consultas a listados de objetos (LINQ to Objects) e incluso algún ejemplo sobre cómo iterar sobre ficheros XML (LINQ to XML). Todas estas operaciones tienen un factor común: se realizaban sobre listados que implementaban la interfaz IEnumerable.

Además de poder lanzar consultas sobre listados de objetos, LINQ nos permite una opción aún más potente: lanzar consultas sobre bases de datos SQL Server mediante LINQ to SQL, que no es más que un mapper objeto-relacional, es decir, encargado de transformar sentencias LINQ en expresiones T-SQL y viceversa.

La potencia de LINQ to SQL radica en que, además de permitir realizar operaciones de consulta sobre una base de datos, también es posible realizar inserciones, actualizaciones y eliminaciones de forma nativa. A continuación veremos cómo realizar esto.

La principal desventaja de usar LINQ to SQL es que nuestra base de datos ha de ser, obligatoriamente, SQL Server (no obstante, existen proveedores LINQ para otras bases de datos, como LINQ to Oracle o LINQ to MySQL (vía NuGet). En caso de que todo esto falle y que necesitemos un proveedor personalizado, siempre podremos desarrollar por cuenta propia nuestro propio proveedor. En cualquier caso, siempre podremos utilizar un mapper objeto-relacional más genérico, como por ejemplo Entity Framework, del que hablaremos en posteriores artículos.

En este primer acercamiento a LINQ to SQL hablaremos de cómo establecer la relación entre nuestro programa (orientado a objetos) y nuestra base de datos (relacional). Para ello disponemos de varias posibilidades, que mostraremos a continuación:

(más…)

Sentencias en LINQ (VIII): Cuantificadores, generadores y conversores


Hasta ahora hemos visto las operaciones más comunes que pueden realizarse mediante LINQ. Por lo tanto, sólo nos queda echarle un vistazo a un subconjunto de sentencias de carácter más auxiliar, tales como la cuantificación, generación y conversión de elementos.

Any

El método Any toma como argumento un delegado o expresión lambda que tomará como parámetro un elemento de la lista y devolverá un valor booleano que indicará si al menos un elemento de la lista cumple la condición especificada.

Así, si quisiéramos saber si se ha vendido al menos un producto cuyo ID sea 3, podríamos optar por, bien crear un método que realice la comparación y que será pasado como delegado, bien utilizar una expresión lambda que realice la misma operación.


        // OPCIÓN 1: Usamos un delegado de una función que toma un elemento del listado como parámetro
        // y devuelve un booleano que devuelve el resultado de la comparación
        public bool PedidoConProductoIgualA3(LineaPedido linea)
        {
            return linea.IdProducto == 3;
        }
        bool existe = DataLists.ListaLineasPedido.Any(PedidoConProductoIgualA3);

        // OPCIÓN 2: Usamos una expresión lambda que realice la misma operación
                  bool existe = DataLists.ListaLineasPedido.Any(linea => (linea.IdProducto == 3));

(más…)

Sentencias en LINQ (VII): Operaciones sobre conjuntos


Las listas generadas mediante el álgebra relacional no son, en última instancia, más que conjuntos de datos. Y si nos ceñimos a una definición formal de conjunto, tenemos que se trata de una agrupación de elementos que es, a su vez, un elemento.

Sobre estos conjuntos pueden realizarse una serie de operaciones básicas:

  • Distinción: selección de los elementos del conjunto que no son iguales a ningún otro.
  • Unión: creación de un conjunto a partir de los elementos de dos o más conjuntos, sin tener en cuenta los elementos repetidos.
  • Concatenación: similar a la unión, pero teniendo en cuenta los elementos repetidos.
  • Comparación: comprueba si los conjuntos poseen exactamente los mismos elementos.
  • Intersección: creación de un conjunto a partir de los elementos comunes a dos o más conjuntos.
  • Diferencia: creación de un conjunto a partir de los elementos de un conjunto cuyos elementos NO se encuentran en otro conjunto.

La operación de distinción (Distinct) la hemos visto en artículos anteriores, por lo que nos centraremos en el resto de operaciones. Comenzaremos por realizar tres consultas compuestas. Una de ellas contendrá información sobre las compras realizadas con valor superior a 20 euros. Otra contendrá las compras por valor entre 7 y 22 euros. La tercera contendrá información sobre compras con valor inferior a 10 euros.

(más…)

Sentencias en LINQ (VI): Ordenación


Otra de las funcionalidades básicas de cualquier consulta es la ordenación de los datos. Por norma nos bastará con dos criterios: campo por el que filtrar y orden en el que filtrar (ascendente o descendente).

La cláusula LINQ para realizar el filtrado es orderby. Si no se añade ningún parámetro de orden, los campos se recuperarán por defecto de forma ascendente. En caso de querer un orden descendente, añadiremos la palabra reservada descending a continuación del campo por el que queremos ordenar. La palabra reservada ascending fuerza a que la ordenación sea, en todo caso, ascendente.


            var consulta = from cliente in DataLists.ListaClientes
                           orderby cliente.Nombre ascending
                           select cliente;

            foreach (var cliente in consulta)
            {
                Console.WriteLine(string.Format("ID: {0}\tNOMBRE: {1}\tF.NACIMIENTO: {2}",
                    cliente.Id, cliente.Nombre, cliente.FechaNac));
            }

En este caso, los registros se ordenan por orden alfabético por el campo nombre, siempre de menor a mayor.

(más…)

Sentencias en LINQ (V): Funciones de agregación


Agregación, agrupación… son dos conceptos que parecen iguales pero que corresponden a características distintas dentro del álgebra relacional.

La agrupación, tal y como vimos en artículos anteriores, consiste en generar un conjunto de datos que poseen una característica común. Por ejemplo, agrupar los pedidos por cliente implicaría la obtención de varios subconjuntos (un subconjunto por cliente) compuestos por un dato que identifique unívocamente al cliente y sus pedidos asociados. Para realizar esta operación hacíamos uso de la sentencia group by.

La agregación está relacionada con la agrupación, ya que en lugar de proyectar un conjunto de datos asociados a otro, realiza una operación aritmética sobre uno o varios de estos datos. Por ejemplo, en lugar de obtener toda la información de los pedidos asociados a un cliente, una operación de agregación consistiría en obtener, por ejemplo el número de pedidos asociados a un cliente. Como podremos imaginar, todo cálculo de agregación debe tener asociada, por definición, una operación de agregación.

Las operaciones de agregación, por lo tanto, son de carácter matemático, y se suelen corresponder con las siguientes cinco operaciones:

  • Cuenta (Count): devuelve el número de registros pertenecientes a la agrupación.
  • Sumatorio (Sum): devuelve la suma de todos los valores de un campo numérico concreto perteneciente a la agrupación.
  • Máximo (Max): devuelve el máximo de los valores de un campo numérico concreto perteneciente a la agrupación.
  • Mínimo (Min): devuelve el mínimo de los valores de un campo numérico concreto perteneciente a la agrupación.
  • Media (Average): devuelve la media aritmética de un campo numérico concreto perteneciente a la agrupación.

Existen muchas otras posibles operaciones de agrupación, generalmente de carácter estadístico, como la varianza o desviación típica. Sin embargo, las cinco operaciones anteriores son las más extendidas en cualquier modelo de datos relacional, y por lo tanto, las más utilizadas.

(más…)

Sentencias en LINQ (IV): Particionado. Delegados y expresiones lambda.


El particionado es una característica que nos permite recuperar conjuntos concretos de una consulta a partir de un índice. Su funcionamiento sería similar al filtrado de no ser porque no hace uso de los datos en sí, sino del orden en el que éstos se almacenan.

Los métodos de particionado más útiles son los siguientes:

Take(n)

La sentencia Take devolverá los n primeros registros de la consulta. Así, si realizamos la siguiente consulta:

            var consulta = (from producto in DataLists.ListaProductos
                           select producto).Take(5);

Obtendremos los cinco primeros elementos de la consulta. Como podemos observar, el funcionamiento de este método es bastante sencillo.

Como punto a destacar: no se trata de una sentencia, sino de un método de la interfaz IEnumerable. Por tanto, puede aplicarse directamente a una lista sin necesidad de realizar la consulta LINQ que acabamos de hacer ahora mismo:

            var consulta = DataLists.ListaProductos.Take(5);

(más…)

Sentencias en LINQ (III): Agrupaciones (group by)


Tras saber cómo filtrar elementos, es buen momento para aprender a agruparlos. Agrupar elementos, como su propio nombre indica, es concentrar los datos de un registro a partir de una característica común. Por ejemplo, saber los pedidos que se corresponden a cada uno de los clientes.

Su sintaxis es la siguiente:


            var agrupacion = from p in DataLists.ListaPedidos
                             group p by p.IdCliente into grupo
                             select grupo;

Lo cual nos devolverá un listado de agrupaciones (objeto que implementa la interfaz IGrouping<tipoClave, tipoObjetoAgrupado>) compuesto por dos elementos principales:

  • Key: contiene la clave de la agrupación, es decir, el campo por el cual se está agrupando. En este caso se trataría del valor de p.IdCliente.
  • <Implícito>: el objeto en sí también es un listado compuesto por los objetos sobre los que itera la cláusula from, es decir, contenidos en DataList.ListaPedidos. En este caso sería un listado de objetos de tipo Pedido. Dado que están agrupados, el objeto grupo sólo contendrá aquellos objetos de la clase Pedido cuyo valor Pedido.IdCliente sea el mismo en todos los elementos de la lista.

(más…)

Sentencias en LINQ (II): Filtrado, Join y Multiselect


Hasta el momento hemos visto cómo realizar consultas sencillas sobre una colección, recuperando el objeto de rango sobre el que iteramos, componentes de éste o un nuevo objeto, bien de un tipo existente o anónimo. Es lo que se conoce en álgebra relacional como operaciones de proyección.

En el presente artículo aprenderemos a realizar operaciones de filtrado a través de la sentencia where. También reciben el nombre de operaciones de restricción.

Para el siguiente artículo haremos uso de las clases definidas en el artículo anterior, en el que devolvíamos la totalidad de los registros de una lista, siendo uno o varios campos de la entidad. A partir de ahora utilizaremos la sentencia where de LINQ, que es bastante similar a la que usamos en SQL.

Para filtrar una consulta en LINQ añadiremos la sentencia where <condición>. La condición, a diferencia de SQL, deberá utilizar el formato estándar del lenguaje, tal y como hacemos en una sentencia if o while. Así, si queremos recuperar aquellos productos cuyo precio sea superior a 7 Euros, lanzaríamos la siguiente consulta sobre la lista ListaProductos:


            var productosDeMasDeSieteEuros = from p in DataLists.ListaProductos
                                             where p.Precio > 7
                                             select p;

Simple, ¿verdad? El resultado sera un único elemento (Mochila escolar).

(más…)

Sentencias en LINQ (I): Selecciones simples. Tipado implícito y tipos anónimos.


Antes de profundizar un poco más en las posibilidades que ofrece LINQ para acceso a distintas fuentes de datos, conviene hablar un poco de las operaciones que podemos realizar con él.

LINQ, como buen lenguaje de consultas, permite la realización de múltiples operaciones sobre conjuntos de datos, tales como proyecciones, ordenaciones, particiones (útiles para realizar paginaciones) o agregaciones.

A continuación construiremos un pequeño conjunto de ejemplos que nos servirán como punto de inicio para comprender el funcionamiento de la sintaxis de este lenguaje. Comenzaremos creando en primer lugar un pequeño conjunto de datos sobre los que operar. Crearemos para ello cuatro entidades relacionadas entre sí. Asumiremos que tratamos de crear una aplicación para una papelería que quiere llevar un registro de clientes y ventas de productos, por lo que haremos uso de las siguientes entidades:

  • Cliente: simboliza un cliente de la papelería.
    • Id (int)
    • Nombre (string)
    • FechaNac (DateTime)
  • Producto: simboliza cada uno de los materiales que la papelería venderá a los clientes.
    • Id (int)
    • Descripcion (string)
    • Precio (float)
  • Pedido: simboliza un conjunto de productos proporcionados a un cliente concreto, por lo que se compondrá de una o más líneas de pedido.
    • Id (int)
    • IdCliente (int)
    • FechaPedido (DateTime)
  • LineaPedido: simboliza la venta de un número de un único producto concreto a un cliente en particular. Se asocia a un único pedido.
    • Id (int)
    • IdPedido (int)
    • IdProducto (int)
    • Cantidad (int)

Hemos definido las relaciones pese a que para este ejemplo no vamos a hacer uso de una base de datos relacional. Sin embargo, nuestro objetivo es simular esta opción (veremos cómo acceder a una fuente de datos relacional en posteriores artículos), por lo que haremos algo que nunca, bajo ninguna circunstancia, debería hacerse: codificar los datos en una clase de forma manual. Todo sea por el afán didáctico J

(más…)

Escribir ficheros XML mediante LINQ


Ayer veíamos la estructura de un fichero XML y cómo hacer uso del espacio de nombres System.Xml.Linq para generar un nuevo fichero XML. Anteayer, además aprendíamos de la versatilidad de LINQ, que nos permite iterar y filtrar sobre prácticamente cualquier cosa.

Hoy vamos a aunar los valores de ambos conceptos y vamos a generar (y consultar) un fichero XML a través de LINQ. Por ello es altamente aconsejable conocer previamente los conceptos explicados en los dos artículos anteriores.

Comenzaremos por el proceso de creación de un fichero XML. O más bien, de «cumplimentación». Hace ya unos añitos (¡cómo pasa el tiempo!) explicábamos en este mismo blog la forma de utilizar la reflexión para acceder a los elementos de un objeto (métodos, propiedades, atributos…). Hace unos días he actualizado ese artículo con información sobre cómo hacer uso de LINQ para realizar la misma operación que realizamos entonces (¡ah…! los tiempos del Framework 2.0…). Sin embargo, en este artículo iremos un poco más allá y aplicaremos esa misma funcionalidad para, a partir de un objeto, conseguir generar un fichero XML que desglose los elementos de cada miembro de un objeto.

Antes de meternos en harina con los ficheros XML, conviene centrarnos en la parte de LINQ. El objetivo es el siguiente: crear un fichero XML que almacene la información de todos los miembros de la clase de un objeto. La estructura objetivo será la siguiente:

  • <Clase>
    • <ConstructorMembers>
      • <Constructor name = «nombreConstructor» value=»void nombreConstructor()» />
    • <MethodMembers>
      • <Method name = «ToString» value = «System.String ToString()» />
      • <Method name = …

Es decir, desglosaremos la clase en secciones que, a su vez, contendrán elementos pertenecientes a esa sección (ConstructorMembers contendrá elementos Constructor y así sucesivamente), que a su vez contendrán dos atributos: name y value.

(más…)

Generar un fichero XML con XDocument


La tecnología LINQ tiene como principal atractivo su versatilidad: es capaz de realizar proyecciones y filtrado sobre cualquier colección iterable, así como de generar colecciones de objetos «al vuelo» de forma sencilla, tal y como vimos en el artículo anterior.

Hoy aprenderemos a hacer uso de uno de los grandes avances que Microsoft ha proporcionado, desde mi punto de vista, al mundo de la programación .NET: el espacio de nombres System.Xml.Linq. Para ello crearemos una pequeña función que, haciendo uso de LINQ y Reflection, recorra todos los elementos de un objeto y genere un fichero XML con sus metadatos.

Supongo que todos sabremos qué es un fichero XML y cuál es su estructura, pero no viene de más realizar una pequeña introducción a este tipo de documentos antes de aprender a bucear en su información y a generar ficheros de este modo.

El fichero XML

Un fichero XML (eXtensible Markup Language) es un fichero de marcas (como HTML) completamente personalizable que permite almacenar datos de forma esquemática y ordenada. Los elementos que nos interesan para entender este ejemplo son los siguientes:

  • Documento: engloba el fichero XML en sí. Se compone de una cabecera o prólogo y de un elemento o nodo raíz, del que colgarán (estarán anidados dentro de él) el resto de elementos del documento. En la imagen que puede verse más abajo, el elemento raíz sería «configuración».
  • Elemento o nodo: elemento principal de un fichero XML. Permite definir atributos y anidar otros elementos dentro de ellos. En la imagen inferior, los elementos del documento serían configuration, startup (que sería hijo directo de configuration) y supportedRuntime (que sería hijo directo de startup y nieto de configuration).
  • Atributo: asocia propiedades o características a un elemento, y se compone por un par clave-valor. En el caso inferior podemos ver algunos de los atributos, como «versión», que será un atributo del elemento supportedRuntime y cuyo valor será «v4.0».

XML

(más…)

Introducción a LINQ


LINQ (leído «link», pese a que mucha gente lo denomina «lin-quiú») es una biblioteca de la plataforma .NET que proporciona acceso a datos de forma nativa a C# o VB.NET.

Basa su existencia en las denominadas expresiones de consulta, que recuerdan a las sentencias SQL pero extienden su funcionalidad de consulta a otros elementos como listas, arrays, clases enumerables, o documentos XML.

Operadores de consulta

LINQ hace uso de un conjunto de operadores, definidos en el espacio de nombres System.Linq, que permiten realizar consultas sobre cualquier conjunto de objetos enumerables, es decir, IEnumerable<T>. Por ejemplo, imaginemos que tenemos un array (que implementa IEnumerable) como el siguiente:

    string[] juegos = {  "Carcassonne", "Bang", "Jungle Speed", "Los colonos de Catán", "Black stories", "Munchkin", "Zombies" };

    IEnumerable<string> consulta = from j in juegos
                                    where j.StartsWith("J")
                                    orderby j ascending
                                    select j;

    foreach( string elemento in consulta)
        Console.WriteLine(elemento);

Como podemos observar, si disponemos de conocimientos básicos de SQL, la consulta LINQ se parece bastante a una consulta SQL: cláusula select, where, from, orderby… Puede que lo único que altere un poco la paz de los que nunca hayan visto esta tecnología sea el orden en el que se declaran las sentencias.

(más…)

El Controlador en ASP.NET MVC 4 (III): Action Filters


Un Action Filter o filtro de acción es un atributo que puede asociarse a una acción de un controlador (o al controlador en su totalidad), modificando la forma en la que la acción se ejecuta. El Framework ASP.NET MVC proporciona unos cuantos, entre ellos:

Nombre Descripción
Authorize Restringe una acción para los roles o usuarios especificados.
HandleError Permite especificar una vista que se mostrará en caso de excepción no controlada.
OutputCache Almacena en caché la salida de un controlador
ValidateAntiForgeryToken Ayuda a evitar peticiones de falsificación de petición (pishing)
ValidateInput Desactiva las validaciones de petición. No es aconsejable hacer uso de este filtro salvo en ocasiones muy concretas, ya que pone en peligro la seguridad de la aplicación.

Además de los existentes, es posible crear filtros personalizados para fines definidos por el negocio (como por ejemplo, un sistema de autenticación personalizado).

Tal y como vimos brevemente en el artículo anterior con [HttpGet] y [HttpPost], las acciones pueden «condimentarse» con atributos que afectan a su funcionalidad. Los filtros se añaden a modo de atributo a las acciones, haciendo que su comportamiento varíe. Veamos un par de ejemplos.

(más…)

Instalar log4net en ASP.NET


Haremos una pequeña parada en el camino antes de proceder a explicar el funcionamiento de los Action Filters para aprender a configurar la herramienta de logging de Apache log4net. Esto se debe a que en el siguiente artículo crearemos un filtro personalizado que se encargará de trazar todas las operaciones realizadas por nuestros controladores, por lo que será requisito previo disponer de esta biblioteca instalada en nuestro proyecto.

Comenzaremos descargándonos log4net de la web de apache. Podemos obtenerlo desde aquí.

Hecho esto, abriremos el fichero .zip y nos dirigiremos al directorio que se corresponda con nuestra versión, en este caso, 4.0.


Localizaremos a continuación la biblioteca log4net.dll


(más…)

El Controlador en ASP.NET MVC 4 (II): Action Results


Hemos visto hasta ahora que nuestras acciones (recordemos que las acciones son los métodos públicos de un controlador) deben devolver un objeto de la clase ActionResult.

En ejemplos anteriores hemos utilizado los métodos View() y Content() para generar un objeto de este tipo, pero estos no son los únicos métodos que generan un resultado de una acción (ActionResult).

Dependiendo de la respuesta que queramos dar podremos hacer uso de los siguientes métodos, con sus correspondientes ActionResults, que generan desde texto plano (como Content()) hasta la lectura de un fichero (método File()) o la redirección a una nueva URL (método Redirect()):

MÉTODO ACTION RESULT DESCRIPCIÓN
Content() ContentResult Devuelve una cadena de texto.
EmptyResult (sin respuesta)
File() FileContentResult
FilePathResult
FileStreamResult
Devuelve el contenido de un fichero.
HttpUnauthorizedResult Devuelve un error de autorización (403)
JavaScript() JavaScriptResult Devuelve un fragmento de código JavaScript a ejecutar.
Json() JsonResult Devuelve datos en formato JSON.
Redirect() RedirectResult Redirecciona a una nueva URL.
RedirectToRoute()
RedirectToAction()
RedirectToRouteResult Redirecciona a otra acción.
View()
PartialView()
ViewResult
PartialViewResult
Traspasa el control a una vista.

A continuación echaremos un vistazo por encima a los elementos más importantes de esta tabla.

(más…)

El Controlador en ASP.NET MVC 4 (I): Enrutado


Anteriormente hemos aprendido el funcionamiento general de la arquitectura MVC de ASP.NET. Sin embargo, hay algunas dudas que se mantienen en el aire, como por ejemplo, cómo sabe MVC a qué controlador debe acudir cada vez que se recibe una petición HTTP.

Redireccionando las peticiones HTTP

Para bien o para mal, el enrutado no es una tarea que pertenezca al framework, sino que es ASP.NET quien debe encargarse de ello en última instancia. Previamente vimos que MVC 4 realiza una redirección hacia un controlador acorde a la ruta que se invoca: si se trataba de la ruta <servidor>/Home/About, comprobamos que se invocaba el método About() del controlador HomeController.

¿Dónde puede configurarse este comportamiento? La respuesta corta es: en el archivo de configuración global, global.asax.cs.

Este fichero contiene, entre otro código, las operaciones a realizar al levantar la aplicación, previas a cualquier petición que pueda realizarse. Entre esas operaciones se encuentra la posibilidad de indicarle a nuestra aplicación cómo se realizarán las redirecciones de las peticiones HTTP. Esto lo podremos observar en la siguiente línea de configuración:


RouteConfig.RegisterRoutes(RouteTable.Routes);

(más…)

Introducción a ASP.NET MVC 4


Aunque no hayas estudiado patrones de diseño, es altamente probable de que, si te dedicas a la programación, hayas oído hablar en alguna ocasión del Modelo-Vista-Controlador. Se trata de uno de los patrones de diseño más ubicuos y populares, que persigue la filosofía de crear un patrón de tres capas que diferencian las labores de la aplicación en:

  • MODELO: Gestiona la información que el usuario precisa, es decir qué información quiere el usuario.
  • VISTA: Muestra la información al usuario y permite que éste interactúe con ella, proporcionando datos, modificándolos, solicitando su modificación o simplemente, consultándolos. En resumen, cómo se muestra la información en pantalla.
  • CONTROLADOR: Actúa de intermediario entre los elementos anteriores y el usuario, atendiendo las peticiones HTTP (en el caso de ASP.NET), generando la información que el usuario requiere (modelo) y mostrándola por pantalla (vista).

Microsoft proporciona una implementación estándar de este patrón permitiendo crear un proyecto basado en web que genera automáticamente estos tres elementos, separando de una forma más clara la funcionalidad interna de la aplicación de la gestión de las peticiones y su visualización en pantalla.

(más…)