Compartir a través de


Archivos estáticos Blazor Hybrid en ASP.NET Core

Nota

Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión de .NET 9 de este artículo.

Advertencia

Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la directiva de compatibilidad de .NET y .NET Core. Para la versión actual, consulte la versión de .NET 9 de este artículo.

Importante

Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Para la versión actual, consulte la versión de .NET 9 de este artículo.

En este artículo se describe cómo consumir archivos de recursos estáticos en aplicaciones Blazor Hybrid.

En una aplicación Blazor Hybrid, los archivos estáticos son recursos de la aplicación, a los que acceden los componentes Razor mediante los métodos siguientes:

Cuando los recursos estáticos solo se usan en los componentes Razor, los recursos estáticos se pueden consumir desde la raíz web (carpeta wwwroot) de forma similar a las aplicaciones Blazor WebAssembly y Blazor Server. Para obtener más información, consulta la sección Recursos estáticos limitados a componentesRazor.

.NET MAUI

En las aplicaciones .NET MAUI, los recursos sin procesar que usan la acción de compilación MauiAsset y .NET MAUI file system helpers se usan para los recursos estáticos.

Nota

Las interfaces, las clases y los tipos auxiliares para trabajar con el almacenamiento en dispositivos en todas las plataformas admitidas para características como elegir un archivo, guardar preferencias y usar almacenamiento seguro se encuentran en el espacio de nombres Microsoft.Maui.Storage. El espacio de nombres está disponible en toda una aplicación Blazor Hybrid de MAUI, por lo que no es necesario especificar una instrucción using en un archivo de clase o una directiva @usingRazor en un componente Razor para el espacio de nombres.

Coloca los recursos sin procesar en la carpeta Resources/Raw de la aplicación. En el ejemplo de esta sección se usa un archivo de texto estático.

Resources/Raw/Data.txt:

This is text from a static text file resource.

El componente Razor siguiente:

Pages/StaticAssetExample.razor:

@page "/static-asset-example"
@using System.IO
@using Microsoft.Extensions.Logging
@inject ILogger<StaticAssetExample> Logger

<h1>Static Asset Example</h1>

<p>@dataResourceText</p>

@code {
    public string dataResourceText = "Loading resource ...";

    protected override async Task OnInitializedAsync()
    {
        try
        {
            using var stream = 
                await FileSystem.OpenAppPackageFileAsync("Data.txt");
            using var reader = new StreamReader(stream);

            dataResourceText = await reader.ReadToEndAsync();
        }
        catch (FileNotFoundException ex)
        {
            dataResourceText = "Data file not found.";
            Logger.LogError(ex, "'Resource/Raw/Data.txt' not found.");
        }
    }
}

Para obtener más información, consulta los siguientes recursos:

WPF

Coloca el recurso en una carpeta de la aplicación, normalmente en la raíz del proyecto, como una carpeta Resources. En el ejemplo de esta sección se usa un archivo de texto estático.

Resources/Data.txt:

This is text from a static text file resource.

Si una carpeta Properties no existe en la aplicación, cree una carpeta Properties en la raíz de la aplicación.

Si la carpeta Properties no contiene un archivo de recursos (Resources.resx), crea el archivo en Explorador de soluciones con el comando del menú contextual Agregar>Nuevo elemento.

Haz doble clic en el archivo Resource.resx.

Selecciona Cadenas>Archivos en la lista desplegable.

Selecciona Agregar recurso>Agregar archivo existente. Si Visual Studio te pide que confirmes la edición del archivo, selecciona . Ve a la carpeta Resources, selecciona el archivo Data.txt y selecciona Abrir.

En el componente de ejemplo siguiente, ResourceManager.GetString obtiene el texto del recurso de cadena para mostrar.

Advertencia

Nunca uses métodos ResourceManager con datos que no son de confianza.

StaticAssetExample.razor:

@page "/static-asset-example"
@using System.Resources

<h1>Static Asset Example</h1>

<p>@dataResourceText</p>

@code {
    public string dataResourceText = "Loading resource ...";

    protected override void OnInitialized()
    {
        var resources = 
            new ResourceManager(typeof(WpfBlazor.Properties.Resources));

        dataResourceText = resources.GetString("Data") ?? "'Data' not found.";
    }
}

Windows Forms

