Creación de una interfaz de usuario reutilizable con el proyecto de biblioteca de clases de Razor en ASP.NET Core

Por Rick Anderson

Las vistas, páginas, controladores y modelos de página de Razor, los componentes de Razor, los componentes de vista y los modelos de datos se pueden integrar en una biblioteca de clases de Razor (RCL). Las RCL se pueden empaquetar y reutilizar. Las aplicaciones pueden incluir la RCL y reemplazar las vistas y páginas que contienen. Si existe una vista,una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web.

Para obtener información sobre cómo integrar npm y webpack en el proceso de compilación de una biblioteca de clases Razor (RCL), consulta Compilación de recursos web cliente para la Biblioteca de clases Razor.

Creación de una biblioteca de clases que contenga interfaz de usuario de Razor

  • En Visual Studio, selecciona Crear un proyecto nuevo.
  • Selecciona Biblioteca de clases de Razor>Siguiente.
  • Asigna un nombre a la biblioteca (por ejemplo, "RazorClassLib"), >Crear. Para evitar un conflicto de nombres de archivo con la biblioteca de vistas generada, asegúrate de que el nombre de la biblioteca no acaba en .Views.
  • Selecciona Páginas y vistas de soporte técnico si necesitas que la biblioteca contenga páginas o vistas. Solo se admiten componentes de Razor de forma predeterminada. Selecciona Crear.

De forma predeterminada, la plantilla de la biblioteca de clases Razor usa el desarrollo de componentes de Razor. La opción Admitir páginas y vistas proporciona compatibilidad con páginas y vistas. Para obtener más información sobre la compatibilidad con RCL en Blazor, consulta Consumo de componentes Razor de ASP.NET Core a partir de una biblioteca de clases de Razor (RCL).

Agrega archivos de Razor a la RCL.

Las plantillas de ASP.NET Core dan por sentado que el contenido de la RCL se encuentra en la carpeta Areas. Consulta la sección Diseño de páginas de RCL a continuación para crear una RCL que exponga el contenido en ~/Pages en lugar de ~/Areas/Pages.

Referencias al contenido de la RCL

Los siguientes elementos pueden hacer referencia a la RCL:

Reemplazar vistas, vistas parciales y páginas

Si existe una vista, una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web. Por ejemplo, si agregas WebApp1/Areas/MyFeature/Pages/Page1.cshtml a WebApp1, Page1 en WebApp1 prevalecerá sobre Page1 en la RCL.

En la descarga de ejemplo, cambia el nombre WebApp1/Areas/MyFeature2 por WebApp1/Areas/MyFeature para comprobar la prioridad.

Copia la vista parcial RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml en WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Actualiza el marcado para señalar la nueva ubicación. Compila y ejecuta la aplicación para comprobar si se está usando la versión de la vista parcial de la aplicación.

Si la RCL usa Razor Pages, habilita los servicios y puntos de conexión de Razor Pages en la aplicación de hospedaje:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();
app.Run();

Diseño de páginas de RCL

Para hacer referencia al contenido de la RCL como si formara parte de la carpeta Pages de la aplicación web, crea el proyecto RCL con la siguiente estructura de archivos:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Imagina que RazorUIClassLib/Pages/Shared contiene dos archivos parciales: _Header.cshtml y _Footer.cshtml. En ese caso, se podrían agregar etiquetas <partial> al archivo _Layout.cshtml:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

Agrega el archivo _ViewStart.cshtml a la carpeta Pages del proyecto RCL para usar el archivo _Layout.cshtml de la aplicación web host:

@{
    Layout = "_Layout";
}

Creación de una RCL con recursos estáticos

Una RCL puede requerir recursos estáticos complementarios a los que puede hacer referencia la RCL o la aplicación de consumo de la RCL. ASP.NET Core permite crear bibliotecas de clases de Razor que incluyan recursos estáticos que estén disponibles para una aplicación de consumo.

Para incluir los recursos complementarios como parte de una RCL, crea una carpeta wwwroot en la biblioteca de clases e incluya en ella los archivos necesarios.

Al empaquetar una RCL, todos los recursos complementarios de la carpeta wwwroot se incluyen automáticamente en el paquete.

Use el comando dotnet pack en vez de la versión de NuGet.exe nuget pack.

Adición de recursos web de cliente al proceso de compilación

La integración de recursos web de cliente en la canalización de compilación no es trivial. Consulte Compilación de recursos web de cliente para la biblioteca de clases Razor para obtener más información.

Exclusión de recursos estáticos

Para excluir recursos estáticos, agregue la ruta de exclusión deseada al grupo de propiedades $(DefaultItemExcludes) en el archivo del proyecto. Separe las entradas con un punto y coma (;).

En el ejemplo siguiente, la hoja de estilos lib.css de la carpeta wwwroot no se considera un recurso estático y no se incluye en la RCL publicada:

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Integración de TypeScript

