Autor en Google+
Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET, ASP.NET Core, MVC, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

11 años online 🎂

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET, ASP.NET Core, MVC, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 27 de junio de 2017
C#Hace poco hablábamos del nuevo soporte para tuplas de C#, y comentábamos que una forma de consumirlas era mediante la deconstrucción, otra nueva característica introducida en la versión 7 del lenguaje, que consiste en “despiezar” las tuplas, extrayendo de ellas sus elementos e introduciéndolos en variables locales, utilizando una sintaxis muy concisa.

En realidad no es algo demasiado diferente a lo que hacemos normalmente cuando almacenamos en una variable local el resultado de un método que retorna un único valor:
var sum = Sum(1, 3); // Guardamos el valor de retorno en variable local
Console.WriteLine($"Sum: {sum}");
...

static int Sum(int a, int b)
{
   return a+b;
}
Pues bien, cuando un método retorna más de un valor en forma de tupla, podemos conseguir exactamente lo mismo para todos los valores retornados, de una forma igualmente sencilla. El siguiente ejemplo muestra un método que retorna una tupla, y cómo la deconstruimos para obtener sus valores en forma de nuevas variables locales:
var (add, sub, mul, div) = Calculate(1, 3); // Guardamos los valores de retorno en vars locales
Console.WriteLine($"Sum: {add}");
...

static (int add, int sub, int mul, int div) Calculate(int a, int b)
{
    return (a + b, a - b, a * b, a / b);
}
Observad que hemos utilizado la palabra clave var para indicar al compilador que sea él el que se encargue de inferir los tipos de los elementos de la tupla. Pero si nos va el masoquismo podríamos hacerlo de forma mucho más trabajosa; las siguientes líneas son equivalentes:
(int add, int sub, int mul, int div) = Calculate(1, 3);
(var add, var sub, var mul, var div) = Calculate(1, 3);
var (add, sub, mul, div) = Calculate(1, 3);
También podemos deconstruir sobre variables existentes con anterioridad, como en el siguiente ejemplo:
int add, sub, mul, div;
...
(add, sub, mul, div) = Calculate(1, 3);
Console.WriteLine($"Sum: {add}");
Por supuesto, los nombres de las variables locales pueden ser diferentes a los nombres asignados a los miembros de la tupla. Lo que importa es el orden, que sí debe coincidir (¡recordad que una tupla es una lista ordenada de elementos!):
var (a, s, m, d) = Calculate(1, 3);
Console.WriteLine($"Sum: {a}");
Otro aspecto interesante es que si, como en el ejemplo anterior, no vamos a utilizar todos los elementos de la tupla, podemos sustituir por el placeholder "_" los elementos que no nos interesen:
var (add, _, _, div) = Calculate(1, 3);
Console.WriteLine($"Sum: {add}, Div: {div}");

La deconstrucción más allá de las tuplas

Aunque hemos visto la deconstrucción en el ámbito de las tuplas, donde tienen una aplicación sencilla y directa, en realidad es una característica del lenguaje que puede utilizarse con cualquier tipo de .NET. No veo que sea algo excesivamente útil en la práctica, e incluso dudo mucho que favorezca la legibilidad del código, pero bueno, siempre es bueno saber que existe esta posibilidad y cómo implementarla.

