Comparteix a través de


Integrar componentes de ASP.NET Core Razor en aplicaciones de ASP.NET Core

En este artículo se explican escenarios de integración de los componentes Razor para aplicaciones ASP.NET Core.

Integración de componentes Razor

Los componentes Razor se pueden integrar en Razor Pages, MVC y otros tipos de aplicaciones ASP.NET Core. Los componentes Razor también se pueden integrar en cualquier aplicación web, incluidas las aplicaciones que no se basan en ASP.NET Core, como elementos HTML personalizados.

Usa la guía de las secciones siguientes en función de los requisitos de la aplicación:

Usar componentes no enrutables en páginas o vistas

Usa la siguiente guía para integrar componentes Razoren páginas o vistas de una aplicación RazorPages o MVC existente con el Asistente de etiqueta de componente.

Nota:

Si tu aplicación requiere componentes enrutables directamente (no insertados en páginas o vistas), omite esta sección y usa la guía de la sección Agregar compatibilidad con Blazor a una aplicación ASP.NET Core.

Cuando se usa la representación previa del servidor y la página o vista se representa:

  • El componente se representa previamente con la página o la vista.
  • Se pierde el estado inicial del componente que se usa para la representación previa.
  • Cuando se establece la conexión SignalR, se crea un estado del componente.

Para obtener más información sobre los modos de representación, incluida la representación de componentes estáticos no interactivos, consulta Asistente de etiqueta de componente en ASP.NET Core. Para guardar el estado de los componentes representados previamente Razor, consulta Asistente de etiqueta del estado del componente persistente en ASP.NET Core.

Agrega una carpeta Components a la carpeta raíz del proyecto.

Agrega un archivo de importación a la carpeta Components con el siguiente contenido. Cambia el marcador de posición {APP NAMESPACE} al espacio de nombres del proyecto.

Components/_Imports.razor:

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using {APP NAMESPACE}
@using {APP NAMESPACE}.Components

En el archivo de diseño del proyecto (Pages/Shared/_Layout.cshtml en aplicaciones Razor Pages o Views/Shared/_Layout.cshtml en aplicaciones MVC):

  • Agrega la etiqueta <base> siguiente y el asistente de etiqueta de componente para un componente HeadOutlet al marcado <head>:

    <base href="~/" />
    <component type="typeof(Microsoft.AspNetCore.Components.Web.HeadOutlet)" 
        render-mode="ServerPrerendered" />
    

    El valor href (la ruta de acceso base de la aplicación) del ejemplo anterior da por hecho que la aplicación reside en la ruta de acceso URL raíz (/). Si la aplicación es una subaplicación, sigue las instrucciones de la sección Ruta base de la aplicación del artículo Hospedaje e implementación de ASP.NET Core Blazor.

    El componente HeadOutlet se usa para representar el contenido principal (<head>) para los títulos de página (componente PageTitle) y otros elementos principales (componente HeadContent) establecidos por componentes Razor. Para obtener más información, consulta Control del contenido principal en aplicaciones Blazor de ASP.NET Core.

  • Agrega una etiqueta <script> para el script blazor.web.js inmediatamente antes de la sección de representación Scripts (@await RenderSectionAsync(...)):

    <script src="_framework/blazor.web.js"></script>
    

    El marco Blazor agrega automáticamente el script blazor.web.js a la aplicación.

Nota:

Normalmente, el diseño se carga a través de un archivo _ViewStart.cshtml.

Agrega un componente App no operativo (no-op) al proyecto.

Components/App.razor:

@* No-op App component *@

Donde se registran los servicios, agrega servicios para componentes Razor y servicios para admitir la representación de componentes del servidor interactivos.

En la parte superior del archivo Program, agrega una instrucción using a la parte superior del archivo para los componentes del proyecto:

using {APP NAMESPACE}.Components;

En la línea anterior, cambia el marcador de posición {APP NAMESPACE} al espacio de nombres de la aplicación. Por ejemplo:

using BlazorSample.Components;

En el archivo Program antes de la línea que compila la aplicación (builder.Build()):

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

Para obtener más información sobre cómo agregar compatibilidad con los componentes de servidor y WebAssembly, consulta Modos de representaciónBlazor de ASP.NET Core.