Para incluir archivos TypeScript en una RCL:

  1. Haga referencia al paquete NuGet Microsoft.TypeScript.MSBuild en el proyecto.

    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). Confirme las versiones correctas del paquete en NuGet.org.

  2. Coloque los archivos TypeScript ( .ts) fuera de la carpeta wwwroot. Por ejemplo, coloque los archivos en una carpeta de Client.

  3. Configure la salida de la compilación de TypeScript para la carpeta wwwroot. Establezca la propiedad TypescriptOutDir dentro de un PropertyGroup en el archivo del proyecto:

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  4. Incluya el destino de TypeScript como una dependencia del destino PrepareForBuildDependsOn; para ello, agregue el siguiente destino dentro de un objeto PropertyGroup en el archivo del proyecto:

    <PrepareForBuildDependsOn>
      CompileTypeScript;
      GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn)
    </PrepareForBuildDependsOn>
    

Consumo de contenido de una RCL a la que se hace referencia

Los archivos incluidos en la carpeta wwwroot de la RCL se exponen a la RCL o a la aplicación de consumo en el prefijo _content/{PACKAGE ID}/. Por ejemplo, una biblioteca con un nombre de ensamblado de Razor.Class.Lib y sin un objeto <PackageId> especificado en su archivo de proyecto da como resultado una ruta al contenido estático en _content/Razor.Class.Lib/. Al generar un paquete NuGet, si el nombre del ensamblado no es igual que el del identificador del paquete (<PackageId> en el archivo de proyecto de la biblioteca), use el identificador de paquete tal como se especifica en el archivo del proyecto para {PACKAGE ID}.

La aplicación de consumo hace referencia a los recursos estáticos proporcionados por la biblioteca con <script>, <style>, <img> y otras etiquetas HTML. La aplicación de consumo debe tener habilitada la compatibilidad con archivos estáticos en:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();
app.Run();

Al ejecutar la aplicación de consumo desde la salida de la compilación (dotnet run), los activos web estáticos están habilitados de forma predeterminada en el entorno de desarrollo. Para admitir recursos en otros entornos al ejecutar la aplicación desde la salida de la compilación, llame a UseStaticWebAssets en el generador de hosts en Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseWebRoot("wwwroot");
builder.WebHost.UseStaticWebAssets();

builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

No es necesario llamar a UseStaticWebAssets si se ejecuta una aplicación desde la salida publicada (dotnet publish).

Flujo de desarrollo de varios proyectos

Al ejecutar la aplicación de consumo:

  • Los recursos de la biblioteca de clases de Razor permanecen en sus carpetas originales. Los recursos no se mueven a la aplicación de consumo.
  • Cualquier cambio dentro de la carpeta wwwroot de la RCL se refleja en la aplicación de consumo después de que se vuelva a compilar la RCL y sin tener que recompilar la aplicación de consumo.

Cuando se compila la biblioteca de clases de Razor, se genera un manifiesto que describe las ubicaciones de los recursos web estáticos. La aplicación de consumo lee el manifiesto en tiempo de ejecución para consumir los recursos de los proyectos y paquetes a los que se hace referencia. Cuando se agrega un nuevo recurso a una RCL, esta se debe recompilar para actualizar el manifiesto antes de que una aplicación de consumo pueda acceder al nuevo recurso.

Publicar

Cuando se publica la aplicación, los recursos complementarios de todos los proyectos y paquetes a los que se hace referencia se copian en la carpeta wwwroot de la aplicación publicada en _content/{PACKAGE ID}/. Al generar un paquete NuGet, si el nombre del ensamblado no igual que el del identificador del paquete (<PackageId> en el archivo de proyecto de la biblioteca), use el identificador de paquete tal como se especifica en el archivo del proyecto para {PACKAGE ID} al examinar la carpeta wwwroot de los recursos publicados.

Recursos adicionales

Las vistas, páginas, controladores y modelos de página de Razor, los componentes de Razor, los componentes de vista y los modelos de datos se pueden integrar en una biblioteca de clases de Razor (RCL). Las RCL se pueden empaquetar y reutilizar. Las aplicaciones pueden incluir la RCL y reemplazar las vistas y páginas que contienen. Si existe una vista,una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web.

Para obtener información sobre cómo integrar npm y webpack en el proceso de compilación de una biblioteca de clases Razor, consulta Compilación de recursos web cliente para la biblioteca de clases Razor.

Creación de una biblioteca de clases que contenga interfaz de usuario de Razor

  • En Visual Studio, selecciona Crear un proyecto nuevo.
  • Selecciona Biblioteca de clases de Razor>Siguiente.
  • Asigna un nombre a la biblioteca (por ejemplo, "RazorClassLib"), >Crear. Para evitar un conflicto de nombres de archivo con la biblioteca de vistas generada, asegúrate de que el nombre de la biblioteca no acaba en .Views.
  • Selecciona Admitir páginas y vistas si necesitas admitir vistas. Solo se admite Razor Pages de forma predeterminada. Selecciona Crear.