Coloca el recurso en una carpeta de la aplicación, normalmente en la raíz del proyecto, como una carpeta Resources. En el ejemplo de esta sección se usa un archivo de texto estático.

Resources/Data.txt:

This is text from a static text file resource.

Examina los archivos asociados a Form1 en el Explorador de soluciones. Si Form1 no tienes un archivo de recursos (.resx), agrega un archivo Form1.resx con el comando de menú contextual Agregar>Nuevo elemento .

Haz doble clic en el archivo Form1.resx.

Selecciona Cadenas>Archivos en la lista desplegable.

Selecciona Agregar recurso>Agregar archivo existente. Si Visual Studio te pide que confirmes la edición del archivo, selecciona . Ve a la carpeta Resources, selecciona el archivo Data.txt y selecciona Abrir.

En el ejemplo de componente siguiente:

  • El nombre del ensamblado de la aplicación es WinFormsBlazor. El nombre base de ResourceManager se establece en el nombre del ensamblado de Form1 (WinFormsBlazor.Form1).
  • ResourceManager.GetString obtiene el texto del recurso de cadena para mostrar.

Advertencia

Nunca uses métodos ResourceManager con datos que no son de confianza.

StaticAssetExample.razor:

@page "/static-asset-example"
@using System.Resources

<h1>Static Asset Example</h1>

<p>@dataResourceText</p>

@code {
    public string dataResourceText = "Loading resource ...";

    protected override async Task OnInitializedAsync()
    {   
        var resources = 
            new ResourceManager("WinFormsBlazor.Form1", this.GetType().Assembly);

        dataResourceText = resources.GetString("Data") ?? "'Data' not found.";
    }
}

Recursos estáticos limitados a componentes Razor

Un control BlazorWebView tiene un archivo host configurado (HostPage), normalmente wwwroot/index.html. La ruta de acceso HostPage es relativa a la carpeta de proyecto. Todos los recursos web estáticos (scripts, archivos CSS, imágenes y otros archivos) a los que se hace referencia desde BlazorWebView son relativos a su valor HostPage configurado.

Los recursos web estáticos de una biblioteca de clases (RCL) de Razor usan rutas de acceso especiales: _content/{PACKAGE ID}/{PATH AND FILE NAME}. El marcador de posición {PACKAGE ID} es el id. de paquete de la biblioteca. El id. de paquete tiene como valor predeterminado el nombre de ensamblado del proyecto si <PackageId> no se especifica en el archivo del proyecto. El marcador de posición {PATH AND FILE NAME} es la ruta de acceso y el nombre de archivo en wwwroot. Estas rutas de acceso son subrutas lógicas de la carpeta wwwroot de la aplicación, aunque realmente proceden de otros paquetes o proyectos. Los conjuntos de estilos CSS específicos de componentes también se compilan en la raíz de la carpeta wwwroot.

La raíz web de HostPage determina qué subconjunto de recursos estáticos están disponibles:

  • wwwroot/index.html (Recomendado): todos los recursos de la carpeta wwwroot de la aplicación están disponibles (por ejemplo: wwwroot/image.png está disponible en /image.png), incluidas las subcarpetas (por ejemplo: wwwroot/subfolder/image.png está disponible en /subfolder/image.png). Los recursos estáticos de RCL en la carpeta wwwroot de RCL están disponibles (por ejemplo: wwwroot/image.png está disponible en la ruta de acceso _content/{PACKAGE ID}/image.png), incluidas las subcarpetas (por ejemplo: wwwroot/subfolder/image.png está disponible en la ruta de acceso _content/{PACKAGE ID}/subfolder/image.png).
  • wwwroot/{PATH}/index.html: todos los recursos de la carpeta wwwroot/{PATH} de la aplicación están disponibles mediante rutas de acceso relativas raíz web de la aplicación. Los recursos estáticos RCL de wwwroot/{PATH} no están disponibles porque estarían en una ubicación teórica inexistente, como ../../_content/{PACKAGE ID}/{PATH}, que no es una ruta de acceso relativa admitida.
  • wwwroot/_content/{PACKAGE ID}/index.html: todos los recursos de la carpeta wwwroot/{PATH} de RCL están disponibles mediante rutas de acceso relativas de raíz web RCL. Los recursos estáticos de la aplicación de wwwroot/{PATH} no están disponibles porque estarían en una ubicación teórica inexistente, como ../../{PATH}, que no es una ruta de acceso relativa admitida.