En el archivo Program inmediatamente después de la llamada a asignar Razor Pages (MapRazorPages) en una aplicación de Razor Pages o para asignar la ruta predeterminada del controlador (MapControllerRoute) en una aplicación MVC, llama a MapRazorComponents para detectar componentes disponibles y especificar el componente raíz de la aplicación (el primer componente cargado). De forma predeterminada, el componente raíz de la aplicación es el componente App (App.razor). Encadena una llamada a AddInteractiveServerRenderMode para configurar la representación interactiva del lado servidor (SSR interactiva) para la aplicación:

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

Nota:

Si la aplicación aún no se ha actualizado para incluir el middleware de antifalsificación, agrega la línea siguiente después de llamar a UseAuthorization:

app.UseAntiforgery();

Integra los componentes en cualquier página o vista. Por ejemplo, agrega un componente EmbeddedCounter a la carpeta Components del proyecto.

Components/EmbeddedCounter.razor:

<h1>Embedded Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Razor Pages:

En la página Index del proyecto de una aplicación Razor Pages, agrega el espacio de nombres del componente EmbeddedCounter e inserta el componente en la página. Cuando se carga la página Index, el componente EmbeddedCounter se representa previamente en ella. En el ejemplo siguiente, reemplaza el marcador de posición {APP NAMESPACE} por el espacio de nombres del proyecto.

Pages/Index.cshtml:

@page
@using {APP NAMESPACE}.Components
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<component type="typeof(EmbeddedCounter)" render-mode="ServerPrerendered" />

MVC:

En la vista Index del proyecto de una aplicación MVC, agrega el espacio de nombres del componente EmbeddedCounter e inserta el componente en la vista. Cuando se carga la vista Index, el componente EmbeddedCounter se representa previamente en ella. En el ejemplo siguiente, reemplaza el marcador de posición {APP NAMESPACE} por el espacio de nombres del proyecto.

Views/Home/Index.cshtml:

@using {APP NAMESPACE}.Components
@{
    ViewData["Title"] = "Home Page";
}

<component type="typeof(EmbeddedCounter)" render-mode="ServerPrerendered" />

Incorporación de compatibilidad de Blazor a una aplicación de ASP.NET Core

En esta sección, se explica cómo agregar compatibilidad con Blazor a una aplicación ASP.NET Core:

Nota:

En los ejemplos de esta sección, el nombre y el espacio de nombres de la aplicación de ejemplo es BlazorSample.

Agregar la representación estática del lado servidor (SSR estática)

Agrega una carpeta Components a la aplicación.

Agrega el siguiente _Imports archivo para los espacios de nombres usados por Razor los componentes.

Components/_Imports.razor:

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using {APP NAMESPACE}
@using {APP NAMESPACE}.Components

Cambia el marcador de posición del espacio de nombres ({APP NAMESPACE}) al espacio de nombres de la aplicación. Por ejemplo:

@using BlazorSample
@using BlazorSample.Components

Agrega el enrutador Blazor (<Router>, Router) a la aplicación en un componente Routes, que se coloca en la carpeta Components de la aplicación.

Components/Routes.razor:

<Router AppAssembly="typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="routeData" />
        <FocusOnNavigate RouteData="routeData" Selector="h1" />
    </Found>
</Router>

Agrega un App componente a la aplicación, que actúa como componente raíz, que es el primer componente que carga la aplicación.

Components/App.razor:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="@Assets["{ASSEMBLY NAME}.styles.css"]" />
    <HeadOutlet />
</head>

<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="{ASSEMBLY NAME}.styles.css" />
    <HeadOutlet />
</head>

<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

El marcador de posición {ASSEMBLY NAME} es el nombre de ensamblado de la aplicación. Por ejemplo, un proyecto con un nombre de ensamblaje de ContosoApp utiliza el ContosoApp.styles.css nombre de archivo de la hoja de estilos.

Agrega una Pages carpeta a la Components carpeta para contener componentes enrutables Razor.

Agrega el siguiente componente Welcome para mostrar la SSR estática.

Components/Pages/Welcome.razor:

@page "/welcome"

<PageTitle>Welcome!</PageTitle>

<h1>Welcome to Blazor!</h1>

<p>@message</p>

@code {
    private string message = 
        "Hello from a Razor component and welcome to Blazor!";
}