De forma predeterminada, la plantilla de la biblioteca de clases de Razor (RCL) usa el desarrollo de componentes de Razor. La opción Admitir páginas y vistas proporciona compatibilidad con páginas y vistas.

Agrega archivos de Razor a la RCL.

Las plantillas de ASP.NET Core dan por sentado que el contenido de la RCL se encuentra en la carpeta Areas. Consulta la sección Diseño de páginas de RCL a continuación para crear una RCL que exponga el contenido en ~/Pages en lugar de ~/Areas/Pages.

Referencias al contenido de la RCL

Los siguientes elementos pueden hacer referencia a la RCL:

Reemplazar vistas, vistas parciales y páginas

Si existe una vista, una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web. Por ejemplo, si agregas WebApp1/Areas/MyFeature/Pages/Page1.cshtml a WebApp1, Page1 en WebApp1 prevalecerá sobre Page1 en la RCL.

En la descarga de ejemplo, cambia el nombre WebApp1/Areas/MyFeature2 por WebApp1/Areas/MyFeature para comprobar la prioridad.

Copia la vista parcial RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml en WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Actualiza el marcado para señalar la nueva ubicación. Compila y ejecuta la aplicación para comprobar si se está usando la versión de la vista parcial de la aplicación.

Si la RCL usa Razor Pages, habilita los servicios y puntos de conexión de Razor Pages en la aplicación de hospedaje:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();
app.Run();

Diseño de páginas de RCL

Para hacer referencia al contenido de la RCL como si formara parte de la carpeta Pages de la aplicación web, crea el proyecto RCL con la siguiente estructura de archivos:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Imagina que RazorUIClassLib/Pages/Shared contiene dos archivos parciales: _Header.cshtml y _Footer.cshtml. En ese caso, se podrían agregar etiquetas <partial> al archivo _Layout.cshtml:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

Agrega el archivo _ViewStart.cshtml a la carpeta Pages del proyecto RCL para usar el archivo _Layout.cshtml de la aplicación web host:

@{
    Layout = "_Layout";
}

Creación de una RCL con recursos estáticos

Una RCL puede requerir recursos estáticos complementarios a los que puede hacer referencia la RCL o la aplicación de consumo de la RCL. ASP.NET Core permite crear bibliotecas de clases de Razor que incluyan recursos estáticos que estén disponibles para una aplicación de consumo.

Para incluir los recursos complementarios como parte de una RCL, crea una carpeta wwwroot en la biblioteca de clases e incluya en ella los archivos necesarios.

Al empaquetar una RCL, todos los recursos complementarios de la carpeta wwwroot se incluyen automáticamente en el paquete.

Usa el comando dotnet pack en vez de la versión de NuGet.exe nuget pack.

Exclusión de recursos estáticos

Para excluir recursos estáticos, agregue la ruta de exclusión deseada al grupo de propiedades $(DefaultItemExcludes) en el archivo del proyecto. Separe las entradas con un punto y coma (;).

En el ejemplo siguiente, la hoja de estilos lib.css de la carpeta wwwroot no se considera un recurso estático y no se incluye en la RCL publicada:

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Integración de TypeScript

Para incluir archivos TypeScript en una RCL:

  1. Haga referencia al paquete NuGet Microsoft.TypeScript.MSBuild en el proyecto.

    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). Confirme las versiones correctas del paquete en NuGet.org.

  2. Coloque los archivos TypeScript ( .ts) fuera de la carpeta wwwroot. Por ejemplo, coloque los archivos en una carpeta de Client.

  3. Configure la salida de la compilación de TypeScript para la carpeta wwwroot. Establezca la propiedad TypescriptOutDir dentro de un PropertyGroup en el archivo del proyecto:

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  4. Incluya el destino de TypeScript como una dependencia del destino PrepareForBuildDependsOn; para ello, agregue el siguiente destino dentro de un objeto PropertyGroup en el archivo del proyecto:

    <PrepareForBuildDependsOn>
      CompileTypeScript;
      GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn)
    </PrepareForBuildDependsOn>
    

Consumo de contenido de una RCL a la que se hace referencia

Los archivos incluidos en la carpeta wwwroot de la RCL se exponen a la RCL o a la aplicación de consumo en el prefijo _content/{PACKAGE ID}/. Por ejemplo, una biblioteca con un nombre de ensamblado de Razor.Class.Lib y sin un objeto <PackageId> especificado en su archivo de proyecto da como resultado una ruta al contenido estático en _content/Razor.Class.Lib/. Al generar un paquete NuGet, si el nombre del ensamblado no es igual que el del identificador del paquete (<PackageId> en el archivo de proyecto de la biblioteca), use el identificador de paquete tal como se especifica en el archivo del proyecto para {PACKAGE ID}.

La aplicación de consumo hace referencia a los recursos estáticos proporcionados por la biblioteca con <script>, <style>, <img> y otras etiquetas HTML. La aplicación de consumo debe tener habilitada la compatibilidad con archivos estáticos en:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.MapRazorPages();
app.Run();

