Saltar al contenido

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

18 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 Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
Mostrando entradas con la etiqueta aspnetcoremvc. Mostrar todas las entradas
Mostrando entradas con la etiqueta aspnetcoremvc. Mostrar todas las entradas
jueves, 13 de junio de 2024
Blazor

Este post pertenece a una serie de tres partes donde estamos viendo cómo renderizar componentes Blazor en el interior de vistas MVC de ASP.NET Core. Hasta ahora, hemos visto cómo renderizar desde vistas MVC componentes Blazor usando los siguientes modos de renderización:

En esta entrega final veremos cómo renderizar componentes Blazor ejecutados por completo en el lado cliente (WebAssembly).

miércoles, 12 de junio de 2024
Blazor

Este post pertenece a una serie de tres partes donde estamos viendo cómo renderizar componentes Blazor en vistas MVC de ASP.NET Core.

En la primera parte de la serie vimos cómo renderizar componentes estáticos (SSR) en servidor, y ahora vamos a centrarnos en hacerlo con componentes con interactividad también en el lado servidor (Blazor Server), dejando para una siguiente entrega los componentes interactivos ejecutados por completo en cliente con WebAssembly.

martes, 11 de junio de 2024
Blazor

Hace no demasiado, mientras analizábamos la posibilidad de que Blazor acabara en algún momento sustituyendo a MVC como tecnología "por defecto" para el desarrollo de aplicaciones web en .NET, comentaba que técnicamente no hay nada que impida a ambas tecnologías convivir pacíficamente en una misma aplicación. De hecho, están diseñadas para trabajar juntas :)

En este sentido, uno de los escenarios soportados es la inserción de componentes Blazor en el interior de vistas de una aplicación ASP.NET Core MVC. Esto puede ser muy interesante, entre otros casos, si queremos ir introduciendo Blazor progresivamente en aplicaciones MVC existentes o para reutilizar componentes entre distintos proyectos.

En esta miniserie vamos a ver cómo conseguirlo con los distintos modos de renderizado de Blazor, porque cada uno tiene sus particularidades:

martes, 9 de abril de 2024
Blazor

Este tema lo he debatido con colegas en varias ocasiones y creo que abordarlo aquí puede resultar interesante para algunos más que os estéis preguntando lo mismo a raíz de la tracción que, poco a poco, va tomando Blazor entre los desarrolladores web que trabajamos con el stack de tecnologías de Microsoft.

Voy a explicar mi punto de vista al respecto contemplando dos aspectos distintos, que creo que son los fundamentales para poder responder apropiadamente a esta pregunta:

  • Si técnicamente sería posible reemplazar MVC por Blazor, esto es, si Blazor dispone de mecanismos suficientes para cubrir las necesidades de una aplicación que tradicionalmente se desarrollaría con MVC.
  • Si la popularidad y difusión de Blazor podría llegar a alcanzar las cotas suficientes para convertirse en una alternativa completa y segura a MVC, en términos de madurez, estabilidad, soporte y tamaño de la comunidad. O en otras palabras, si Blazor como producto llegará a estar lo suficientemente consolidado como para poder reemplazar a MVC.

Vamos a analizar cada una de ellas.

Disclaimer: obviamente, todo lo que veréis a continuación son opiniones personales y, como tales, pueden ser discutibles. Si tenéis una opinión diferente, estaré encantado de leerla en los comentarios.

martes, 26 de abril de 2022
ASP.NET Core

Imaginad que tenemos un controlador MVC como el siguiente:

public class TestController : Controller
{
    public IActionResult Add(int a, int b)
    {
        return Content($"Result: {a + b}");
    }
}

Claramente, la acción Add() retornará la suma de los enteros a y b que le llegarán como parámetros de la query string:

GET https://localhost:7182/test/add?a=1&b=2 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

Result: 3

Pero, como sabemos, podríamos llamar a la acción sin indicar alguno de esos parámetros, o incluso ninguno de ellos:

Petición Respuesta
GET /test/add?a=1&b=2 Result: 3
GET /test/add?a=0&b=0 Result: 0
GET /test/add?a=1 Result: 1
GET /test/add Result: 0

Esto es así porque el binder será capaz de poblar correctamente los parámetros a y b cuando estén presentes en la cadena de la petición y sean correctos, o les asignará su valor por defecto (0) cuando no hayan sido suministrados.

Pero dado que el cero es un valor de entrada válido, a priori desde nuestro código no tendríamos forma de distinguir cuándo el parámetro ha sido omitido y cuándo se ha establecido expresamente.

¿Cómo podríamos hacerlo?

martes, 29 de marzo de 2022
ASP.NET Core

A veces, sobre todo en aplicaciones muy grandes, con las definiciones de rutas muy complejas o cuando nos toca analizar aplicaciones ajenas, puede ser interesante saber qué punto del código está procesando una petición determinada, ya sea un endpoint definido usando Endpoint Routing o Minimal APIs o bien sea una acción de un controlador MVC.

En este post vamos a ver cómo conseguirlo de forma muy sencilla, mediante la implementación un pequeño middleware que, insertado en el pipeline, añadirá en el encabezado información sobre el handler que generó la respuesta de la petición actual.

martes, 8 de febrero de 2022
ASP.NET Core MVC

Dada una petición como la siguiente:

POST https://localhost:5001/friends HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{ "name": "Jon", "age": 24 }

Lo habitual es que queramos recibir los datos ya materializados en forma de objeto de .NET. Esto podemos conseguirlo fácilmente desde una acción como la siguiente:

[Route("friends")]
public class FriendsController : Controller
{
    [HttpPost]
    public ActionResult Test([FromBody]Friend friend)
    {
        return Content($"Hello, {friend.Name}, you are {friend.Age} years old");
    }
}

Pero aunque no es algo que ocurra con frecuencia, a veces podríamos necesitar recibir el cuerpo JSON de una petición como string, es decir, en crudo, sin deserializarlo ni procesarlo de ninguna manera para, ya más adelante, hacerlo nosotros manualmente. Y aunque a primera vista pudiera resultar trivial, tiene un poco más de truco de lo que parece...

martes, 31 de marzo de 2020
ASP.NET Core Como sabemos, hasta ASP.NET Core 2.2, registrábamos los servicios de MVC y Razor Pages en el método ConfigureServices() de la clase Startup con una línea como la siguiente:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    ...
}
Esto era todo lo que necesitábamos para poder utilizar cualquiera de estas tecnologías en nuestra aplicación. Sin embargo, a partir de ASP.NET Core 3.0, nuestro intellisense se vio inundado de opciones adicionales como AddControllers(), AddRazorPages() AddControllersWithViews().

¿Para qué sirven, y por qué ha sido necesario introducir estos nuevos extensores?
martes, 18 de febrero de 2020
ASP.NET Core MVC En muchas ocasiones, la llegada de una nueva versión de un framework viene acompañada de documentación, posts y otro tipo de contenidos que anuncian a bombo y platillo las principales novedades y cambios introducidos. Ante este ruido, es fácil pasar por alto otros pequeños cambios que introducen mejoras a los marcos de trabajo o simplemente permiten ir evolucionando código antiguo a funcionalidades más recientes.

Hoy vamos a hablar de una de eso pequeños descubrimientos: el rutado dinámico de controladores. Introducido en ASP.NET Core 3, se trata de una característica que no ha sido especialmente publicitada ni comentada, pero puede ser de utilidad en algunas ocasiones, pues permite interferir en la forma de interpretar las rutas de las peticiones entrantes con objeto de decidir en cada caso cómo deben ser procesadas.
martes, 4 de febrero de 2020
Open API Días atrás veíamos cómo utilizar Swashbuckle para generar automáticamente la descripción OpenAPI de APIs creadas con ASP.NET Core MVC y ponerlas a disposición de los consumidores en una ruta específica:
  Descripción OpenAPI de una API

En este post vamos a ver un par de formas de sacar provecho de esta descripción:
  • En primer lugar, usaremos Swagger UI para generar un sitio web interactivo de documentación y pruebas de nuestra API.
  • Después, veremos cómo generar desde Visual Studio código cliente para acceder a la API.
martes, 28 de enero de 2020
Open API La OpenAPI Specification (OAS) es un estándar abierto para la descripción de APIS REST promovido por la Iniciativa OpenAPI, un consorcio de compañías de primer nivel como Microsoft, Google, IBM, Paypal y otros.

El objetivo de OpenAPI es conseguir una fórmula normalizada para describir las capacidades de un servicio REST, independientemente de los lenguajes o tecnologías con las que sea implementado. Esta descripción, normalmente especificada en formato JSON o YAML, permite a clientes (sean humanos o máquinas) descubrir servicios, comprender sus capacidades y conocer sus detalles de funcionamiento sin necesidad de tener acceso a su código fuente o documentación textual.

Esta especificación formal abre interesantes posibilidades, pues a partir de la definición estandarizada de servicios es posible, entre otros,
  • disponer de herramientas de diseño y modelado de servicios,
  • generar automáticamente páginas de documentación,
  • generar automáticamente código cliente y servidor para dichos servicios para distintos, frameworks y lenguajes de programación,
  • generar automáticamente código de testing y validaciones,
  • o generar automáticamente mocks de servicios.

martes, 14 de enero de 2020
ASP.NET Core Las Razor Class Libraries (RCL) constituyen una interesante fórmula para crear componentes redistribuibles de interfaz de usuario para aplicaciones basadas en ASP.NET Core MVC o Razor Pages. En las bibliotecas de clases de este tipo podemos incluir controladores, view components, tag helpers o vistas y páginas Razor, elementos que estarán disponibles en las aplicaciones que las referencien, bien directamente o bien a través del paquete NuGet en el que las distribuyamos.

Sin embargo, es menos conocido el hecho de que estas bibliotecas pueden incluir también recursos estáticos como imágenes, hojas de estilo o scripts, lo que resulta bastante interesante a la hora de crear componentes totalmente autosuficientes y muy reutilizables.

En este post vamos a ver cómo crear una RCL redistribuible que definirá el tag helper <mario>, cuya inclusión en una página hará que ésta muestre el conocido personaje correteando por la pantalla, como se muestra en la siguiente captura:

Mario corriendo por la pantalla
martes, 26 de noviembre de 2019
ASP.NET CoreHace ya algún tiempo nos preguntábamos que dónde había ido a parar la directiva @helper de Razor en ASP.NET Core, y la respuesta era simple: había desaparecido.

Como recordaréis, esta directiva era bastante útil para simplificar el código de las vistas y mejorar su legibilidad, pues permitía crear funciones reutilizables que mezclaban HTML y código de servidor, como en el siguiente ejemplo:
@* File: Test.cshtml *

@Multiplication(2)
@Multiplication(3)

@helper Multiplication(int x)
{
    <h2>Multiplication table of @x</h2>
    <ul>
        @for (var i = 1; i <= 10; i++)
        {
            <li>@x * @i = @(x * i)</li>
        }
    </ul>
}
Hasta la versión 2.2, teníamos que conformarnos con apaños como los descritos en aquél post si queríamos emular lo que llevábamos tantos años utilizando con MVC 5 y anteriores. Y también entonces comentamos que había ciertas posibilidades de que en algún momento volviera a la vida, y éstas se han materializado, por fin, en ASP.NET Core 3.0.

Aunque quizás más bien habría que hablar de reencarnación...
martes, 12 de noviembre de 2019
ASP.NET Core MVCUn alumno del curso de ASP.NET Core 3 en CampusMVP, me preguntaba hace unos días qué había pasado con la llamada al método SetCompatibilityVersion() que veíamos en la plantilla de proyectos ASP.NET Core MVC y Razor Pages desde la versión 2.1:
public void ConfigureServices(IServiceCollection services)
{
   services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
Esta llamada era incluida de serie en los nuevos proyectos ASP.NET Core desde la versión 2.1, pero en la versión 3.0 ya no aparece. Y probablemente también os llame la atención a quienes ya habéis trabajado con ASP.NET Core 2.x, así que he pensado que sería interesante comentarlo por aquí.
martes, 1 de octubre de 2019
ASP.NET Core MVC La compilación de vistas y páginas Razor es una de esas features de ASP.NET Core que ha ido dando tumbos y evolucionando a lo largo de las distintas versiones del framework, algunas veces por necesidades técnicas y otras por la búsqueda del funcionamiento más correcto. De hecho, a lo largo de la historia de este blog creo que debe haber pocas cosas de las que haya hablado en tantas ocasiones porque, además, es una característica que me encanta.

Bueno, la cuestión es que en ASP.NET Core 3.0 ha vuelto a cambiar, y esperemos que sea por última vez ;)

Veamos en qué han consistido estos cambios.
miércoles, 25 de septiembre de 2019
CURSO DE ASP.NET Core 3 MVC

Seguramente estáis al tanto de que Microsoft acaba de anunciar la disponibilidad de .NET Core 3.0 y tecnologías relacionadas, incluyendo ASP.NET Core 3.0.

Pues bien, me complace anunciaros que, sólo un día más tarde, desde CampusMVP hemos lanzado el nuevo curso Desarrollo Web con ASP.NET Core 3 MVC.

Se trata de una  gran revisión del curso de desarrollo con ASP.NET Core MVC que ha formado ya con éxito a cientos de desarrolladores de todo el mundo, en la que hemos introducido los cambios y novedades que han venido de la mano de la nueva versión del framework.

En este post intentaremos responder a las siguientes preguntas:
martes, 24 de septiembre de 2019
ASP.NET Core 3 Como seguro sabréis, hace pocas horas se ha lanzado, en el marco del evento .NET Conf 2019, una nueva oleada de actualizaciones de las principales tecnologías y frameworks "Core":
  • .NET Core 3.0
  • C# 8
  • ASP.NET Core 3.0
  • Blazor server-side
  • Entity Framework Core 3.0
  • Entity Framework 6.3 (sí, ¡compatible con .NET Core!)
  • SignalR 3.0
  • ML.NET
  • Soporte WinForms y WPF para .NET Core 3
  • Visual Studio 2019 16.3
En lo relativo a ASP.NET Core no es que haya sido una auténtica revolución pero, aún así, ASP.NET Core 3.0 trae novedades que vale la pena conocer:
  • Simplificación del archivo de proyecto .csproj
  • Uso del host genérico
  • Introducción del endpoint routing
  • Mayor modularidad en el registro de servicios de MVC
  • Nuevo serializador/deserializador JSON (bye bye, JSON.NET!)
  • Compatibilidad exclusivamente con .NET Core (bye bye, target .NET Framework!)
  • Limpieza de Microsoft.AspNetCore.App
  • Cambios en la compilación de vistas
  • Soporte para gRPC
  • Y, por supuesto, muchas otras mejoras...
Si os interesa conocer más, he publicado en el blog de CampusMVP un artículo detallando estas novedades:

       Novedades de ASP.NET Core 3.0

¡No os lo perdáis!

Publicado en: www.variablenotfound.com.
martes, 2 de abril de 2019
ASP.NET Core Hace unas semanas, el amigo J. Roldán escribía un comentario en el post Inyección de dependencias en ASP.NET Core con una pregunta interesante sobre la forma de registrar determinados componentes en el inyector de dependencias. Básicamente la duda que planteaba era cómo asociar distintas interfaces a una única instancia, algo que, aunque no es complicado de conseguir, tampoco tiene una solución precisamente intuitiva.

El problema

En el escenario concreto que planteaba nuestro querido lector era que quería proporcionar, a los componentes que necesitaban acceder a datos en su aplicación, un acceso limitado al contexto de datos de Entity Framework.