En el archivo del Program proyecto ASP.NET Core:

  • Agrega una using instrucción a la parte superior del archivo para los componentes del proyecto:

    using {APP NAMESPACE}.Components;
    

    En la línea anterior, cambia el marcador de posición {APP NAMESPACE} al espacio de nombres de la aplicación. Por ejemplo:

    using BlazorSample.Components;
    
  • Agrega servicios de componente Razor (AddRazorComponents), que también agregan automáticamente servicios antifalsificación (AddAntiforgery). Agrega la línea siguiente antes de la línea que llama a builder.Build()):

    builder.Services.AddRazorComponents();
    
  • Agrega Middleware antifalsificación a la canalización de procesamiento de solicitudes con UseAntiforgery. UseAntiforgery se llama después de la llamada a UseRouting. Si hay llamadas a UseRouting y UseEndpoints, la llamada a UseAntiforgery debe ir entre ellas. Se debe realizar una llamada a UseAntiforgery después de las llamadas a UseAuthentication y UseAuthorization.

    app.UseAntiforgery();
    
  • Agrega MapRazorComponents a la canalización de procesamiento de solicitudes de la aplicación con el componente App (App.razor) especificado como componente raíz predeterminado (el primer componente cargado). Coloca el código siguiente antes de la línea que llama a app.Run:

    app.MapRazorComponents<App>();
    

Cuando se ejecuta la aplicación, se accede al componente Welcome en el punto de conexión /welcome.

Habilitar la representación interactiva del lado servidor (SSR interactiva)

Sigue las instrucciones de la sección Agregar representación estática del lado servidor (SSR estático).

En el archivo Program de la aplicación, agrega una llamada a AddInteractiveServerComponents donde se agreguen los servicios de componentes Razor con AddRazorComponents:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

Agrega una llamada a AddInteractiveServerRenderModedonde se asignen los componentes de Razor con MapRazorComponents:

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

Agrega el siguiente componente Counter a la aplicación que adopta la representación interactiva del lado servidor (SSR interactiva).

Components/Pages/Counter.razor:

@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Cuando se ejecuta la aplicación, se accede al Counter componente en /counter.

Habilitar la representación automática interactiva (Automática) o del lado cliente (CSR)

Sigue las instrucciones de la sección Agregar representación estática del lado servidor (SSR estático).

Los componentes que usan el modo de representación automática interactiva usan inicialmente SSR interactivo. El runtime de .NET y el lote de aplicaciones se descargan en el cliente en segundo plano y se almacenan en caché para que se puedan usar en futuras visitas. Los componentes que usan el modo de representación Interactivo de WebAssembly solo se representan de forma interactiva en el cliente después de descargar la agrupación Blazor y el runtime Blazor se activa. Ten en cuenta que cuando se usan los modos de representación automática interactiva o interactivo de WebAssembly, el código de componente descargado en el cliente no es privado. Para obtener más información, consulta Modos de representación de ASP.NET CoreBlazor.

Después de decidir qué modo de representación adoptar:

Agrega una referencia de paquete a la aplicación para el paquete de NuGet Microsoft.AspNetCore.Components.WebAssembly.Server.

Nota:

Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirma las versiones correctas del paquete en NuGet.org.

Crea una Blazor Web App de donante para proporcionar recursos a la aplicación. Sigue las orientaciones del artículo Herramientas para ASP.NET Core Blazor, seleccionando la compatibilidad con las siguientes funciones de plantilla al generar la Blazor Web App.

Para el nombre de la aplicación, usa el mismo nombre que la aplicación ASP.NET Core, lo que da como resultado la coincidencia de marcado de nombres de aplicación en componentes y espacios de nombres coincidentes en el código. El uso del mismo nombre o espacio de nombres no es estrictamente necesario, ya que los espacios de nombres se pueden ajustar después de que los recursos se muevan de la aplicación donante a la aplicación ASP.NET Core. Sin embargo, el tiempo se guarda haciendo coincidir los espacios de nombres en el principio.

Visual Studio:

  • Para modo de representación interactiva, selecciona Automático (servidor y WebAssembly).
  • Establece la ubicación de interactividad en Por página o componente.
  • Anula la selección de la casilla incluir páginas de ejemplo.

CLI DE .NET:

  • Usa la opción -int Auto.
  • No uses la opción -ai|--all-interactive.
  • Pasa la opción -e|--empty.

Desde la Blazor Web App de donante, copia todo el proyecto .Client en la carpeta de la solución de la aplicación ASP.NET Core.

Importante