Al ejecutar la aplicación de consumo desde la salida de la compilación (dotnet run), los activos web estáticos están habilitados de forma predeterminada en el entorno de desarrollo. Para admitir recursos en otros entornos al ejecutar la aplicación desde la salida de la compilación, llame a UseStaticWebAssets en el generador de hosts en Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseWebRoot("wwwroot").UseStaticWebAssets();

builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Nota: .NET 6 solo requiere llamar a builder.WebHost.UseWebRoot("wwwroot").UseStaticWebAssets. Para más información, consulte este problema de GitHub.

No es necesario llamar a UseStaticWebAssets si se ejecuta una aplicación desde la salida publicada (dotnet publish).

Flujo de desarrollo de varios proyectos

Al ejecutar la aplicación de consumo:

  • Los recursos de la biblioteca de clases de Razor permanecen en sus carpetas originales. Los recursos no se mueven a la aplicación de consumo.
  • Cualquier cambio dentro de la carpeta wwwroot de la RCL se refleja en la aplicación de consumo después de que se vuelva a compilar la RCL y sin tener que recompilar la aplicación de consumo.

Cuando se compila la biblioteca de clases de Razor, se genera un manifiesto que describe las ubicaciones de los recursos web estáticos. La aplicación de consumo lee el manifiesto en tiempo de ejecución para consumir los recursos de los proyectos y paquetes a los que se hace referencia. Cuando se agrega un nuevo recurso a una RCL, esta se debe recompilar para actualizar el manifiesto antes de que una aplicación de consumo pueda acceder al nuevo recurso.

Publicar

Cuando se publica la aplicación, los recursos complementarios de todos los proyectos y paquetes a los que se hace referencia se copian en la carpeta wwwroot de la aplicación publicada en _content/{PACKAGE ID}/. Al generar un paquete NuGet, si el nombre del ensamblado no igual que el del identificador del paquete (<PackageId> en el archivo de proyecto de la biblioteca), use el identificador de paquete tal como se especifica en el archivo del proyecto para {PACKAGE ID} al examinar la carpeta wwwroot de los recursos publicados.

Recursos adicionales

Las vistas, páginas, controladores y modelos de página de Razor, los componentes de Razor, los componentes de vista y los modelos de datos se pueden integrar en una biblioteca de clases de Razor (RCL). Las RCL se pueden empaquetar y reutilizar. Las aplicaciones pueden incluir la RCL y reemplazar las vistas y páginas que contienen. Si existe una vista,una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web.

Vea o descargue el código de ejemplo (cómo descargarlo)

Creación de una biblioteca de clases que contenga interfaz de usuario de Razor

  • En Visual Studio, seleccione Crear un proyecto nuevo.
  • Seleccione Biblioteca de clases de Razor>Siguiente.
  • Asigna un nombre a la biblioteca (por ejemplo, "RazorClassLib"), >Crear>Siguiente. Para evitar un conflicto de nombres de archivo con la biblioteca de vistas generada, asegúrese de que el nombre de la biblioteca no acaba en .Views.
  • Seleccione la plataforma de destino. Marque ☑ páginas y vistas de soporte técnico para admitir vistas. Solo se admiten componentes de Razor de forma predeterminada. Seleccione Crear.

De forma predeterminada, la plantilla de la biblioteca de clases de Razor (RCL) usa el desarrollo de componentes de Razor. La opción Admitir páginas y vistas proporciona compatibilidad con páginas y vistas.

Agrega archivos de Razor a la RCL.

Las plantillas de ASP.NET Core dan por sentado que el contenido de la RCL se encuentra en la carpeta Areas. Consulte la sección Diseño de páginas de RCL para crear una RCL que exponga contenido en ~/Pages y no en ~/Areas/Pages.

Referencias al contenido de la RCL

Los siguientes elementos pueden hacer referencia a la RCL:

Reemplazar vistas, vistas parciales y páginas

Si existe una vista, una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web. Por ejemplo, si agregas WebApp1/Areas/MyFeature/Pages/Page1.cshtml a WebApp1, Page1 en WebApp1 prevalecerá sobre Page1 en la RCL.

En la descarga de ejemplo, cambia el nombre WebApp1/Areas/MyFeature2 por WebApp1/Areas/MyFeature para comprobar la prioridad.

Copia la vista parcial RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml en WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Actualiza el marcado para señalar la nueva ubicación. Compile y ejecute la aplicación para comprobar si se está usando la versión de la vista parcial de la aplicación.

Diseño de páginas de RCL

Para hacer referencia al contenido de la RCL como si formara parte de la carpeta Pages de la aplicación web, crea el proyecto RCL con la siguiente estructura de archivos:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Imagina que RazorUIClassLib/Pages/Shared contiene dos archivos parciales: _Header.cshtml y _Footer.cshtml. En ese caso, se podrían agregar etiquetas <partial> al archivo _Layout.cshtml:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

Agrega el archivo _ViewStart.cshtml a la carpeta Pages del proyecto RCL para usar el archivo _Layout.cshtml de la aplicación web host:

@{
    Layout = "_Layout";
}

Creación de una RCL con recursos estáticos

Una RCL puede requerir recursos estáticos complementarios a los que puede hacer referencia la RCL o la aplicación de consumo de la RCL. ASP.NET Core permite crear bibliotecas de clases de Razor que incluyan recursos estáticos que estén disponibles para una aplicación de consumo.

Para incluir los recursos complementarios como parte de una RCL, crea una carpeta wwwroot en la biblioteca de clases e incluya en ella los archivos necesarios.

Al empaquetar una RCL, todos los recursos complementarios de la carpeta wwwroot se incluyen automáticamente en el paquete.

Usa el comando dotnet pack en vez de la versión de NuGet.exe nuget pack.

Exclusión de recursos estáticos

Para excluir recursos estáticos, agregue la ruta de exclusión deseada al grupo de propiedades $(DefaultItemExcludes) en el archivo del proyecto. Separe las entradas con un punto y coma (;).

En el ejemplo siguiente, la hoja de estilos lib.css de la carpeta wwwroot no se considera un recurso estático y no se incluye en la RCL publicada:

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Integración de TypeScript

Para incluir archivos TypeScript en una RCL:

  1. Haga referencia al paquete NuGet Microsoft.TypeScript.MSBuild en el proyecto.

    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). Confirme las versiones correctas del paquete en NuGet.org.

  2. Coloque los archivos TypeScript ( .ts) fuera de la carpeta wwwroot. Por ejemplo, coloque los archivos en una carpeta de Client.

  3. Configure la salida de la compilación de TypeScript para la carpeta wwwroot. Establezca la propiedad TypescriptOutDir dentro de un PropertyGroup en el archivo del proyecto:

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  4. Incluya el destino de TypeScript como una dependencia del destino ResolveCurrentProjectStaticWebAssets; para ello, agregue el siguiente destino dentro de un objeto PropertyGroup en el archivo del proyecto:

    <ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
      CompileTypeScript;
      $(ResolveCurrentProjectStaticWebAssetsInputs)
    </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
    

Consumo de contenido de una RCL a la que se hace referencia

Los archivos incluidos en la carpeta wwwroot de la RCL se exponen a la RCL o a la aplicación de consumo en el prefijo _content/{PACKAGE ID}/. Por ejemplo, una biblioteca con un nombre de ensamblado de Razor.Class.Lib y sin un objeto <PackageId> especificado en su archivo de proyecto da como resultado una ruta al contenido estático en _content/Razor.Class.Lib/. Al generar un paquete NuGet, si el nombre del ensamblado no es igual que el del identificador del paquete (<PackageId> en el archivo de proyecto de la biblioteca), use el identificador de paquete tal como se especifica en el archivo del proyecto para {PACKAGE ID}.

La aplicación de consumo hace referencia a los recursos estáticos proporcionados por la biblioteca con <script>, <style>, <img> y otras etiquetas HTML. La aplicación de consumo debe tener habilitada la compatibilidad con archivos estáticos en Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseStaticFiles();

    ...
}

Al ejecutar la aplicación de consumo desde la salida de la compilación (dotnet run), los activos web estáticos están habilitados de forma predeterminada en el entorno de desarrollo. Para admitir recursos en otros entornos al ejecutar la aplicación desde la salida de la compilación, llame a UseStaticWebAssets en el generador de hosts en Program.cs:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStaticWebAssets();
                webBuilder.UseStartup<Startup>();
            });
}

No es necesario llamar a UseStaticWebAssets si se ejecuta una aplicación desde la salida publicada (dotnet publish).

Flujo de desarrollo de varios proyectos

Al ejecutar la aplicación de consumo:

  • Los recursos de la biblioteca de clases de Razor permanecen en sus carpetas originales. Los recursos no se mueven a la aplicación de consumo.
  • Cualquier cambio dentro de la carpeta wwwroot de la RCL se refleja en la aplicación de consumo después de que se vuelva a compilar la RCL y sin tener que recompilar la aplicación de consumo.

Cuando se compila la biblioteca de clases de Razor, se genera un manifiesto que describe las ubicaciones de los recursos web estáticos. La aplicación de consumo lee el manifiesto en tiempo de ejecución para consumir los recursos de los proyectos y paquetes a los que se hace referencia. Cuando se agrega un nuevo recurso a una RCL, esta se debe recompilar para actualizar el manifiesto antes de que una aplicación de consumo pueda acceder al nuevo recurso.

Publicar

Cuando se publica la aplicación, los recursos complementarios de todos los proyectos y paquetes a los que se hace referencia se copian en la carpeta wwwroot de la aplicación publicada en _content/{PACKAGE ID}/. Al generar un paquete NuGet, si el nombre del ensamblado no igual que el del identificador del paquete (<PackageId> en el archivo de proyecto de la biblioteca), use el identificador de paquete tal como se especifica en el archivo del proyecto para {PACKAGE ID} al examinar la carpeta wwwroot de los recursos publicados.