Para ello, por un lado definía una interfaz parecida a la siguiente, que proporcionaba acceso a los repositorios:
public interface IUserRepositories
{
    DbSet<User> Users { get; }
    ...
}
Por otra parte, definía otra interfaz que era la que permitía comprometer cambios (adiciones, supresiones, modificaciones) realizadas en el contexto de datos:
public interface IUnitOfWork
{
    int SaveChanges();
}
La idea de esta separación es que si un componente necesitaba exclusivamente consultar datos relativos a usuarios, sólo recibiría mediante inyección de dependencias la instancia de IUserRepositories, mientras que si necesitaba persistir datos, recibiría adicionalmente un objeto IUnitOfWork, por ejemplo:
public class UserServices
{
    ...
    public UserServices(IMapper mapper, IUserRepositories userRepos, IUnitOfWork uow) 
    { 
        _mapper = mapper;
        _userRepos = userRepos;
        _uow = uow;
    }

    public async Task Update(int id, UserDto user) 
    {
        var user = await _userRepos.Users.FirstOrDefaultAsync(u=>u.Id == id);
        if(user == null)
            throw new Exception();
        
        _mapper.Map(userDto, user);
        await _uof.SaveChangesAsync();
    }
}
Bien, pues el problema lo tenía precisamente a la hora de registrar las dependencias de forma apropiada.

martes, 19 de febrero de 2019
ASP.NET Core MVCUna gestión apropiada de la caché es muchas veces el secreto para los sistemas de alto rendimiento o que tienen que atender a una gran carga de peticiones por segundo, y el framework ASP.NET Core MVC incluye numerosas herramientas para ello.

Entre otras, el tag helper <cache> es especialmente útil para almacenar en la memoria del servidor el resultado de procesar una porción de página o vista, de forma que pueda ser reutilizada en peticiones siguientes. Un ejemplo bastante básico, pero que deja bastante clara su utilidad y forma de uso, podría ser el siguiente:
<h1>Atomic clock</h1>
<cache expires-after="@TimeSpan.FromSeconds(30)">
    @{
        await Task.Delay(3000);
    }
    Current time: @DateTime.UtcNow.ToLongTimeString()
</cache>
Al acceder a una vista con el código anterior por primera vez, se producirá un retardo forzado de tres segundos, se renderizará el interior del tag <cache> mostrando la hora actual, y el resultado será almacenado en memoria durante 30 segundos.

Si volvemos a acceder a la misma vista durante esos 30 segundos, el resultado será mostrado inmediatamente (sin esperar los tres segundos) y el cliente recibirá el contenido que se cacheó durante la primera visita. Al transcurrir este plazo, en la siguiente petición se volverá a procesar el contenido del tag helper, ejecutándose la espera y volviendo a generar y cachear el resultado enviado al cliente.

Pero podemos tener ejemplos algo más complejos, como el siguiente. En el interior del tag helper hemos insertado un view component que podría mostrar las últimas noticias obtenidas de una base de datos, en lo que podría ser la página de inicio de un servicio de información on-line:
<section>
    <h1>Latest news</h1>
    <cache expires-after="@TimeSpan.FromSeconds(30)">
        <vc:latest-news></vc:latest-news>
        <p>
            Updated at: @DateTime.UtcNow.ToLongTimeString()
        </p>
    </cache>
</section>
Fijaos que en este caso el tiempo de invalidación del contenido almacenado en caché no tendría sentido que fuera periódico: ¿para qué invalidar la caché y volver a obtener las noticias de la base de datos cada X segundos si quizás no se ha introducido ninguna nueva desde la última vez que se renderizó la página? ¿No sería mejor recargar la caché sólo cuando se hayan modificado las noticias?
martes, 12 de febrero de 2019
ASP.NET Core Como sabemos, ASP.NET Core incluye un sistema de inyección de dependencias que, aunque es algo simple comparado con otras alternativas más veteranas, cubre la mayoría de necesidades habituales. Por ejemplo, un aspecto que no es muy conocido y que puede ser útil en muchas ocasiones es su capacidad para registrar y recuperar múltiples implementaciones de una misma interfaz.

En este post vamos a ver cómo conseguirlo, y un caso práctico de uso de esta técnica en un escenario muy frecuente.