Para que un tipo cualquiera (clase o estructura) pueda ser deconstruido, debe implementar un método void llamado Deconstruct(), más o menos con la siguiente pinta:
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }

    public void Deconstruct(out string name, out int age, out string email)
    {
        name = Name;
        age = Age;
        email = Email;
    }
}
El número y tipo de parámetros out en Deconstruct() es el que define las "piezas" en las que podrán ser deconstruidos los objetos de nuestra clase. Así, según el código anterior, podríamos efectuar una deconstrucción de la siguiente manera:
var person = _myServices.GetPersonById(3422);
...
var (name, age, email) = person;
Console.WriteLine($"I'm {name}, {age} years old");
Console.WriteLine($"Contact me at {email}");
De hecho, si descompilamos un código como el visto anteriormente, descubriremos que, al fin y al cabo, la deconstrucción es un simple edulcorante sintáctico sobre las llamadas al método Deconstruct():
// Decompiled sources:
string name;
string email;
int age;
person.Deconstruct(out name, out age, out email);
Por este motivo, en la práctica es posible crear distintas sobrecargas de Deconstruct() que serán invocadas en función del número de parámetros que utilicemos en la deconstrucción:
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }

    // Consumo: var (name, age) = person;
    public void Deconstruct(out string name, out int age)
    {
        name = Name;
        age = Age;
    }

    // Consumo: var (name, age, email) = person;
    public void Deconstruct(out string name, out int age, out string email)
    {
        name = Name;
        age = Age;
        email = Email;
    }
}
En definitiva, tenemos delante una vuelta de tuerca al lenguaje que permite sacar mayor partido a las tuplas y facilita la codificación en algunos escenarios. Aunque probablemente no vayamos a usarla todos los días, sin duda es una herramienta interesante para tener en nuestro cinturón de herramientas.

Por último, por si os interesa, os recuerdo otros posts de esta serie sobre novedades de C# 7:
Publicado en Variable not found.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 26 de junio de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 20 de junio de 2017
C#Continuamos esta serie sobre las novedades incluidas en C#7, y en esta ocasión vamos a ver una pequeña mejora en el lenguaje que seguro nos será de utilidad para simplificar código muy frecuente: las expresiones throw.

Fijaos en un código como el siguiente, que seguro que habéis escrito cientos de veces, donde utilizamos el constructor de una clase para recibir sus dependencias y almacenarlas en miembros de la instancia:
public class MyService: IMyService
{
    private readonly IDependency _first;
    private readonly IAnotherDependency _second;

    public MyService(IDependency first, IAnotherDependency second)
    {
        if (first==null)
            throw new ArgumentNullException("first");

        if (second == null) // O mejor, usando el operador nameof
            throw new ArgumentNullException(nameof(second));

        _first = first;
        _second = second;
    }

    ...
}

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 19 de junio de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 13 de junio de 2017
C#Y continuamos escarbando en las nuevas características disponibles en C#7, incluido de serie en Visual Studio 2017. Hasta el momento hemos profundizado en las siguientes novedades:
En esta ocasión nos centraremos en la vuelta de tuerca que se ha dado a las tuplas a nivel de lenguaje, reforzándolas como first-class citizens para los desarrolladores C#.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 12 de junio de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 6 de junio de 2017
Google Chrome logoCuando desarrollamos aplicaciones web que funcionan sobre el protocolo HTTPS en la máquina local, lo más habitual es que utilicemos un certificado digital autofirmado o, en cualquier caso, firmado por una entidad no confiable.

Esto hace que los navegadores, por supuesto siempre con el ánimo de preservar nuestra privacidad,  sospechen del sitio web y muestren alertas como la siguiente, donde se nos informa de que el certificado es inválido y que alguien podría estar intentando robarnos información:

Chrome mostrando el error: La conexión no es privada

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 5 de junio de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

miércoles, 31 de mayo de 2017
Visual StudioHace poco me encontraba con el post "Breakpoint Generator extension is open source" y me llamó la atención, básicamente porque no sabía de qué estaban hablando. Cosas de la ignorancia :D

Tirando un poco del hilo, he encontrado con que se trata de una extensión interesante y que podría ser útil en algunos escenarios, por lo que voy a comentar por aquí lo que he ido viendo.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 30 de mayo de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 23 de mayo de 2017
ASP.NET MVC 5El amigo José Antonio M. A., alumno de mi curso de ASP.NET MVC 5 en CampusMVP, me envió hace unos días una pregunta que he creído interesante comentar por aquí porque probablemente pueda ayudar a alguien más.