Recursos adicionales

Las vistas, páginas, controladores y modelos de página de Razor, los componentes de Razor, los componentes de vista y los modelos de datos se pueden integrar en una biblioteca de clases de Razor (RCL). Las RCL se pueden empaquetar y reutilizar. Las aplicaciones pueden incluir la RCL y reemplazar las vistas y páginas que contienen. Si existe una vista,una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web.

Vea o descargue el código de ejemplo (cómo descargarlo)

Creación de una biblioteca de clases que contenga interfaz de usuario de Razor

  • En el menú Archivo de Visual Studio, seleccione Nuevo>Proyecto.
  • Seleccione Aplicación web de ASP.NET Core.
  • Asigna un nombre a la biblioteca (por ejemplo, "RazorClassLib") >Aceptar. Para evitar un conflicto de nombres de archivo con la biblioteca de vistas generada, asegúrese de que el nombre de la biblioteca no acaba en .Views.
  • Confirme que ASP.NET Core 2.1 o una versión posterior está seleccionado.
  • Seleccione Biblioteca de clases de Razor>Aceptar.

Una RCL tiene el siguiente archivo de proyecto:

<Project Sdk="Microsoft.NET.Sdk.Razor">

    <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
    </PropertyGroup>

    <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
    </ItemGroup>


</Project>

Agrega archivos de Razor a la RCL.

Las plantillas de ASP.NET Core dan por sentado que el contenido de la RCL se encuentra en la carpeta Areas. Consulte la sección Diseño de páginas de RCL para crear una RCL que exponga contenido en ~/Pages y no en ~/Areas/Pages.

Referencias al contenido de la RCL

Los siguientes elementos pueden hacer referencia a la RCL:

Tutorial: Creación y uso de un proyecto de RCL desde un proyecto de Razor Pages

En lugar de crearlo, puede descargar el proyecto completo y comprobarlo. La descarga de ejemplo contiene más código y vínculos que hacen que el proyecto sea fácil de comprobar. Puede dejar sus comentarios en este problema de GitHub sobre las descargas de ejemplo en comparación con las instrucciones paso a paso.

Comprobar la aplicación de descarga

Si no ha descargado la aplicación final y prefiere crear el proyecto de tutorial, omita este paso y vaya a la siguiente sección.

Abra el archivo .sln en Visual Studio. Ejecutar la aplicación.

Siga las instrucciones de Probar WebApp1.

Creación de una RCL

En esta sección, se creará una RCL y se agregarán a ella archivos de Razor.

Cree el proyecto de RCL:

  • En el menú Archivo de Visual Studio, seleccione Nuevo>Proyecto.
  • Seleccione Aplicación web de ASP.NET Core.
  • Asigna a la aplicación el nombre RazorUIClassLib>Aceptar.
  • Confirme que ASP.NET Core 2.1 o una versión posterior está seleccionado.
  • Seleccione Biblioteca de clases de Razor>Aceptar.
  • Agregue un archivo de vista parcial de Razor denominado RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml.

Adición de archivos y carpetas de Razor al proyecto

  • Reemplace el marcado de RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml por el siguiente código:

    <h3>_Message.cshtml partial view.</h3>
    
    <p>RazorUIClassLib\Areas\MyFeature\Pages\Shared\_Message.cshtml</p>
    
  • Reemplace el marcado de RazorUIClassLib/Areas/MyFeature/Pages/Page1.cshtml por el siguiente código:

    @page
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <h2>Hello from a Razor UI class library!</h2>
    <p> From  RazorUIClassLib\Areas\MyFeature\Pages\Page1.cshtml</p>
    
    <partial name="_Message" />
    

    Se necesita @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers para usar la vista parcial (<partial name="_Message" />). En lugar de incluir la directiva @addTagHelper, puede agregar un archivo _ViewImports.cshtml. Por ejemplo:

    dotnet new viewimports -o RazorUIClassLib/Areas/MyFeature/Pages
    

    Para obtener más información sobre _ViewImports.cshtml, consulte Importar directivas compartidas.

  • Compile la biblioteca de clases para confirmar que no hay ningún error de compilador:

    dotnet build RazorUIClassLib
    

La salida de la compilación contiene RazorUIClassLib.dll y RazorUIClassLib.Views.dll. RazorUIClassLib.Views.dll incluye el contenido de Razor compilado.

Uso de la biblioteca de interfaz de usuario de Razor desde un proyecto de Razor Pages

Cree la aplicación web de páginas de Razor:

  • En el Explorador de soluciones, haga clic con el botón derecho en la solución >Agregar>Nuevo proyecto.

  • Seleccione Aplicación web de ASP.NET Core.

  • Denomine la aplicación WebApp1.

  • Confirme que ASP.NET Core 2.1 o una versión posterior está seleccionado.

  • Seleccione Aplicación web>Aceptar.

  • En el Explorador de soluciones, haga clic con el botón derecho en WebApp1 y seleccione Establecer como proyecto de inicio.

  • En el Explorador de soluciones, haga clic con el botón derecho en WebApp1 y seleccione Dependencias de compilación>Dependencias del proyecto.

  • Marque RazorUIClassLib como dependencia de WebApp1.

  • En el Explorador de soluciones, haga clic con el botón derecho en WebApp1 y seleccione Agregar>Referencia.

  • En el cuadro de diálogo Administrador de referencias, marque RazorUIClassLib>Aceptar.

