Condividi tramite


Più app ASP.NET Core Blazor WebAssembly ospitate

Nota

Questa non è la versione più recente di questo articolo. Per la versione più recente di questo articolo, vedere la versione di .NET 7.

Questo articolo illustra come configurare un'app ospitata Blazor WebAssembly per ospitare più Blazor WebAssembly app.

Impostazione

Selezionare la versione di questo articolo che soddisfa i requisiti di hosting, ovvero l'hosting di porte/domini (ad esempio, :5001/:5002 o ) o firstapp.comsecondapp.com/l'hosting di sottopercorso di route (ad esempio, /FirstApp e )./SecondApp

Con la selezione dell'hosting corrente, questo articolo illustra l'hosting di porte/dominio (ad esempio, :5001/:5002 o ).firstapp.com/secondapp.com

Negli esempi seguenti:

  • Il nome del progetto dell'app ospitata Blazor WebAssembly si trova MultipleBlazorApps in una cartella denominata MultipleBlazorApps.
  • I tre progetti nella soluzione prima dell'aggiunta di una seconda app client si trovano MultipleBlazorApps.Client nella Client cartella , MultipleBlazorApps.Server nella Server cartella e MultipleBlazorApps.Shared nella Shared cartella .
  • L'app client iniziale (prima) è il progetto client predefinito della soluzione creata dal modello di Blazor WebAssembly progetto.
  • Alla soluzione viene aggiunta una seconda app client, MultipleBlazorApps.SecondClient in una cartella denominata SecondClient.
  • Facoltativamente, il progetto server (MultipleBlazorApps.Server) può gestire pagine o visualizzazioni come un'app Razor Pages o MVC.
  • La prima app client è accessibile in un browser sulla porta 5001 o con un host di firstapp.com. La seconda app client è accessibile in un browser sulla porta 5002 o con un host di secondapp.com.

Con la selezione corrente, questo articolo illustra l'hosting del sottopercorso di route , ad esempio /FirstApp e /SecondApp.

Negli esempi seguenti:

  • Il nome del progetto dell'app ospitata Blazor WebAssembly si trova MultipleBlazorApps in una cartella denominata MultipleBlazorApps.
  • I tre progetti nella soluzione prima dell'aggiunta di una seconda app client si trovano MultipleBlazorApps.Client nella Client cartella , MultipleBlazorApps.Server nella Server cartella e MultipleBlazorApps.Shared nella Shared cartella .
  • L'app client iniziale (prima) è il progetto client predefinito della soluzione creata dal modello di Blazor WebAssembly progetto.
  • Alla soluzione viene aggiunta una seconda app client, MultipleBlazorApps.SecondClient in una cartella denominata SecondClient.
  • Facoltativamente, il progetto server (MultipleBlazorApps.Server) può gestire pagine o visualizzazioni come un'app MVC o Pagine formali Razor .
  • Entrambe le app client usano la porta predefinita definita dal MultipleBlazorApps.Server file del Properties/launchSettings.json progetto nel relativo applicationUrl valore. La prima app client è accessibile in un browser nel /FirstApp sottopercorso. La seconda app client è accessibile in un browser nel /SecondApp sottopercorso.

Gli esempi illustrati in questo articolo richiedono una configurazione aggiuntiva per:

  • Accesso alle app direttamente nei domini firstapp.com host di esempio e secondapp.com.
  • Certificati per le app client per abilitare la sicurezza TLS/HTTPS.
  • Configurazione dell'app server come Razor app Pages per le funzionalità seguenti:
    • Integrazione dei Razor componenti in pagine o visualizzazioni.
    • Prerendering dei Razor componenti.

Le configurazioni precedenti non rientrano nell'ambito di questo articolo. Per ulteriori informazioni, vedi le seguenti risorse:

Usare una soluzione ospitataBlazor WebAssembly esistente o creare una nuova soluzione ospitata Blazor WebAssembly dal Blazor WebAssembly modello di progetto passando l'opzione -ho|--hosted se si usa l'interfaccia della riga di comando di .NET o selezionando la casella di controllo ASP.NET Core Hosted in Visual Studio quando il progetto viene creato nell'IDE.