La cuestión que planteaba era relativa al mal funcionamiento de WebGrid cuando mostramos un campo de tipo enum y queremos ordenar por el mismo. Poco más o menos, me lo comentaba de la siguiente forma:
He incluido un campo enum en la clase del modelo y lo he incluido como columna en WebGrid.
[…]
Todo funciona bien menos el WebGrid, que no me ordena por esa columna. Al hacer click en ella ordena de forma correcta ascendentemente pero al hacer click otra vez no te ordena de forma descendente, mirando la url se ve que sortOrder no varía sigue siendo ASC. si lo cambio a mano a desc me lo ordena bien. ¿Es que el webgrid no ordena enumeraciones? ¿Cuál sería la solución, si quiero ordenar?
Obviamente, el hecho de que al cambiar a mano el parámetro sortOrder todo funcionara bien, dejaba de manifiesto que el problema no estaba en el controlador ni en el modelo, dejando la vista como única sospechosa de provocar ese problema.

Mis primeras respuestas iban orientadas a buscar un pequeño fallo en la forma de usar WebGrid o similar, porque me parecía algo bastante extraño, y, sobre todo, me parecía raro que no me hubiera pasado antes. José Antonio comentó, además, que había encontrado referencias por la red de que WebGrid tenía este problema, y que podía solucionarse si se forzaba una conversión de la enumeración a string a la hora de pasar los datos a la vista (!).

Y tras hacer varias pruebas, efectivamente, parece que algo hay. No sé si categorizarlo como bug del componente, o simplemente un comportamiento algo oscuro y poco previsible del mismo, pero en cualquier caso es interesante conocer este problema para poder atajarlo con éxito.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 22 de mayo de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 16 de mayo de 2017
ASP.NET CoreA la hora de iniciar un nuevo proyecto ASP.NET Core, una de las primeras decisiones que debemos tomar es si el target de éste será .NET Core o .NET Framework.

Muchas veces esto dependerá de los requisitos y el entorno del proyecto; por ejemplo, si nos interesa la capacidad para ejecutarlo o desarrollarlo sobre entornos Linux o Mac, nos tendremos que decantar por .NET Core, pues el framework completo sólo está disponible para Windows. También podemos encontrarnos con que necesitamos (re)utilizar componentes o bibliotecas que aún no han sido portadas a .NET Core, por lo que en este caso el target será .NET Framework (bueno, esto cambiará bastante con la llegada de Net Standard 2.0, pero de momento es lo que hay).

En cualquier caso, la decisión la tomamos justo en el momento de crear el proyecto en Visual Studio, al seleccionar la plantilla que usaremos como base:

Cuadro de diálogo de creación de proyecto ASP.NET Core en Visual Studio 2017

Sin embargo, conforme el proyecto avanza, puede que esta decisión que tomamos tan al principio no sea del todo válida: quizás en su momento elegimos .NET Core, pero ahora debemos cambiar a .NET Framework. O al contrario, porque ahora necesitamos que nuestra aplicación sea multiplataforma. O tal vez necesitemos las dos cosas al mismo tiempo por si acaso…

Nota: aunque aún pululan por ahí aplicaciones creadas con versiones preliminares del SDK, basadas en el difunto project.json, aquí utilizaremos la versión 1.0 del SDK, que ya utiliza el nuevo .csproj. Si todavía no has migrado, ya estás tardando ;)

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 15 de mayo de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

miércoles, 10 de mayo de 2017
11 años de Variable Not FoundDesde luego, conforme me voy haciendo más viejo, más rápido pasan los años, aunque probablemente esta sensación se deba también a que la fiesta de celebración del décimo aniversario se alargó varios meses y parece que fue ayer. Pero bueno, el caso es que aquí estamos, celebrando una vez más el cumpleaños de este blog :)

Once años dan para mucho, la verdad. Superamos ya las novecientas cincuenta publicaciones, más de 2.300 comentarios y 2,7 millones de páginas vistas según Blogger, cifras que van mucho más allá de lo que habría firmado sin dudarlo aquél mayo de 2006 cuando empezó este viaje.

