Blazor · Laboratorio
Vas a armar tu primera página en Blazor con Rider: una lista de tareas que agrega, edita y quita a través de un servicio inyectado. Después abrís dos pestañas, cambiás una sola palabra en Program.cs y mirás qué pasa con los datos.
dotnet --version # tiene que empezar con 9
Blazor Web App · net9.0
En Rider elegí . En el panel de la izquierda, dentro del grupo .NET, hacé click en . Completá así:
LabBlazor — así tus namespaces coinciden con los del ejercicionet9.0 (debería decir from SDK 9.0)Apretá .
Si el asistente de Rider te da problemas, abrí la terminal de Rider en una carpeta vacía y pegá esto. Después y elegí el archivo LabBlazor.csproj.
dotnet new blazor -o LabBlazor -int Server # crea la carpeta LabBlazor con el proyecto
Dale ▶ Run (o Shift+F10) para confirmar que arranca. Después detenela con ■ Stop antes de seguir.
Now listening on: http://localhost:PUERTO. Quiere decir que tu aplicación ya está andando en tu propia computadora: localhost significa «esta máquina» y PUERTO es el número de la «puerta» por la que atiende (Rider elige uno y puede ser distinto en cada proyecto).@page + contenido + @code
Click derecho sobre la carpeta Components/Pages → . Nombre: Tareas. No elijas Razor Page, que está justo debajo: crea otro tipo de página que no sirve para este ejercicio. Borrá todo lo que traiga el archivo y pegá esto:
@page "/tareas"
<PageTitle>Tareas</PageTitle>
<h1>Mis tareas</h1>
<p>Primera página Blazor de: <strong>@integrantes</strong></p>
<ul>
<li>Tarea de ejemplo 1</li>
<li>Tarea de ejemplo 2</li>
</ul>
@code {
// TODO 1: escribí los nombres de tu equipo entre las comillas
private string integrantes = "";
}
Ahora ▶ Run y, en la barra de direcciones, escribí a mano http://localhost:PUERTO/tareas.
@page "/tareas" es la que crea la ruta: el nombre del archivo no importa. Lo que empieza con @ es C# metido dentro del HTML.
una clase que guarda y modifica tareas
Click derecho sobre el proyecto LabBlazor → , nombre TareaServicio. Reemplazá todo el contenido por esto. No hay nada que completar: es el servicio ya armado.
namespace LabBlazor;
public class Tarea
{
public int Id { get; set; }
public string Titulo { get; set; } = "";
}
public class TareaServicio
{
private readonly List<Tarea> _tareas = new();
private int _proximoId = 1;
// Un código corto para reconocer cuál instancia del servicio estás usando.
public string IdInstancia { get; } = Guid.NewGuid().ToString("N")[..6];
public IReadOnlyList<Tarea> Listar() => _tareas;
public void Agregar(string titulo)
{
_tareas.Add(new Tarea { Id = _proximoId++, Titulo = titulo });
}
public void Quitar(int id)
{
_tareas.RemoveAll(t => t.Id == id);
}
public void Editar(int id, string nuevoTitulo)
{
var tarea = _tareas.FirstOrDefault(t => t.Id == id);
if (tarea is not null) tarea.Titulo = nuevoTitulo;
}
}
Fijate en tres cosas, porque las vamos a usar durante todo el ejercicio:
Tarea es la entidad: tiene un Id y un Titulo.TareaServicio guarda la lista en memoria y sabe Listar, Agregar, Quitar y Editar.IdInstancia es un código al azar que se genera una sola vez, cuando se crea el objeto. Sirve para reconocer qué instancia del servicio estamos usando.Compilá desde la terminal de Rider:
dotnet build # tiene que terminar en "Build succeeded."
Build succeeded. sin errores.
Program.cs + @inject + CRUD en pantalla
Program.cs: ■ Stop y después ▶ Run. Con la app corriendo el cambio parece guardado, pero no se aplica: sigue funcionando la versión vieja y no da ningún error. Rider tiene una opción para que los cambios se actualicen sin reiniciar (se llama Hot Reload), pero buscarla queda por cuenta de cada uno.
3A · Registrar el servicio. Program.cs es el archivo donde se configuran los servicios de la aplicación: ahí le decimos al contenedor de inyección de dependencias qué servicios existen y con qué «vida» (Scoped o Singleton). Después, cada página los pide con @inject, que es lo que vas a hacer en 3B.
Abrí Program.cs y completá el TODO 2. El contenedor se arma en Build(), así que la línea tiene que quedar antes:
using LabBlazor; var builder = WebApplication.CreateBuilder(args); // ... acá quedan las líneas que ya traía la plantilla ... // TODO 2: registrar TareaServicio en el contenedor con vida Scoped var app = builder.Build(); // <- todo lo de arriba tiene que ir ANTES de esta línea
builder.Services.AddScoped<MiClase>();. El nombre del método elige la vida del servicio (AddScoped, AddSingleton o AddTransient) y entre los signos <> va el nombre de la clase que querés registrar.
3B · Inyectar y conectar la página. Reemplazá todo el contenido de Tareas.razor por esto. Rider va a marcar en rojo Servicio hasta que resuelvas el TODO 3:
@page "/tareas"
@rendermode InteractiveServer
@* TODO 3: inyectá acá el servicio (tipo TareaServicio, nombre Servicio) *@
<PageTitle>Tareas</PageTitle>
<h1>Mis tareas</h1>
<p>
Instancia del servicio:
<strong>@(RendererInfo.IsInteractive ? Servicio.IdInstancia : "conectando…")</strong>
</p>
<input class="form-control mb-2" @bind="texto" @bind:event="oninput" placeholder="Título de la tarea" />
<button class="btn btn-primary mb-3" @onclick="Guardar">@(editandoId is null ? "Agregar" : "Guardar cambios")</button>
<ul>
@foreach (var t in Servicio.Listar())
{
<li>
@t.Titulo
<button class="btn btn-sm btn-outline-secondary" @onclick="() => Editar(t)">Editar</button>
<button class="btn btn-sm btn-outline-danger" @onclick="() => Quitar(t.Id)">Quitar</button>
</li>
}
</ul>
@code {
private string texto = "";
private int? editandoId;
private void Guardar()
{
if (string.IsNullOrWhiteSpace(texto)) return;
if (editandoId is null)
{
// TODO 4: agregar la tarea usando el servicio
}
else
{
// TODO 5: editar la tarea usando el servicio
}
texto = "";
editandoId = null;
}
private void Editar(Tarea t)
{
editandoId = t.Id;
texto = t.Titulo;
}
private void Quitar(int id)
{
// TODO 6: quitar la tarea usando el servicio
}
}
@inject TipoDelServicio NombreQueElijas. Primero va el tipo (la clase del servicio) y después el nombre con el que lo vas a usar en el resto de la página: fijate cuál aparece en el código de arriba. Los TODO 4, 5 y 6 se resuelven llamando a los métodos del servicio. Mirá qué métodos tiene TareaServicio (paso 2) y qué datos necesita cada uno. La línea @rendermode InteractiveServer ya viene puesta: es la que hace que los botones respondan.
InvalidOperationException que dice Cannot provide a value for property 'Servicio'… There is no registered service of type… significa que falta el TODO 2: el servicio está pedido pero nunca fue registrado.
3C · Probar. ▶ Run, abrí /tareas y agregá tres tareas, editá una y quitá otra.
new TareaServicio() y aun así Servicio tiene una instancia lista para usar. ¿Quién la creó? ¿Cuándo?
dos pestañas + F5
Sin tocar nada del código, vas a mirar lo mismo desde dos pestañas. Escribí tu predicción antes de mirar.
/tareas) dejá las tareas que ya cargaste y anotá el código de instancia.http://localhost:PUERTO/tareas. Anotá qué lista ve y su código.| Qué hicimos | Predicción (antes de mirar) | Qué pasó |
|---|---|---|
| Abrimos B con la misma dirección | ||
| Agregamos una tarea en B y volvemos a A | ||
| F5 en A |
de Scoped a Singleton
Ahora el cambio de una sola palabra. El resto del código no se toca.
Program.cs, resolvé el TODO 7:// TODO 7: cambiá SOLO la palabra Scoped por Singleton (misma línea, no agregues otra) builder.Services.AddScoped<TareaServicio>();
/tareas (será la pestaña A).| Qué hicimos | Predicción (antes de mirar) | Qué pasó |
|---|---|---|
| Abrimos B con la misma dirección | ||
| Agregamos una tarea en B y volvemos a A sin tocar nada | ||
| F5 en A | ||
| ■ Stop y ▶ Run (se reinicia la app) |
NavMenu.razor + NavLink
Hasta ahora llegabas a tu página escribiendo /tareas a mano. En este paso la conectás al menú lateral, para entrar desde la Home con un click y volver, sin tocar la barra de direcciones.
Abrí Components/Layout/NavMenu.razor. Ahí está el menú lateral: cada opción (Home, Counter, Weather) es un bloque con un NavLink.
TODO 8: agregá una opción nueva, debajo de las que ya están, que lleve a tu página de tareas.
NavLink lleva a otra página con su atributo href (la ruta que definiste con @page) y muestra el texto que pongas adentro. Lo más simple es copiar una de las opciones que ya existen, pegarla debajo y cambiar la ruta y el texto.
Detené la app con ■ Stop y volvé a correrla con ▶ Run. Se abre en la Home, en la dirección de siempre, sin /tareas. Probá el recorrido completo: entrá a tu página desde el menú, volvé a la Home desde el menú y entrá de nuevo.
bool Hecha a Tarea y un botón para marcarla como hecha.