Usare una cartella per la soluzione denominata MultipleBlazorApps e denominare il progetto MultipleBlazorApps.

Creare una nuova cartella nella soluzione denominata SecondClient. Nella nuova cartella aggiungere una seconda Blazor WebAssembly app client denominata MultipleBlazorApps.SecondClient. Aggiungere il progetto come app autonoma Blazor WebAssembly . Per creare un'app autonoma Blazor WebAssembly , non passare l'opzione -ho|--hosted se si usa l'interfaccia della riga di comando di .NET o non usare la casella di controllo ASP.NET Core Hosted se si usa Visual Studio.

Apportare le modifiche seguenti al MultipleBlazorApps.SecondClient progetto:

  • Copiare il FetchData componente (Pages/FetchData.razor) dalla Client/Pages cartella alla SecondClient/Pages cartella . Questo passaggio è obbligatorio perché un'app autonoma Blazor WebAssembly non chiama il controller di un Server progetto per i dati meteo, usa un file di dati statici. Copiando il FetchData componente nel progetto aggiunto, la seconda app client effettua anche una chiamata API Web all'API server per i dati meteo.
  • Eliminare la SecondClient/wwwroot/sample-data cartella, perché il weather.json file nella cartella non viene usato.

La tabella seguente descrive le cartelle e i nomi dei progetti della soluzione dopo l'aggiunta della cartella e MultipleBlazorApps.SecondClient del SecondClient progetto.

Cartella fisica Nome progetto Descrizione
Client MultipleBlazorApps.Client Blazor WebAssembly app client
SecondClient MultipleBlazorApps.SecondClient Blazor WebAssembly app client
Server MultipleBlazorApps.Server ASP.NET'app server Core
Shared MultipleBlazorApps.Shared Progetto risorse condivise

Il MultipleBlazorApps.Server progetto serve le due Blazor WebAssembly app client e fornisce i dati meteo ai componenti delle FetchData app client tramite un controller MVC. Facoltativamente, il MultipleBlazorApps.Server progetto può anche servire pagine o visualizzazioni, come un'app Pages o MVC tradizionale Razor . I passaggi per abilitare la gestione di pagine o visualizzazioni sono descritti più avanti in questo articolo.

Nota

La dimostrazione in questo articolo usa i nomi dei percorsi di asset Web statici di FirstApp per il MultipleBlazorApps.Client progetto e SecondApp per il MultipleBlazorApps.SecondClient progetto. I nomi "FirstApp" e "SecondApp" sono solo a scopo dimostrativo. Altri nomi sono accettabili per distinguere le app client, ad esempio App1App2/, Client1/Client2, 1/2o qualsiasi schema di denominazione simile.

Quando si instradano le richieste alle app client da una porta o da un dominio, "FirstApp" e "SecondApp" vengono usate internamente per instradare le richieste e gestire le risposte per gli asset statici e non vengono visualizzate nella barra degli indirizzi del browser.

Nota

La dimostrazione in questo articolo usa i nomi dei percorsi di asset Web statici di FirstApp per il MultipleBlazorApps.Client progetto e SecondApp per il MultipleBlazorApps.SecondClient progetto. I nomi "FirstApp" e "SecondApp" sono solo a scopo dimostrativo. Altri nomi sono accettabili per distinguere le app client, ad esempio App1App2/, Client1/Client2, 1/2o qualsiasi schema di denominazione simile.

"FirstApp" e "SecondApp" vengono visualizzati anche nella barra degli indirizzi del browser perché le richieste vengono instradate alle due app client usando questi nomi. Altri segmenti di route URL validi sono supportati e i segmenti di route non devono necessariamente corrispondere ai nomi usati per instradare internamente gli asset Web statici. L'uso di "FirstApp" e "SecondApp" sia per il routing interno delle risorse statiche che per il routing delle richieste di app è semplicemente per la convocazione negli esempi di questo articolo.

Nel file di progetto della prima app client (MultipleBlazorApps.Client.csproj), aggiungere una <StaticWebAssetBasePath> proprietà a un <PropertyGroup> con il valore per FirstApp impostare il percorso di base per gli asset statici del progetto:

<StaticWebAssetBasePath>FirstApp</StaticWebAssetBasePath>

MultipleBlazorApps.SecondClient Nel file di progetto dell'app (MultipleBlazorApps.SecondClient.csproj):

  • Aggiungere una <StaticWebAssetBasePath> proprietà a un <PropertyGroup> oggetto con un valore di SecondApp:

    <StaticWebAssetBasePath>SecondApp</StaticWebAssetBasePath>
    
  • Aggiungere un riferimento al progetto a MultipleBlazorApps.Shared un <ItemGroup>oggetto :

    <ItemGroup>
      <ProjectReference Include="..\Shared\MultipleBlazorApps.Shared.csproj" />
    </ItemGroup>
    

Nel file di progetto dell'app server (Server/MultipleBlazorApps.Server.csproj) creare un riferimento al progetto per l'app client aggiunta MultipleBlazorApps.SecondClient in :<ItemGroup>

<ProjectReference Include="..\SecondClient\MultipleBlazorApps.SecondClient.csproj" />

Nel file dell'app Properties/launchSettings.json server configurare l'oggetto applicationUrl del Kestrel profilo (MultipleBlazorApps.Server) per accedere alle app client alle porte 5001 e 5002. Se si configura l'ambiente locale per l'uso dei domini di esempio, gli URL per applicationUrl possono usare firstapp.com e secondapp.com non usare le porte.

Nota

L'uso delle porte in questa dimostrazione consente l'accesso ai progetti client in un browser locale senza la necessità di configurare un ambiente di hosting locale in modo che i Web browser possano accedere alle app client tramite le configurazioni firstapp.com host e secondapp.com. Negli scenari di produzione, una configurazione tipica consiste nell'usare sottodomini per distinguere le app client.

Ad esempio:

  • Le porte vengono eliminate dalla configurazione di questa dimostrazione.
  • Gli host vengono modificati in modo da usare sottodomini, ad esempio www.contoso.com per i visitatori del sito e admin.contoso.com per gli amministratori.
  • È possibile includere host aggiuntivi per altre app client e almeno un altro host è necessario se l'app server è anche un'app Razor Pages o MVC che serve pagine o visualizzazioni.

Se si prevede di gestire pagine o visualizzazioni dall'app server, usare l'impostazione seguente applicationUrl nel Properties/launchSettings.json file, che consente l'accesso seguente:

  • Facoltativamente, l'app Razor Pages o MVC (MultipleBlazorApps.Server project) risponde alle richieste sulla porta 5000.
  • Le risposte alle richieste per il primo client (MultipleBlazorApps.Client progetto) si trovano sulla porta 5001.
  • Le risposte alle richieste per il secondo client (MultipleBlazorApps.SecondClient progetto) si trovano sulla porta 5002.
"applicationUrl": "https://localhost:5000;https://localhost:5001;https://localhost:5002",

Se non si prevede che l'app server gestisca pagine o visualizzazioni e gestisca solo le Blazor WebAssembly app client, usare l'impostazione seguente, che consente l'accesso seguente:

  • La prima app client risponde sulla porta 5001.
  • La seconda app client risponde sulla porta 5002.
"applicationUrl": "https://localhost:5001;https://localhost:5002",