Un viaje que tiene destino ni fecha de finalización: el único objetivo es disfrutar del camino, que os puedo asegurar que lo estoy haciendo, y echar una manita a los compañeros de profesión y afición que anden buscando información o soluciones a problemas con las que yo me haya topado antes. ¿Hay algo más gratificante que esto?

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 9 de mayo de 2017
C#Seguimos revisando las novedades que nos llegan de la mano de C# 7, la nueva versión del lenguaje aparecida junto a Visual Studio 2017.

En un post anterior ya profundizamos un poco en las funciones locales, y hoy veremos en qué consisten las nuevas inline out variables, una característica muy útil que nos ahorrará escribir código en escenarios en los que siempre hemos tenido la sensación de que C# podía hacer algo más por nosotros.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 8 de mayo de 2017

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

miércoles, 3 de mayo de 2017
Los que llevamos tiempo trabajando con paquetes NuGet, sabemos que la desinstalación de paquetes requería tradicionalmente entrar en la consola del gestor de paquetes, o bien usar el interfaz gráfico de este gestor de paquetes en Visual Studio, lo que era bastante lento y farragoso.

Y claro, como los humanos somos animales de costumbre, lo normal es que cuando damos el salto a ASP.NET Core continuemos haciéndolo de la misma forma, sin pararnos un segundo a replantearnos si hay mejores formas… lo que me recuerda a esta famosa imagen que anda por Internet desde hace bastante tiempo:

No gracias, no quiero perder el tiempo probando esas ruedas redondas porque estoy demasiado ocupado tirando de mi carro con ruedas cuadradas
(Fuente: Ni idea)

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 2 de mayo de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 25 de abril de 2017
C#Pues ya con la séptima versión de C# en la calle, aparecida de la mano del flamante Visual Studio 2017, va siendo hora de echar un vistacillo rápido a las principales novedades que encontraremos en esta nueva iteración de nuestro lenguaje favorito.

Y hoy vamos a comenzar con las funciones locales, una nueva capacidad que nos permitirá crear funciones locales a un ámbito, y que no serán visibles desde fuera de éste. Por ejemplo, podemos crear funciones en el interior de métodos, constructores, getters o setters, etc., pero éstas sólo serán visibles desde el interior del miembro en el que han sido declaradas.

Puede ser útil en determinados escenarios, puesto que evitan la introducción de "ruido" en las clases cuando determinado código sólo se va a consumir en el interior de un método, y al mismo tiempo pueden contribuir a mejorar la legibilidad y robustez del código.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 24 de abril de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core


Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 18 de abril de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 10 de abril de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 4 de abril de 2017
ASP.NET Core MVCComo sabemos, tradicionalmente los controladores MVC son clases cuyo nombre, según la convención, debe finalizar por “Controller”, como en InvoiceController o CustomerController, y esta convención ha continuado en ASP.NET Core MVC, la edición más reciente del framework.

Sin embargo, desde las primeras versiones del framework la convención era modificable y podíamos adaptarla a nuestras necesidades aprovechando la extensibilidad del framework. De hecho, ya vimos hace muuucho mucho tiempo cómo hacerlo con la versión "clásica" de ASP.NET MVC, pero con la llegada de MVC Core las cosas han cambiado bastante.

En este post vamos a ver cómo modificar la convención de nombrado de controladores a algo más patrio: haremos que éstos puedan llamarse “ControladorDeXYZ”, como en ControladorDeFacturas o ControladorDeClientes. Es decir, si tenemos una clase como la siguiente, pretendemos que una petición hacia "/facturas/index" retorne el texto "ControladorDeFacturas.Index":
public class ControladorDeFacturas : Controller
{
    public IActionResult Index()
    {
        return Content("ControladorDeFacturas.Index");
    }
}
Por supuesto, podríamos hacer que esta clase fuera un controlador simplemente aplicándole el atributo [Controller], pero el objetivo de este post es aprender algo sobre el funcionamiento interno del framework, así que no vamos a quedarnos con esta solución tan sencilla ;)

