Share via


使用 Razor 類別庫 (RCL) 跨 Web 和原生用戶端共用資產

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

使用 Razor 類別庫 (RCL),跨 Web 和原生用戶端共用 Razor 元件、C# 程式碼和靜態資產。

本文以下列文章中找到的一般概念為基礎:

本文中的範例會在伺服器端 Blazor 應用程式與相同解決方案中的 .NET MAUIBlazor Hybrid 應用程式之間共用資產:

  • 雖然使用伺服器端 Blazor 應用程式,但指引同樣適用於與 Blazor Hybrid 應用程式共用資產的 Blazor WebAssembly 應用程式。
  • 專案位於相同的解決方案中,但 RCL 可以將共用資產提供給解決方案外部的專案。
  • RCL 會以專案形式新增至解決方案,但任何 RCL 都可以發佈為 NuGet 套件。 NuGet 套件可以將共用資產提供給 Web 和原生用戶端專案。
  • 建立專案的順序並不重要。 不過,仰賴 RCL 進行資產的專案必須在建立 RCL 之後,建立 RCL 的專案參考。

如需建立 RCL 的指引,請參閱從 Razor 類別庫 (RCL) 取用 ASP.NET Core Razor。 或者,在具有 ASP.NET Core 的類別庫中可重複使用 Razor UI 中,存取廣泛套用於 ASP.NET Core 應用程式的其他 RCL 相關指引。

ClickOnce 部署的目標架構

若要使用 ClickOnce 在 .NET 6 中發行具有 Razor 類別庫 (RCL) 的 WPF 或 Windows Forms 專案,除了 net6.0 之外,RCL 還必須以 net6.0-windows 為目標。

範例:

<TargetFrameworks>net6.0;net6.0-windows</TargetFrameworks>

如需詳細資訊,請參閱下列文章:

範例應用程式

如需本文所述的案例範例,請參閱 .NET Podcasts 範例應用程式:

.NET 播客應用程式展示下列技術:

共用 Web UI Razor 元件、程式碼和靜態資產

RCL 中的元件可由使用 Blazor 建置的 Web 和原生用戶端應用程式同時共用。 從 Razor 類別庫 (RCL) 取用 ASP.NET Core Razor 元件中的指引說明如何使用 Razor 類別庫 (RCL) 共用 Razor 元件。 相同的指導方針適用於在 Blazor Hybrid 應用程式中從 RCL 重複使用 Razor 元件。

元件命名空間衍生自 RCL 的套件識別碼或組件名稱,以及 RCL 內的元件資料夾路徑。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件。 針對元件和程式碼,@using 指示詞可以放在 _Imports.razor 檔案中,如下列範例針對名為 SharedLibrary 的 RCL 所示範,使用共用 Razor 元件的 Shared 資料夾,以及共用資料類別的 Data 資料夾:

@using SharedLibrary
@using SharedLibrary.Shared
@using SharedLibrary.Data

將共用靜態資產放在 RCL 的 wwwroot 資料夾中,並在應用程式中更新靜態資產路徑,以使用下列路徑格式:

_content/{PACKAGE ID/ASSEMBLY NAME}/{PATH}/{FILE NAME}

預留位置:

  • {PACKAGE ID/ASSEMBLY NAME}:RCL 的套件識別碼或組件名稱。
  • {PATH}:RCL wwwroot 資料夾內的選擇性路徑。
  • {FILE NAME}:靜態資產的檔案名稱。

上述路徑格式也會用於應用程式中新增至 RCL 的 NuGet 套件所提供的靜態資產。

針對名為 SharedLibrary 的 RCL,並使用縮短 Bootstrap 樣式表單做為範例:

_content/SharedLibrary/css/bootstrap/bootstrap.min.css

如需有關如何跨專案共用靜態資產的其他資訊,請參閱下列文章:

index.html 檔案通常專屬於應用程式,且應該保留在 Blazor Hybrid 應用程式或 Blazor WebAssembly 應用程式中。 通常不會共用 index.html 檔案。

根 Razor 元件 (App.razorMain.razor) 可以共用,但通常可能需要專屬於主控應用程式。 例如,啟用驗證時,伺服器端 Blazor 和 Blazor WebAssembly 專案範本中的 App.razor 不同。 您可以新增 AdditionalAssemblies 參數來指定任何共用可路由元件的位置,且您可以依類型名稱指定路由器的共用預設配置元件

提供與裝載模型無關的程式碼和服務

當程式碼在裝載模型或目標平台之間必須有所不同時,請將程式碼抽象化為介面,並在每個專案中插入服務實作。

下列氣象資料範例會抽象化不同的氣象預報服務實作:

  • 使用 Blazor Hybrid 和 Blazor WebAssembly 的 HTTP 要求。
  • 直接要求伺服器端 Blazor 的資料。

此範例使用下列規格和慣例:

  • RCL 命名為 SharedLibrary,並且包含下列資料夾和命名空間:
    • Data:包含 WeatherForecast 類別,做為氣象資料的模型。
    • Interfaces:包含名為 IWeatherForecastService 的服務實作服務介面。
  • FetchData 元件會保留在 RCL 的 Pages 資料夾中,由任何取用 RCL 的應用程式路由傳送。
  • 每個 Blazor 應用程式都會維護實作 IWeatherForecastService 介面的服務實作。

在 RCL 中的 Data/WeatherForecast.cs

namespace SharedLibrary.Data;

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    public string? Summary { get; set; }
}

在 RCL 中的 Interfaces/IWeatherForecastService.cs

using SharedLibrary.Data;

namespace SharedLibrary.Interfaces;

public interface IWeatherForecastService
{
    Task<WeatherForecast[]?> GetForecastAsync(DateTime startDate);
}

RCL 中的 _Imports.razor 檔案包含下列新增的命名空間:

@using SharedLibrary.Data
@using SharedLibrary.Interfaces

Blazor Hybrid 和 Blazor WebAssembly 應用程式中的 Services/WeatherForecastService.cs

using System.Net.Http.Json;
using SharedLibrary.Data;
using SharedLibrary.Interfaces;

namespace {APP NAMESPACE}.Services;

public class WeatherForecastService : IWeatherForecastService
{
    private readonly HttpClient http;

    public WeatherForecastService(HttpClient http)
    {
        this.http = http;
    }

    public async Task<WeatherForecast[]?> GetForecastAsync(DateTime startDate) =>
        await http.GetFromJsonAsync<WeatherForecast[]?>("WeatherForecast");
}

在上述範例中,{APP NAMESPACE} 預留位置是應用程式的命名空間。

伺服器端 Blazor 應用程式中的 Services/WeatherForecastService.cs

using SharedLibrary.Data;
using SharedLibrary.Interfaces;

namespace {APP NAMESPACE}.Services;

public class WeatherForecastService : IWeatherForecastService
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot"
    };

    public async Task<WeatherForecast[]?> GetForecastAsync(DateTime startDate) =>
        await Task.FromResult(Enumerable.Range(1, 5)
            .Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            }).ToArray());
}

在上述範例中,{APP NAMESPACE} 預留位置是應用程式的命名空間。

Blazor Hybrid、Blazor WebAssembly 和伺服器端 Blazor 應用程式會針對 IWeatherForecastService 註冊其氣象預報服務實作 (Services.WeatherForecastService)。

Blazor WebAssembly 專案也會註冊 HttpClient。 根據預設,在從 Blazor WebAssembly 專案範本建立的應用程式中註冊的 HttpClient,就足以達到此目的。 如需詳細資訊,請參閱從 ASP.NET Core Blazor 應用程式呼叫 Web API

在 RCL 中的 Pages/FetchData.razor

@page "/fetchdata"
@inject IWeatherForecastService ForecastService

<PageTitle>Weather forecast</PageTitle>

<h1>Weather forecast</h1>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[]? forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }
}

其他資源