다음을 통해 공유


ASP.NET Core Blazor Hybrid 정적 파일

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Warning

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

이 문서에서는 Blazor Hybrid 앱에서 정적 자산 파일을 사용하는 방법을 설명합니다.

Blazor Hybrid 앱에서 정적 파일은 다음 방법을 사용하여 Razor 구성 요소가 액세스하는 앱 리소스입니다.

정적 자산이 Razor 구성 요소에서만 사용되는 경우 Blazor WebAssembly 및 Blazor Server 앱과 비슷한 방식으로 웹 루트(wwwroot 폴더)에서 정적 자산을 사용할 수 있습니다. 자세한 내용은 Razor 구성 요소로 제한된 정적 자산 섹션을 참조하세요.

.NET MAUI

.NET MAUI 앱에서 MauiAsset 빌드 작업 및 .NET MAUI file system helpers를 사용하는 원시 자산은 정적 자산에 사용됩니다.

참고 항목

파일 선택, 기본 설정 저장 및 보안 스토리지 사용과 같은 기능을 위해 지원되는 모든 플랫폼에서 디바이스의 스토리지와 함께 작동하는 인터페이스, 클래스 및 지원 형식이 네임스페이스에 있습니다 Microsoft.Maui.Storage . 네임스페이스는 MAUI Blazor Hybrid 앱 전체에서 사용할 수 있으므로 클래스 파일에 문을 지정하거나 @usingRazor 네임스페이스에 대한 구성 요소의 Razor 지시문을 지정할 using 필요가 없습니다.

원시 자산을 앱의 Resources/Raw 폴더에 배치합니다. 이 섹션의 예제에서는 정적 텍스트 파일을 사용합니다.

Resources/Raw/Data.txt:

This is text from a static text file resource.

다음 Razor 구성 요소는

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.");
        }
    }
}

자세한 내용은 다음 리소스를 참조하세요.

WPF

자산을 앱의 폴더(일반적으로 프로젝트의 루트(예: Resources 폴더))에 배치합니다. 이 섹션의 예제에서는 정적 텍스트 파일을 사용합니다.

Resources/Data.txt:

This is text from a static text file resource.

앱에 Properties 폴더가 없는 경우 앱의 루트에 Properties 폴더를 만듭니다.

Properties 폴더에 리소스 파일(Resources.resx)이 없는 경우 추가>새 항목 바로 가기 메뉴 명령을 사용하여 솔루션 탐색기에 파일을 만듭니다.

Resource.resx 파일을 두 번 클릭합니다.

드롭다운 목록에서 문자열>파일을 선택합니다.

리소스 추가>기존 파일 추가를 선택합니다. Visual Studio에 파일 편집을 확인하라는 메시지가 표시되면 를 선택합니다. Resources 폴더로 이동하여 Data.txt 파일을 선택한 다음 열기를 선택합니다.

다음 예제 구성 요소에서 ResourceManager.GetString은 표시할 문자열 리소스의 텍스트를 가져옵니다.

Warning

신뢰할 수 없는 데이터와 함께 ResourceManager 메서드를 사용하지 마세요.

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

자산을 앱의 폴더(일반적으로 프로젝트의 루트(예: Resources 폴더))에 배치합니다. 이 섹션의 예제에서는 정적 텍스트 파일을 사용합니다.

Resources/Data.txt:

This is text from a static text file resource.

솔루션 탐색기에서 Form1과 연결된 파일을 검사합니다. Form1에 리소스 파일(.resx)이 없는 경우 추가>새 항목 바로 가기 메뉴 명령을 사용하여 Form1.resx 파일을 추가합니다.

Form1.resx 파일을 두 번 클릭합니다.

드롭다운 목록에서 문자열>파일을 선택합니다.

리소스 추가>기존 파일 추가를 선택합니다. Visual Studio에 파일 편집을 확인하라는 메시지가 표시되면 를 선택합니다. Resources 폴더로 이동하여 Data.txt 파일을 선택한 다음 열기를 선택합니다.

다음 예제 구성 요소에서:

  • WinFormsBlazor은 앱의 어셈블리 이름입니다. ResourceManager의 기본 이름은 Form1의 어셈블리 이름(WinFormsBlazor.Form1)으로 설정됩니다.
  • ResourceManager.GetString은 표시할 문자열 리소스의 텍스트를 가져옵니다.

Warning

신뢰할 수 없는 데이터와 함께 ResourceManager 메서드를 사용하지 마세요.

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.";
    }
}

Razor 구성 요소로 제한된 정적 자산

BlazorWebView 컨트롤에는 구성된 호스트 파일(HostPage), 일반적으로 wwwroot/index.html이 있습니다. HostPage 경로는 프로젝트에 상대적입니다. BlazorWebView에서 참조되는 모든 정적 웹 자산(스크립트, CSS 파일, 이미지 및 기타 파일)은 구성된 HostPage를 기준으로 합니다.