Pero antes de ponernos a ello, permitidme aclarar que cambiar las convenciones de nombrado de controladores no es muy conveniente porque, aparte de romper el principio de la mínima sorpresa, hay herramientas que podrían dejar de funcionar correctamente, pero sin duda hacerlo ofrece una magnífica ocasión para profundizar un poco en los entresijos del framework ;)

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 3 de abril de 2017

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

miércoles, 29 de marzo de 2017
Desarrollador volviéndose loco
Imagen original de Pixabay.
La llegada del próximo April Fool's day, algo parecido a lo que por aquí conocemos como el día de los Inocentes, me ha recordado una curiosidad con la que me topé hace algún tiempo que, si tenéis un poco de maldad reprimida, podéis utilizar para gastar una broma a algún compañero desarrollador y echar unas risas.

La historia consiste en abusar del amplio conjunto de caracteres soportado por UTF, sustituyendo el punto y coma de finalización de una línea de código (";") por el símbolo de interrogación griego (";", Unicode 037E), indistinguibles a simple vista, como en la siguiente línea:
public void HelloWorld()
{
    Console.WriteLine("Hello world!");
}
Esto dará lugar a un extraño error sintáctico compilación que, situado en un lugar estratégico, hará que más de uno tenga que devanarse los sesos para descubrir dónde está el problema:
1>------ Build started: Project: TestApp, Configuration: Debug Any CPU ------
1>C:\Projects\TestApp\Program.cs(9,46,9,47): error CS1002: ; expected
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Hey, pero por si luego quieren matar a alguien, os adjunto un link a la fuente original, que mía no es la ocurrencia ;D
Replace a semicolon with a greek question mark

Publicado en Variable not found.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 27 de marzo de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 21 de marzo de 2017
ASP.NET Core MVCSabemos que mientras se renderiza una vista Razor, por defecto el framework MVC va almacenando el resultado en memoria, y sólo al finalizar es cuando comienza a retornarlo al lado cliente.

Por ejemplo, en la ejecución del siguiente código Razor, el usuario que solicitó la página no vería absolutamente nada durante 10 segundos, y de pronto le llegaría el resultado completo:
@using System.Threading.Tasks
@{
    Layout = null;
}
<html>
<head>
    <title>Hello world!</title>
</head>
<body>
    <h1>Let's go</>
    <ul>
        @for (int i = 0; i < 10; i++)
        {
            await Task.Delay(1000);
            <li>@i</li>
        }
    </ul>
</body>
</html>
Nota: Observad que para hacer el retardo, en lugar del típico Thread.Sleep() he utilizado Task.Delay() sólo para recordaros que en ASP.NET Core las vistas se renderizan/ejecutan en un contexto asíncrono y, por tanto, podemos utilizar en su interior llamadas con await como hacemos en otros puntos del código.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 20 de marzo de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET/.NET Core

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 14 de marzo de 2017
ASP.NET CoreEl sistema de inyección de dependencias de ASP.NET Core es un potente mecanismo que viene de serie en el framework y, que de hecho, es uno de los principales pilares en los que se basa su funcionamiento.

Probablemente sabréis (y si no, podéis echar un vistazo a este post) que existen diversas fórmulas para añadir servicios o componentes al contenedor de dependencias, y una de ellas es la denominada "Scoped". Estos componentes quedan registrados asociados a un ciclo de vida específico (ServiceLifetime.Scoped), que indica que cada vez que haya que se solicite un objeto de este tipo se retornará la misma instancia dentro el ámbito actual, que normalmente coincide con el proceso de una petición específica.

O en otras palabras, dentro de la misma petición, la instancia del componente será compartida por todos los objetos que dependan de él. Además, al finalizar el proceso de la petición, el framework invocará su método Dispose() (si existe, claro), permitiendo liberar los recursos que haya utilizado. Por ejemplo, suele ser una buena práctica emplear esta técnica para reutilizar un contexto de datos entre los servicios que participan en el proceso de una petición que accede a una base de datos, y asegurar su liberación final para no dejar conexiones abiertas.