Ejecute la aplicación.

Probar WebApp1

Vaya a /MyFeature/Page1 para comprobar que la biblioteca de clases de la interfaz de usuario de Razor está en uso.

Reemplazar vistas, vistas parciales y páginas

Si existe una vista, una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web. Por ejemplo, si agregas WebApp1/Areas/MyFeature/Pages/Page1.cshtml a WebApp1, Page1 en WebApp1 prevalecerá sobre Page1 en la RCL.

En la descarga de ejemplo, cambia el nombre WebApp1/Areas/MyFeature2 por WebApp1/Areas/MyFeature para comprobar la prioridad.

Copia la vista parcial RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml en WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Actualiza el marcado para señalar la nueva ubicación. Compile y ejecute la aplicación para comprobar si se está usando la versión de la vista parcial de la aplicación.

Diseño de páginas de RCL

Para hacer referencia al contenido de la RCL como si formara parte de la carpeta Pages de la aplicación web, crea el proyecto RCL con la siguiente estructura de archivos:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Imagina que RazorUIClassLib/Pages/Shared contiene dos archivos parciales: _Header.cshtml y _Footer.cshtml. En ese caso, se podrían agregar etiquetas <partial> al archivo _Layout.cshtml:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

Las vistas, páginas, controladores y modelos de página de Razor, los componentes de Razor, los componentes de vista y los modelos de datos se pueden integrar en una biblioteca de clases de Razor (RCL). Las RCL se pueden empaquetar y reutilizar. Las aplicaciones pueden incluir la RCL y reemplazar las vistas y páginas que contienen. Si existe una vista,una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web.

Vea o descargue el código de ejemplo (cómo descargarlo)

Creación de una biblioteca de clases que contenga interfaz de usuario de Razor

  • En Visual Studio, selecciona Crear un proyecto nuevo.
  • Selecciona Biblioteca de clases de Razor>Siguiente.
  • Asigna un nombre a la biblioteca (por ejemplo, "RazorClassLib"), >Crear. Para evitar un conflicto de nombres de archivo con la biblioteca de vistas generada, asegúrate de que el nombre de la biblioteca no acaba en .Views.
  • Selecciona Admitir páginas y vistas si necesitas admitir vistas. Solo se admite Razor Pages de forma predeterminada. Selecciona Crear.

De forma predeterminada, la plantilla de la biblioteca de clases de Razor (RCL) usa el desarrollo de componentes de Razor. La opción Admitir páginas y vistas proporciona compatibilidad con páginas y vistas.

Agrega archivos de Razor a la RCL.

Las plantillas de ASP.NET Core dan por sentado que el contenido de la RCL se encuentra en la carpeta Areas. Consulta la sección Diseño de páginas de RCL a continuación para crear una RCL que exponga el contenido en ~/Pages en lugar de ~/Areas/Pages.

Referencias al contenido de la RCL

Los siguientes elementos pueden hacer referencia a la RCL:

Reemplazar vistas, vistas parciales y páginas

Si existe una vista, una vista parcial o una página de Razor tanto en la aplicación web como en la RCL, tiene prioridad el marcado de Razor (archivo .cshtml) de la aplicación web. Por ejemplo, si agregas WebApp1/Areas/MyFeature/Pages/Page1.cshtml a WebApp1, Page1 en WebApp1 prevalecerá sobre Page1 en la RCL.

En la descarga de ejemplo, cambia el nombre WebApp1/Areas/MyFeature2 por WebApp1/Areas/MyFeature para comprobar la prioridad.

Copia la vista parcial RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml en WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Actualiza el marcado para señalar la nueva ubicación. Compila y ejecuta la aplicación para comprobar si se está usando la versión de la vista parcial de la aplicación.

Si la RCL usa Razor Pages, habilita los servicios y puntos de conexión de Razor Pages en la aplicación de hospedaje:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
}

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

        endpoints.MapRazorPages();
    });
}

Diseño de páginas de RCL

Para hacer referencia al contenido de la RCL como si formara parte de la carpeta Pages de la aplicación web, crea el proyecto RCL con la siguiente estructura de archivos:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Imagina que RazorUIClassLib/Pages/Shared contiene dos archivos parciales: _Header.cshtml y _Footer.cshtml. En ese caso, se podrían agregar etiquetas <partial> al archivo _Layout.cshtml:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

Agrega el archivo _ViewStart.cshtml a la carpeta Pages del proyecto RCL para usar el archivo _Layout.cshtml de la aplicación web host:

@{
    Layout = "_Layout";
}

Creación de una RCL con recursos estáticos

Una RCL puede requerir recursos estáticos complementarios a los que puede hacer referencia la RCL o la aplicación de consumo de la RCL. ASP.NET Core permite crear bibliotecas de clases de Razor que incluyan recursos estáticos que estén disponibles para una aplicación de consumo.

Para incluir los recursos complementarios como parte de una RCL, crea una carpeta wwwroot en la biblioteca de clases e incluya en ella los archivos necesarios.

Al empaquetar una RCL, todos los recursos complementarios de la carpeta wwwroot se incluyen automáticamente en el paquete.

Usa el comando dotnet pack en vez de la versión de NuGet.exe nuget pack.

Exclusión de recursos estáticos

Para excluir recursos estáticos, agregue la ruta de exclusión deseada al grupo de propiedades $(DefaultItemExcludes) en el archivo del proyecto. Separe las entradas con un punto y coma (;).

En el ejemplo siguiente, la hoja de estilos lib.css de la carpeta wwwroot no se considera un recurso estático y no se incluye en la RCL publicada:

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Integración de TypeScript

Para incluir archivos TypeScript en una RCL:

  1. Haga referencia al paquete NuGet Microsoft.TypeScript.MSBuild en el proyecto.

    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). Confirme las versiones correctas del paquete en NuGet.org.

  2. Coloque los archivos TypeScript ( .ts) fuera de la carpeta wwwroot. Por ejemplo, coloque los archivos en una carpeta de Client.

  3. Configure la salida de la compilación de TypeScript para la carpeta wwwroot. Establezca la propiedad TypescriptOutDir dentro de un PropertyGroup en el archivo del proyecto:

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  4. Incluya el destino de TypeScript como una dependencia del destino ResolveCurrentProjectStaticWebAssets; para ello, agregue el siguiente destino dentro de un objeto PropertyGroup en el archivo del proyecto:

    <ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
      CompileTypeScript;
      $(ResolveCurrentProjectStaticWebAssetsInputs)
    </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
    

Consumo de contenido de una RCL a la que se hace referencia

Los archivos incluidos en la carpeta wwwroot de la RCL se exponen a la RCL o a la aplicación de consumo en el prefijo _content/{PACKAGE ID}/. Por ejemplo, una biblioteca con un nombre de ensamblado de Razor.Class.Lib y sin un objeto <PackageId> especificado en su archivo de proyecto da como resultado una ruta al contenido estático en _content/Razor.Class.Lib/. Al generar un paquete NuGet, si el nombre del ensamblado no es igual que el del identificador del paquete (<PackageId> en el archivo de proyecto de la biblioteca), use el identificador de paquete tal como se especifica en el archivo del proyecto para {PACKAGE ID}.

La aplicación de consumo hace referencia a los recursos estáticos proporcionados por la biblioteca con <script>, <style>, <img> y otras etiquetas HTML. La aplicación de consumo debe tener habilitada la compatibilidad con archivos estáticos en Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseStaticFiles();

    ...
}

Al ejecutar la aplicación de consumo desde la salida de la compilación (dotnet run), los activos web estáticos están habilitados de forma predeterminada en el entorno de desarrollo. Para admitir recursos en otros entornos al ejecutar la aplicación desde la salida de la compilación, llame a UseStaticWebAssets en el generador de hosts en Program.cs:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStaticWebAssets();
                webBuilder.UseStartup<Startup>();
            });
}

No es necesario llamar a UseStaticWebAssets si se ejecuta una aplicación desde la salida publicada (dotnet publish).

Flujo de desarrollo de varios proyectos

Al ejecutar la aplicación de consumo:

  • Los recursos de la biblioteca de clases de Razor permanecen en sus carpetas originales. Los recursos no se mueven a la aplicación de consumo.
  • Cualquier cambio dentro de la carpeta wwwroot de la RCL se refleja en la aplicación de consumo después de que se vuelva a compilar la RCL y sin tener que recompilar la aplicación de consumo.

Cuando se compila la biblioteca de clases de Razor, se genera un manifiesto que describe las ubicaciones de los recursos web estáticos. La aplicación de consumo lee el manifiesto en tiempo de ejecución para consumir los recursos de los proyectos y paquetes a los que se hace referencia. Cuando se agrega un nuevo recurso a una RCL, esta se debe recompilar para actualizar el manifiesto antes de que una aplicación de consumo pueda acceder al nuevo recurso.

Publicar

Cuando se publica la aplicación, los recursos complementarios de todos los proyectos y paquetes a los que se hace referencia se copian en la carpeta wwwroot de la aplicación publicada en _content/{PACKAGE ID}/. Al generar un paquete NuGet, si el nombre del ensamblado no igual que el del identificador del paquete (<PackageId> en el archivo de proyecto de la biblioteca), use el identificador de paquete tal como se especifica en el archivo del proyecto para {PACKAGE ID} al examinar la carpeta wwwroot de los recursos publicados.

Recursos adicionales