RCL(Razor 클래스 라이브러리)의 정적 웹 자산은 특수 경로 _content/{PACKAGE ID}/{PATH AND FILE NAME}를 사용합니다. {PACKAGE ID} 자리 표시자는 라이브러리의 패키지 ID입니다. <PackageId>가 프로젝트 파일에 지정되지 않은 경우 패키지 ID는 기본적으로 프로젝트의 어셈블리 이름으로 설정됩니다. {PATH AND FILE NAME} 자리 표시자는 wwwroot 아래의 경로 및 파일 이름입니다. 이러한 경로는 실제로 다른 패키지 또는 프로젝트에서 들어오지만 앱 wwwroot 폴더의 논리적 하위 경로입니다. 구성 요소별 CSS 스타일 번들도 wwwroot 폴더의 루트에 빌드됩니다.

HostPage의 웹 루트는 사용할 수 있는 정적 자산의 하위 집합을 결정합니다.

  • wwwroot/index.html(권장): 하위 폴더(예: 사용 가능)를 포함하여 앱 폴더의 wwwroot 모든 자산을 사용할 /image.png수 있습니다(예: wwwroot/image.png wwwroot/subfolder/image.png 다음에서 /subfolder/image.png사용 가능). 하위 폴더(예: _content/{PACKAGE ID}/subfolder/image.png 경로에서 wwwroot/subfolder/image.png 사용 가능) RCL wwwroot 폴더의 RCL 정적 자산을 사용할 수 있습니다(예: _content/{PACKAGE ID}/image.png 경로에서 wwwroot/image.png 사용 가능).
  • wwwroot/{PATH}/index.html: 앱의 wwwroot/{PATH} 폴더에 있는 모든 자산은 앱 웹 루트 상대 경로를 사용하여 사용할 수 있습니다. RCL 정적 자산은 wwwroot/{PATH} 지원되는 상대 경로가 아닌 등 존재하지 않는 이론적 위치에 ../../_content/{PACKAGE ID}/{PATH}있기 때문입니다.
  • wwwroot/_content/{PACKAGE ID}/index.html: RCL의 wwwroot/{PATH} 폴더에 있는 모든 자산은 RCL 웹 루트 상대 경로를 사용하여 사용할 수 있습니다. 앱의 정적 자산 wwwroot/{PATH} 은 지원되는 상대 경로가 아닌 등 존재하지 않는 이론적 위치에 ../../{PATH}있기 때문이 아닙니다.

대부분의 앱에서는 앱, RCL, 앱 및 RCL의 하위 폴더를 통해 정적 자산을 제공하는 가장 큰 유연성을 제공하는 앱 wwwroot 폴더의 루트에 HostPage를 배치 하는 것이 좋습니다.

다음 예제에서는 wwwroot 폴더에 HostPage 루트가 있는 앱의 웹 루트(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');
}

다음 Jeep® 이미지는 이 섹션의 예제에서도 사용됩니다. 다음 이미지를 마우스 오른쪽 단추로 클릭하여 로컬 테스트 앱에서 사용할 수 있도록 로컬로 저장할 수 있습니다.

wwwroot/jeep-yj.png:

Jeep YJ®

Razor 구성 요소에서:

  • 정적 텍스트 파일 내용은 다음 기술을 사용하여 읽을 수 있습니다.
  • JavaScript 파일은 ./경로를 사용하는 wwwroot의 논리적 하위 경로에서 사용할 수 있습니다.
  • 이미지는 이미지 태그(<img>)의 원본 특성(src)일 수 있습니다.

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)
            {
            }
        }
    }
}

.NET MAUI 앱에서 이전 구성 요소의 @code 블록에 다음 ReadData 메서드를 추가합니다.

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

    return await reader.ReadToEndAsync();
}

WPF 및Windows Forms 앱에서 이전 구성 요소의 @code 블록에 다음 ReadData 메서드를 추가합니다.

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

    return await reader.ReadToEndAsync();
}

배치된 JavaScript 파일wwwroot의 논리적 하위 경로에서도 액세스할 수 있습니다. wwwroot/scripts.jsshowPrompt 함수에 대해 앞에서 설명한 스크립트를 사용하는 대신, StaticAssetExample2 구성 요소에 대해 다음과 같은 배치된 JavaScript 파일도 함수를 사용할 수 있게 합니다.

Pages/StaticAssetExample2.razor.js:

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

StaticAssetExample2 구성 요소에서 모듈 개체 참조를 수정하여 배치된 JavaScript 파일 경로(./Pages/StaticAssetExample2.razor.js)를 사용합니다.

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

상표

JeepJeep YJFCA US LLC(Stellantis NV)의 상표로 등록되어 있습니다.

추가 리소스