Pero este post no va de ver cómo registrar estos componentes o de cómo utilizarlos en nuestras aplicaciones, sino de responder una simple curiosidad: ¿quién se encarga de crear este scope cuando comienza una petición y de liberarlo cuando finaliza? Ya, sé que no tiene mucha utilidad práctica en el día a día, pero es una buena excusa para echar un vistazo y entender cómo funcionan las cosas por dentro ;)

<Disclaimer>Todo lo que comentaremos a continuación son detalles de la implementación actual del framework y son válidos en la versión 1.1 de ASP.NET Core, pero podrían cambiar en futuras versiones.</Disclaimer>

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 13 de marzo de 2017
Enlaces interesantesAquí tenéis una nueva colección de enlaces interesantes, con especial atención al lanzamiento de Visual Studio 2017 :)

Por cierto, a partir de ahora voy a utilizar otro criterio de categorización, uniendo .NET y .NET Core en una única categoría, y haciendo lo mismo con ASP.NET y ASP.NET Core, porque cada vez iba teniendo menos sentido mantener esta separación.

Como siempre, espero que estos links os resulten interesantes. :-)

.NET/.NET Core

ASP.NET/ASP.NET Core

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Data

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Cross-platform

Otros


Publicado en Variable not found

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 7 de marzo de 2017
Publish Azure WebJobDesde hace algún tiempo estoy sufriendo un error que aparece justo en el momento de publicar un Webjob a Azure desde Visual Studio 2015.

Supongo que tendrá su motivo y se deberá a que estoy haciendo algo mal, pero bueno, el caso es que el error es un poco molesto porque impide la publicación del proyecto y, aunque no es difícil de solucionar, siempre me obliga a perder unos minutos en buscar una solución y aplicarla a mi proyecto.

El error que podemos ver en la ventana de resultados es el siguiente:
Error : El argumento 'DefaultConnection-Web.config Connection String' no puede ser NULL ni estar vacío.
O su versión en inglés:
Error : The 'DefaultConnection-Web.config Connection String' argument cannot be null or empty.
Así que, a modo de nota mental, y si acaso poder echar una mano a alguno que os encontréis ante el mismo escenario, comento dos soluciones que me han funcionado bien. Simplemente elegid la que más os convenza.

Solución 1

Es la más sencilla, y consiste únicamente en eliminar la carpeta /obj del proyecto en cuestión. Tras ello, volvemos a publicar y funcionará todo bien.

Solución 2

La segunda solución es algo más compleja, aunque tampoco para echarse las manos a la cabeza.

El problema está en el archivo de publicación (.pubxml) que estáis usando para publicar el WebJob, que por algún motivo ha perdido la cadena de conexión por defecto del proyecto. Podéis encontrarlo en la carpeta /Properties y tiene una sección como la siguiente:
<PublishDatabaseSettings>
  <Objects>
    <ObjectGroup Name="DefaultConnection" Order="1" Enabled="False" xmlns="">
      <Destination Path="" />
      <Object Type="DbCodeFirst">
        <Source Path="DBMigration" 
           DbContext="MyProject.MyDataContext, MyProject" 
           MigrationConfiguration="MyProject.Migrations.Configuration, MyProject" 
           Origin="Convention" />
      </Object>
    </ObjectGroup>
  </Objects>
</PublishDatabaseSettings>
Lo único que hay que hacer para poder publicar sin problema es transformar la cuarta línea (el tag <Destination>) de la siguiente forma:
<PublishDatabaseSettings>
  <Objects>
    <ObjectGroup Name="DefaultConnection" Order="1" Enabled="False" xmlns="">
      <Destination Path="{deployment connection string}" /> 
      <Object Type="DbCodeFirst">
        <Source Path="DBMigration" 
           DbContext="MyProject.MyDataContext, MyProject" 
           MigrationConfiguration="MyProject.Migrations.Configuration, MyProject" 
           Origin="Convention" />
      </Object>
    </ObjectGroup>
  </Objects>
