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.

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.
  • Asigne un nombre a la biblioteca (por ejemplo, "RazorClassLib") > Crear. 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 Admitir páginas y vistas si necesita admitir vistas. Solo se admite Razor Pages 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.

Agregue 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 Áreas. 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 agrega WebApp1/Areas/MyFeature/Pages/Page1.cshtml a WebApp1, Page1 en WebApp1 prevalecerá sobre Page1 en la biblioteca de clases de Razor.

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

Copie la vista parcial RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml en WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Actualice 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, cree el proyecto RCL con la siguiente estructura de archivos:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Imagine 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>

Agregue 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, cree 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.

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. Coloque los archivos TypeScript ( .ts) fuera de la carpeta wwwroot. Por ejemplo, coloque los archivos en una carpeta de cliente.

  2. 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>
    
  3. 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/{LIBRARY NAME}/. Por ejemplo, una biblioteca denominada Razor.Class.Lib produce una ruta de acceso 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, use el identificador de paquete para {LIBRARY NAME}.

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/{LIBRARY NAME}/.

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.
  • Asigne 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>

Agregue 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 Áreas. 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.
  • Asigne 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 la sección 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 la casilla RazorUIClassLib > Aceptar.

Ejecutar 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 agrega WebApp1/Areas/MyFeature/Pages/Page1.cshtml a WebApp1, Page1 en WebApp1 prevalecerá sobre Page1 en la biblioteca de clases de Razor.

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

Copie la vista parcial RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml en WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Actualice 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, cree el proyecto RCL con la siguiente estructura de archivos:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Imagine 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, seleccione Crear un proyecto nuevo.
  • Seleccione Biblioteca de clases de Razor > Siguiente.
  • Asigne un nombre a la biblioteca (por ejemplo, "RazorClassLib") > Crear. 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 Admitir páginas y vistas si necesita admitir vistas. Solo se admite Razor Pages 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.

Agregue 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 Áreas. 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 agrega WebApp1/Areas/MyFeature/Pages/Page1.cshtml a WebApp1, Page1 en WebApp1 prevalecerá sobre Page1 en la biblioteca de clases de Razor.

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

Copie la vista parcial RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml en WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Actualice 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, cree el proyecto RCL con la siguiente estructura de archivos:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Imagine 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>

Agregue 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, cree 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.

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. Coloque los archivos TypeScript ( .ts) fuera de la carpeta wwwroot. Por ejemplo, coloque los archivos en una carpeta de cliente.

  2. 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>
    
  3. 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/{LIBRARY NAME}/. Por ejemplo, una biblioteca denominada Razor.Class.Lib produce una ruta de acceso 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, use el identificador de paquete para {LIBRARY NAME}.

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/{LIBRARY NAME}/.

Recursos adicionales