No copies la carpeta .Client en la carpeta del proyecto de ASP.NET Core. El mejor enfoque para organizar soluciones de .NET es colocar cada proyecto de la solución en su propia carpeta dentro de una carpeta de solución de nivel superior. Si no existe una carpeta de solución situada encima de la carpeta del proyecto de ASP.NET Core, cree una. A continuación, copia la carpeta del proyecto .Client desde la Blazor Web App de donante en la carpeta de la solución. La estructura final de carpetas del proyecto debe tener el siguiente diseño:

  • BlazorSampleSolution (carpeta de solución de nivel superior)
    • BlazorSample (proyecto original ASP.NET Core)
    • BlazorSample.Client (carpeta del proyecto .Client de la Blazor Web App de donante)

Para el archivo de solución ASP.NET Core, puedes dejarlo en la carpeta del proyecto ASP.NET Core. Como alternativa, puedes mover el archivo de solución o crear uno nuevo en la carpeta de solución de nivel superior siempre que el proyecto haga referencia correctamente a los archivos de proyecto (.csproj) de los dos proyectos de la carpeta de la solución.

Si has llamado a la Blazor Web App de donante al crear el proyecto de donantes igual que la aplicación ASP.NET Core, los espacios de nombres usados por los recursos donados coinciden con los de la aplicación ASP.NET Core. No es necesario seguir los pasos necesarios para buscar coincidencias con los espacios de nombres. Si usaste un espacio de nombres diferente al crear el proyecto deBlazor Web App de donante, debes ajustar los espacios de nombres entre los recursos donados para que coincidan si piensas usar el rest de esta guía exactamente como se muestra. Si los espacios de nombres no coinciden, ajusta los espacios de nombres antes de continuar o ajusta los espacios de nombres a medida que sigues las instrucciones restantes de esta sección.

Elimina la Blazor Web App de donante, ya que no tiene más uso en este proceso.

Agrega el proyecto .Client a la solución:

  • Haz clic con el botón derecho en el Explorador de soluciones y, a continuación, selecciona Agregar>Proyecto existente. Ve a la .Client carpeta y selecciona el archivo del proyecto (.csproj).

  • CLI de .NET: usa el comando dotnet sln add para agregar el proyecto .Client a la solución.

Agrega una referencia de proyecto desde el proyecto de ASP.NET Core al proyecto de cliente:

  • En el Explorador de soluciones, haz clic con el botón derecho en el proyecto ASP.NET Core y elige Agregar>Referencia del proyecto. Selecciona el proyecto .Client y, después, selecciona Aceptar.

  • CLI de .NET: en la carpeta del proyecto de ASP.NET Core, usa el siguiente comando:

    dotnet add reference ../BlazorSample.Client/BlazorSample.Client.csproj
    

    El comando anterior supone lo siguiente:

    • El nombre del archivo del proyecto es BlazorSample.Client.csproj.
    • El proyecto .Client se encuentra en una carpeta BlazorSample.Client dentro de la carpeta de la solución. La carpeta .Client está en paralelo con la carpeta del proyecto ASP.NET Core.

    Para obtener más información sobre el comando dotnet add reference, consulta dotnet add reference (documentación de.NET).

Realiza los cambios siguientes en el archivo Program de la aplicación ASP.NET Core:

  • Agrega servicios de componentes de WebAssembly interactivos con AddInteractiveWebAssemblyComponents donde se agregan servicios de componentes Razor con AddRazorComponents.

    Para la representación automática interactiva:

    builder.Services.AddRazorComponents()
        .AddInteractiveServerComponents()
        .AddInteractiveWebAssemblyComponents();
    

    Solo para la representación interactiva de WebAssembly:

    builder.Services.AddRazorComponents()
        .AddInteractiveWebAssemblyComponents();
    
  • Agrega el modo de representación interactiva de WebAssembly (AddInteractiveWebAssemblyRenderMode) y ensamblados adicionales para el proyecto .Client donde los componentes Razor se asignan con MapRazorComponents.

    Para la representación automática interactiva (Automática):

    app.MapRazorComponents<App>()
        .AddInteractiveServerRenderMode()
        .AddInteractiveWebAssemblyRenderMode()
        .AddAdditionalAssemblies(typeof(BlazorSample.Client._Imports).Assembly);
    

    Solo para la representación interactiva de WebAssembly:

    app.MapRazorComponents<App>()
        .AddInteractiveWebAssemblyRenderMode()
        .AddAdditionalAssemblies(typeof(BlazorSample.Client._Imports).Assembly);
    

    En los ejemplos anteriores, cambia BlazorSample.Client para que coincida con el .Client espacio de nombres del proyecto.

Agrega una carpeta Pages al proyecto .Client.