Nel file dell'app Program.cs server rimuovere il codice seguente, visualizzato dopo la chiamata a UseHttpsRedirection:

  • Se si prevede di gestire pagine o visualizzazioni dall'app server, eliminare le righe di codice seguenti:

    - app.UseBlazorFrameworkFiles();
    
    - app.MapFallbackToFile("index.html");
    
  • Se si prevede che l'app server gestisca solo le Blazor WebAssembly app client, eliminare il codice seguente:

    - app.UseBlazorFrameworkFiles();
    
    ...
    
    - app.UseRouting();
    
    - app.MapRazorPages();
    - app.MapControllers();
    - app.MapFallbackToFile("index.html");
    

    Lasciare il middleware dei file statici sul posto:

    app.UseStaticFiles();
    
  • Aggiungere middleware che esegue il mapping delle richieste alle app client. L'esempio seguente configura il middleware da eseguire quando la porta della richiesta è 5001 per la prima app client o 5002 per la seconda app client oppure l'host della richiesta è firstapp.com per la prima app client o secondapp.com per la seconda app client.

    Nota

    L'uso degli host (firstapp.com/secondapp.com) in un sistema locale con un browser locale richiede una configurazione aggiuntiva oltre l'ambito di questo articolo. Per i test locali di questo scenario, è consigliabile usare le porte. Le app di produzione tipiche sono configurate per l'uso di sottodomini, ad esempio www.contoso.com per i visitatori del sito e admin.contoso.com per gli amministratori. Con la configurazione corretta di DNS e server, che esula dall'ambito di questo articolo e dipende dalle tecnologie usate, l'app risponde alle richieste in qualsiasi host denominato nel codice seguente.

    Dove è stata rimossa la app.UseBlazorFrameworkFiles(); riga da Program.cs, inserire il codice seguente:

    app.MapWhen(ctx => ctx.Request.Host.Port == 5001 || 
        ctx.Request.Host.Equals("firstapp.com"), first =>
    {
        first.Use((ctx, nxt) =>
        {
            ctx.Request.Path = "/FirstApp" + ctx.Request.Path;
            return nxt();
        });
    
        first.UseBlazorFrameworkFiles("/FirstApp");
        first.UseStaticFiles();
        first.UseStaticFiles("/FirstApp");
        first.UseRouting();
    
        first.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapFallbackToFile("/FirstApp/{*path:nonfile}", 
                "FirstApp/index.html");
        });
    });
    
    app.MapWhen(ctx => ctx.Request.Host.Port == 5002 || 
        ctx.Request.Host.Equals("secondapp.com"), second =>
    {
        second.Use((ctx, nxt) =>
        {
            ctx.Request.Path = "/SecondApp" + ctx.Request.Path;
            return nxt();
        });
    
        second.UseBlazorFrameworkFiles("/SecondApp");
        second.UseStaticFiles();
        second.UseStaticFiles("/SecondApp");
        second.UseRouting();
    
        second.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapFallbackToFile("/SecondApp/{*path:nonfile}", 
                "SecondApp/index.html");
        });
    });
    

    Avviso

    L'API che si basa sull'intestazione Host, ad esempio HttpRequest.Host e RequireHost, è soggetta a potenziali spoofing da parte dei client.

    Per evitare lo spoofing di host e porta, usare uno degli approcci seguenti:

  • Aggiungere middleware che esegue il mapping delle richieste alle app client. L'esempio seguente configura il middleware da eseguire quando il subpath della richiesta è /FirstApp per la prima app client o /SecondApp per la seconda app client.

    Dove è stata rimossa la app.UseBlazorFrameworkFiles(); riga da Program.cs, inserire il codice seguente:

    app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/FirstApp", 
        StringComparison.OrdinalIgnoreCase), first =>
    {
        first.UseBlazorFrameworkFiles("/FirstApp");
        first.UseStaticFiles();
        first.UseStaticFiles("/FirstApp");
        first.UseRouting();
    
        first.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapFallbackToFile("/FirstApp/{*path:nonfile}",
                "FirstApp/index.html");
        });
    });
    
    app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/SecondApp", 
        StringComparison.OrdinalIgnoreCase), second =>
    {
        second.UseBlazorFrameworkFiles("/SecondApp");
        second.UseStaticFiles();
        second.UseStaticFiles("/SecondApp");
        second.UseRouting();
    
        second.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapFallbackToFile("/SecondApp/{*path:nonfile}",
                "SecondApp/index.html");
        });
    });
    
  • Impostare il percorso di base in ogni app client:

    Nel file della prima app client (Client/wwwroot/index.html) aggiornare il valore del index.html <base> tag in modo da riflettere il sottopercorso. La barra finale è obbligatoria:

    <base href="/FirstApp/" />
    

    Nel file della seconda app client (SecondClient/wwwroot/index.html) aggiornare il valore del index.html <base> tag in modo da riflettere il sottopercorso. La barra finale è obbligatoria:

    <base href="/SecondApp/" />
    

Per altre informazioni su UseStaticFiles, vedere ASP.NET File statici coreBlazor.

Per altre informazioni su UseBlazorFrameworkFiles e MapFallbackToFile, vedere le risorse seguenti:

Nota

I collegamenti della documentazione all'origine del riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la versione successiva di .NET. Per selezionare un tag per una versione specifica, usare l'elenco a discesa Switch branches or tags. Per altre informazioni, vedere How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Come selezionare un tag di versione del codice sorgente di ASP.NET - dotnet/AspNetCore.Docs #26205).

Le richieste dalle app client a /WeatherForecast nell'API server sono a /FirstApp/WeatherForecast o /SecondApp/WeatherForecast a seconda dell'app client che effettua la richiesta. Di conseguenza, le route del controller che restituiscono dati meteo dall'API server richiedono una modifica per includere i segmenti di percorso.

Nel controller di previsione meteo dell'app server (Controllers/WeatherForecastController.cs), sostituire la route esistente ([Route("[controller]")]) con WeatherForecastController le route seguenti, che prendono in considerazione i percorsi delle richieste client:

[Route("FirstApp/[controller]")]
[Route("SecondApp/[controller]")]

Se si prevede di gestire le pagine dall'app server, aggiungere una IndexRazor pagina alla Pages cartella dell'app server:

Pages/Index.cshtml:

@page
@model MultipleBlazorApps.Server.Pages.IndexModel
@{
    ViewData["Title"] = "Home";
}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Home</title>
</head>
<body>
    <div class="main">
        <div class="content px-4">

            <div>
                <h1>Welcome</h1>
                <p>Hello from Razor Pages!</p>
            </div>
        </div>
    </div>
</body>
</html>

Pages/Index.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace MultipleBlazorApps.Server.Pages;

public class IndexModel : PageModel
{
    public void OnGet()
    {
    }
}
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace MultipleBlazorApps.Server.Pages
{
    public class IndexModel : PageModel
    {
        public void OnGet()
        {
        }
    }
}

Nota

La pagina precedente Index è un esempio minimo a scopo dimostrativo. Se l'app richiede asset di Pagine aggiuntivi Razor , ad esempio layout, stili, script e importazioni, ottenerli da un'app creata dal modello di Razor progetto Pages. Per altre informazioni, vedere Introduzione alle Razor pagine in ASP.NET Core.

Se si prevede di gestire le visualizzazioni MVC dall'app server, aggiungere una Index visualizzazione e un Home controller:

Views/Home/Index.cshtml:

@{
    ViewData["Title"] = "Home";
}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Home</title>
</head>
<body>
    <div class="main">
        <div class="content px-4">

            <div>
                <h1>Welcome</h1>
                <p>Hello from MVC!</p>
            </div>
        </div>
    </div>
</body>
</html>

Controllers/HomeController.cs:

using Microsoft.AspNetCore.Mvc;

namespace MultipleBlazorApps.Server.Controllers;

public class HomeController : Controller
{
    public IActionResult Index() => View();
}

Nota

La vista precedente Index è un esempio minimo a scopo dimostrativo. Se l'app richiede asset MVC aggiuntivi, ad esempio layout, stili, script e importazioni, ottenerli da un'app creata dal modello di progetto MVC. Per altre informazioni, vedere Introduzione a ASP.NET Core MVC.

Per altre informazioni sull'uso dei Razor componenti di una delle app client nelle pagine o nelle visualizzazioni dell'app server, vedere Integrare ASP.NET Componenti principali Razor con MVC o Razor Pages nelle soluzioni ospitateBlazor WebAssembly.

Eseguire l'app

Eseguire il MultipleBlazorApps.Server progetto:

  • Accedere all'app client iniziale all'indirizzo https://localhost:5001.
  • Accedere all'app client aggiunta all'indirizzo https://localhost:5002.
  • Se l'app server è configurata per gestire pagine o visualizzazioni, accedere alla pagina o alla visualizzazione all'indirizzo Index https://localhost:5000.
  • Accedere all'app client iniziale all'indirizzo https://localhost:{DEFAULT PORT}/FirstApp.
  • Accedere all'app client aggiunta all'indirizzo https://localhost:{DEFAULT PORT}/SecondApp.
  • Se l'app server è configurata per gestire pagine o visualizzazioni, accedere alla pagina o alla visualizzazione all'indirizzo Index https://localhost:{DEFAULT PORT}.

Negli URL di esempio precedenti, il {DEFAULT PORT} segnaposto è la porta predefinita definita dal MultipleBlazorApps.Server file del Properties/launchSettings.json progetto nel relativo applicationUrl valore.

Importante

Quando si esegue l'app con il dotnet watch comando (o dotnet run) (interfaccia della riga di comando .NET), verificare che la shell dei comandi sia aperta nella Server cartella della soluzione.

Quando si usa il pulsante Start di Visual Studio per eseguire l'app, verificare che il MultipleBlazorApps.Server progetto sia impostato come progetto di avvio (evidenziato in Esplora soluzioni).

Asset statici

Quando un asset si trova nella cartella di wwwroot un'app client, specificare il percorso della richiesta di asset statico nei componenti:

<img alt="..." src="{PATH AND FILE NAME}" />

Il segnaposto {PATH AND FILE NAME} corrisponde al percorso e al nome del file in wwwroot.

Ad esempio, l'origine per un'immagine Jeep (jeep-yj.png) nella vehicle cartella di wwwroot:

<img alt="Jeep Wrangler YJ" src="vehicle/jeep-yj.png" />

Supporto della libreria di classi Razor (RCL)

Aggiungere la Razor libreria di classi (RCL) alla soluzione come nuovo progetto:

  • In Esplora soluzioni fare clic con il pulsante destro del mouse sulla soluzione, quindi scegliere Aggiungi>Nuovo progetto.
  • Usare il Razor modello di progetto Libreria di classi per creare il progetto. Gli esempi in questa sezione usano il nome ComponentLibrarydel progetto , che è anche il nome dell'assembly RCL. Non selezionare la casella di controllo Support pages and views (Pagine e visualizzazioni del supporto).

Per ogni app client ospitataBlazor WebAssembly, creare un riferimento al progetto RCL facendo clic con il pulsante destro del mouse su ogni progetto client in Esplora soluzioni e scegliendo Aggiungi>riferimento al progetto.

Usare i componenti dell'RCL nelle app client con uno degli approcci seguenti:

  • Inserire una @using direttiva all'inizio del componente per lo spazio dei nomi rcl e aggiungere Razor la sintassi per il componente. L'esempio seguente è relativo a un rcl con il nome ComponentLibrarydell'assembly :

    @using ComponentLibrary
    
    ...
    
    <Component1 />
    
  • Specificare lo spazio dei nomi di RCL insieme alla Razor sintassi per il componente. Questo approccio non richiede una @using direttiva all'inizio del file del componente. L'esempio seguente è relativo a un rcl con il nome ComponentLibrarydell'assembly :

    <ComponentLibrary.Component1 />
    

Nota

È anche possibile inserire una @using direttiva nel file di _Import.razor ogni app client, che rende lo spazio dei nomi RCL disponibile a livello globale per i componenti di tale progetto.

Quando qualsiasi altro asset statico si trova nella wwwroot cartella di un RCL, fare riferimento all'asset statico in un'app client in base alle indicazioni contenute nell'interfaccia utente riutilizzabile Razor nelle librerie di classi con ASP.NET Core:

<img alt="..." src="_content/{PACKAGE ID}/{PATH AND FILE NAME}" />

Il {PACKAGE ID} segnaposto è l'ID del pacchetto RCL. Per impostazione predefinita, l'ID pacchetto è il nome dell'assembly del progetto, se <PackageId> non è specificato nel file di progetto. Il {PATH AND FILE NAME} segnaposto è percorso e nome file in wwwroot.

L'esempio seguente mostra il markup per un'immagine Jeep (jeep-yj.png) nella vehicle cartella della cartella rcl wwwroot . L'esempio seguente è relativo a un rcl con il nome ComponentLibrarydell'assembly :

<img alt="Jeep Wrangler YJ" src="_content/ComponentLibrary/vehicle/jeep-yj.png" />

Risorse aggiuntive