Para la mayoría de las aplicaciones, se recomienda colocar HostPage en la raíz de la carpeta wwwroot de la aplicación, lo que proporciona la mayor flexibilidad para proporcionar recursos estáticos de la aplicación, RCL y las subcarpetas de la aplicación y RCL.

En los ejemplos siguientes se muestra cómo hacer referencia a recursos estáticos desde la raíz web de la aplicación (carpeta wwwroot) con una raíz HostPage en la carpeta wwwroot.

wwwroot/data.txt:

This is text from a static text file resource.

wwwroot/scripts.js:

export function showPrompt(message) {
  return prompt(message, 'Type anything here');
}

La siguiente imagen de Jeep® se usa también en el ejemplo de esta sección. Puedes hacer clic con el botón derecho en la imagen siguiente para guardarla localmente para usarla en una aplicación de prueba local.

wwwroot/jeep-yj.png:

Jeep YJ®

En un componente Razor:

  • El contenido del archivo de texto estático se puede leer mediante las técnicas siguientes:
  • Los archivos JavaScript están disponibles en subrutas lógicas de wwwroot empleando rutas de acceso de ./.
  • La imagen puede ser el atributo de origen (src) de una etiqueta de imagen (<img>).

StaticAssetExample2.razor:

@page "/static-asset-example-2"
@using Microsoft.Extensions.Logging
@implements IAsyncDisposable
@inject IJSRuntime JS
@inject ILogger<StaticAssetExample2> Logger

<h1>Static Asset Example 2</h1>

<h2>Read a file</h2>

<p>@dataResourceText</p>

<h2>Call JavaScript</h2>

<p>
    <button @onclick="TriggerPrompt">Trigger browser window prompt</button>
</p>

<p>@result</p>

<h2>Show an image</h2>

<p><img alt="1991 Jeep YJ" src="/jeep-yj.png" /></p>

<p>
    <em>Jeep</em> and <em>Jeep YJ</em> are registered trademarks of 
    <a href="https://www.stellantis.com">FCA US LLC (Stellantis NV)</a>.
</p>

@code {
    private string dataResourceText = "Loading resource ...";
    private IJSObjectReference? module;
    private string result;

    protected override async Task OnInitializedAsync()
    {   
        try
        {
            dataResourceText = await ReadData();
        }
        catch (FileNotFoundException ex)
        {
            dataResourceText = "Data file not found.";
            Logger.LogError(ex, "'wwwroot/data.txt' not found.");
        }
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./scripts.js");
        }
    }

    private async Task TriggerPrompt()
    {
        result = await Prompt("Provide some text");
    }

    public async ValueTask<string> Prompt(string message) =>
        module is not null ?
            await module.InvokeAsync<string>("showPrompt", message) : null;

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }
    }
}

En las aplicaciones .NET MAUI, agrega el siguiente método ReadData al bloque @code del componente anterior:

private async Task<string> ReadData()
{
    using var stream = await FileSystem.OpenAppPackageFileAsync("wwwroot/data.txt");
    using var reader = new StreamReader(stream);

    return await reader.ReadToEndAsync();
}

En aplicaciones WPF y Windows Forms, agregue el siguiente método ReadData al bloque @code del componente anterior:

private async Task<string> ReadData()
{
    using var reader = new StreamReader("wwwroot/data.txt");

    return await reader.ReadToEndAsync();
}

Los archivos JavaScript colocados también son accesibles en subrutas lógicas de wwwroot. En lugar de usar el script descrito anteriormente para la función showPrompt en wwwroot/scripts.js, el siguiente archivo JavaScript colocado para el componente StaticAssetExample2 también hace que la función esté disponible.

Pages/StaticAssetExample2.razor.js:

export function showPrompt(message) {
  return prompt(message, 'Type anything here');
}

Modifica la referencia de objeto de módulo en el componente StaticAssetExample2 para usar la ruta de acceso del archivo JavaScript colocado (./Pages/StaticAssetExample2.razor.js):

module = await JS.InvokeAsync<IJSObjectReference>("import", 
    "./Pages/StaticAssetExample2.razor.js");

Marcas comerciales

Jeep y Jeep YJ son marcas registradas de FCA US LLC (Stellantis NV).

Recursos adicionales