Si el proyecto ASP.NET Core tiene un componente existente Counter :

  • Mueve el componente a la carpeta Pages del proyecto .Client.
  • Quita la directiva @rendermode en la parte superior del archivo de componente.

Si la aplicación ASP.NET Core no tiene un Counter componente, agregue el siguiente Counter componente (Pages/Counter.razor) al .Client proyecto:

@page "/counter"
@rendermode InteractiveAuto

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Si la aplicación solo adopta la representación interactiva de WebAssembly, quita la directiva y el valor @rendermode:

- @rendermode InteractiveAuto

Ejecuta la solución desde el proyecto de aplicación ASP.NET Core:

  • Visual Studio: confirma que el proyecto ASP.NET Core está seleccionado en el Explorador de soluciones al ejecutar la aplicación.

  • CLI de .NET: ejecuta el proyecto desde la carpeta del proyecto de ASP.NET Core.

Para cargar el Counter componente, ve a /counter.

Implementación del diseño y los estilos de Blazor

Opcionalmente, asigna un componente de diseño predeterminado mediante el parámetro RouteView.DefaultLayout del componente RouteView.

En Routes.razor, el siguiente ejemplo usa un componente MainLayout como diseño predeterminado:

<RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />

Para obtener más información, consulta Diseños de ASP.NET Core Blazor.

El diseño de plantillas del proyecto Blazor y las hojas de estilo están disponibles en el repositorio dotnet/aspnetcore de GitHub:

  • MainLayout.razor
  • MainLayout.razor.css
  • NavMenu.razor
  • NavMenu.razor.css

Nota:

Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, usa la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, consulta Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).

En función de cómo organices los archivos de diseño en la aplicación, es posible que tengas que agregar una instrucción @using para la carpeta de los archivos de diseño en el archivo _Imports.razor de la aplicación para exponerlos para su uso en los componentes de la aplicación.

No es necesario hacer referencia explícitamente a las hojas de estilo cuando se usa el aislamiento CSS. El marco Blazor agrupa automáticamente hojas de estilo de componentes individuales. Ya se hace referencia a la hoja de estilos agrupada de la aplicación en el componente App de la aplicación ({ASSEMBLY NAME}.styles.css, donde el marcador de posición {ASSEMBLY NAME} es el nombre de ensamblado de la aplicación).

Devolver un RazorComponentResult desde una acción del controlador MVC

Una acción del controlador MVC puede devolver un componente con RazorComponentResult<TComponent>.

Components/Welcome.razor:

<PageTitle>Welcome!</PageTitle>

<h1>Welcome!</h1>

<p>@Message</p>

@code {
    [Parameter]
    public string? Message { get; set; }
}

En un controlador:

public IResult GetWelcomeComponent()
{
    return new RazorComponentResult<Welcome>(new { Message = "Hello, world!" });
}

Solo se devuelve el marcado HTML para el componente representado. Los diseños y el marcado de página HTML no se representan automáticamente con el componente. Para generar una página HTML completa, la aplicación puede mantener un diseño Blazor que proporcione marcado HTML para <html>, <head>, <body> y otras etiquetas. El componente incluye el diseño con la directiva @layoutRazor en la parte superior del archivo de definición de componentes, Welcome.razor para el ejemplo de esta sección. En el ejemplo siguiente se supone que la aplicación tiene un diseño denominado RazorComponentResultLayout (Components/Layout/RazorComponentResultLayout.razor):

@using BlazorSample.Components.Layout
@layout RazorComponentResultLayout

Puede evitar colocar la instrucción @using para la carpeta Layout en componentes individuales si la mueve al archivo _Imports.razor de la aplicación.

Para obtener más información, consulte Diseños de ASP.NET Core Blazor.

Espacios de nombres de componentes

Si usas una carpeta personalizada para contener los componentes Razor del proyecto, agrega el espacio de nombres que representa la carpeta a la página o vista, o bien al archivo _ViewImports.cshtml. En el ejemplo siguiente:

  • Los componentes se almacenan en la carpeta Components del proyecto.
  • El marcador de posición {APP NAMESPACE} es el espacio de nombres del proyecto. Components representa el nombre de la carpeta.
@using {APP NAMESPACE}.Components

Por ejemplo:

@using BlazorSample.Components

El archivo _ViewImports.cshtml se encuentra en la carpeta Pages de una aplicación Razor Pages o en la carpeta Views de una aplicación de MVC.

Para más información, vea Componentes Razor de ASP.NET Core.

Recursos adicionales

Representación previa de componentes de Razor de ASP.NET Core