</PublishDatabaseSettings>
Es decir, establecemos el atributo Path del tag <Destination> al valor "{deployment connection string}" y lo tendremos solucionado.

¡Y eso es todo! En fin, este post trata sobre esos misterios que suceden de vez en cuando y nos hacen dedicar minutos de nuestro preciado tiempo a labores de fontanería. Espero que lo descrito aquí os sea de utilidad en algún momento... o no, porque significaría que no se os ha dado nunca este caso, y eso no es mala cosa ;)

Publicado en Variable not found.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 6 de marzo de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 27 de febrero de 2017
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 21 de febrero de 2017
Aunque IIS Express está diseñado principalmente para ser utilizado por desarrolladores en el interior su equipo de trabajo, seguro que la mayoría sabéis que haciendo un par de cambios en la configuración también es posible utilizarlo desde equipos externos, por ejemplo para poder hacer pruebas de una web o servicio desde otros dispositivos conectados a la misma red.

Es sencillo encontrar cómo hacerlo porque hay mucho escrito al respecto en la red, y sin embargo de vez en cuando me encuentro con desarrolladores que no saben que esto es posible hacerlo, así que este post va por vosotros ;D

Partiremos de un proyecto ASP.NET 4.x creado en Visual Studio 2015 o 2017, da igual si se trata de una aplicación MVC, Web Forms, Web API o lo que sea. Para desarrollar el ejemplo, imaginemos que al ejecutarlo en local estamos usando la URL http://localhost:3803/.

Veamos paso a paso cómo acceder a esta aplicación desde otro equipo conectado a la red local, y cómo solucionar algunos de los problemas que podemos encontrar por el camino.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 20 de febrero de 2017
Happy 15th Birthday .NET!Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 14 de febrero de 2017
ASP.NET CoreHace algunos meses comentábamos por aquí cómo en ASP.NET Core es posible modificar los archivos de configuración de una aplicación en caliente, sin necesidad de detenerla, siendo los cambios aplicados de forma inmediata.

En aquél momento ya vimos que era realmente sencillo conseguirlo cuando usábamos settings no tipados, bastaba con añadir el parámetro reloadOnChanges a la hora de añadir el origen de configuración, como en el siguiente ejemplo:
public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddEnvironmentVariables();
    Configuration = builder.Build();
}
Sin embargo, también vimos que conseguir lo mismo cuando queríamos acceder a los settings de forma tipada era algo más engorroso, puesto que había que configurar manualmente el proceso de recarga y bindeado de datos con la instancia de la clase de configuración, para poder acceder luego a ella a través de un objeto IOptions<T> disponible en el contenedor de dependencias.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

lunes, 13 de febrero de 2017

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

martes, 7 de febrero de 2017
ASP.NET Core MVCDurante el proceso de negociación de contenidos en un API desarrollado con ASP.NET Core MVC, lo habitual es que el output formatter utilizado para componer el resultado enviado de vuelta al cliente sea seleccionado a partir de lo indicado por el cliente en la cabecera Accept de la petición HTTP, pero en este post vamos a ver que esto no tiene por qué ser necesariamente así.

Por ejemplo, supongamos que tenemos una aplicación MVC con un controlador que expone un servicio como el siguiente:
[Route("api/contacts")]
public class ContactsController : Controller
{
    private readonly IContactRepository _repository;

    public ContactsController(IContactRepository repository)
    {
        _repository = repository;
    }

    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        var contact = _repository.Get(id);
        if (contact == null)
            return NotFound();
        return Ok(contact);
    }
}
Esta acción, que retornaría un objeto de tipo Contact del modelo de nuestra aplicación, podría ser fácilmente utilizada desde otras capas o sistemas, por ejemplo como sigue:
// Petición:
GET http://localhost:2805/api/contacts/1 HTTP/1.1 
Accept: application/json

// Respuesta:
HTTP/1.1 200 OK 
Content-Type: application/json; charset=utf-8  
Content-Length: 51

{"id":1,"name":"John Smith","phone":"998-12-32-12"}

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons