Passa al contenuto principale

Blazor WASM/PWA - Configurazione AppSettings per più clienti

Obiettivo

Gestire pubblicazioni diverse della stessa app Blazor WebAssembly/PWA per più clienti, evitando di modificare manualmente appsettings.json dopo la pubblicazione.

Questo è importante perché nelle app Blazor WASM/PWA i file pubblicati vengono inseriti nel manifest degli asset, ad esempio:

service-worker-assets.js

Se si modifica un file statico dopo la pubblicazione, come appsettings.json, gli hash possono non corrispondere più e la PWA può generare errori di integrità/cache.

La soluzione corretta è:

1. mantenere un appsettings.json comune
2. creare un file appsettings per ogni cliente
3. tenere i file cliente fuori da wwwroot
4. usare un profilo di pubblicazione per cliente
5. fare copiare al .csproj solo il file del cliente pubblicato


1. Struttura cartelle consigliata

Nel progetto Blazor WASM, ad esempio Soluziona.Apps.Magazzino, usare questa struttura:

Soluziona.Apps.Magazzino
├── SettingClienti
│   ├── Comside
│   │   └── appsettings.Comside.json
│   └── Demo
│       └── appsettings.Demo.json
│
├── Properties
│   └── PublishProfiles
│       ├── Comside.pubxml
│       └── Demo.pubxml
│
└── wwwroot
    ├── appsettings.json
    ├── appsettings.Development.json
    ├── index.html
    ├── manifest.webmanifest
    ├── service-worker.js
    └── ...

Regola

Dentro wwwroot devono rimanere solo:

appsettings.json
appsettings.Development.json

I file dei clienti devono stare fuori da wwwroot, dentro:

SettingClienti\<NomeCliente>\appsettings.<NomeCliente>.json

Esempio:

SettingClienti\Comside\appsettings.Comside.json
SettingClienti\Demo\appsettings.Demo.json


2. appsettings.json comune

Il file:

wwwroot/appsettings.json

deve contenere solo i valori comuni a tutti i clienti.

Esempio:

{
  "App": {
    "NomeApp": "Liste di Carico",
    "SottoTitoloApp": "Gestione preparazione ordini",
    "Versione": "1.0.6",
    "Build": "2026.09.09.006",
    "Ambiente": "Production",
    "PaginaIniziale": "/calendario"
  },
  "Api": {
    "TimeoutSecondi": 30
  },
  "Offline": {},
  "SyncListeDiCarico": {
    "IntervalloSecondi": 30,
    "GiorniIndietro": 15,
    "GiorniAvanti": 15,
    "EseguiAllAvvio": true
  }
}

Nota

In questo file può mancare:

"BaseUrl"

perché viene valorizzato dal file cliente, ad esempio:

appsettings.Comside.json


3. appsettings.Development.json

Il file:

wwwroot/appsettings.Development.json

viene usato per lo sviluppo locale.

Esempio:

{
  "App": {
    "IdApplicazione": "17630f17-7626-416f-961b-486fbd64fd4f",
    "CodiceApplicazione": "APPLISTEDICARICO",
    "CodiceAzienda": "3",
    "Ambiente": "Development"
  },
  "Api": {
    "BaseUrl": "https://localhost:7021/",
    "TimeoutSecondi": 30
  }
}


4. Settings per cliente

Demo

Percorso:

SettingClienti\Demo\appsettings.Demo.json

Contenuto:

{
  "App": {
    "IdApplicazione": "17630f17-7626-416f-961b-486fbd64fd4f",
    "CodiceApplicazione": "APPLISTEDICARICO",
    "CodiceAzienda": "3",
    "Ambiente": "Production"
  },
  "Api": {
    "BaseUrl": "https://soluzionacoreapi.soluziona.cloud:443/",
    "TimeoutSecondi": 30
  }
}

Comside

Percorso:

SettingClienti\Comside\appsettings.Comside.json

Contenuto:

{
  "App": {
    "IdApplicazione": "90208117-20b4-446c-a771-42bce3fb63c5",
    "CodiceApplicazione": "ListeDiCarico",
    "CodiceAzienda": "59",
    "Ambiente": "Production"
  },
  "Api": {
    "BaseUrl": "https://192.168.232.122:4433/",
    "TimeoutSecondi": 30
  }
}


5. Modifica del .csproj

Aprire il file .csproj del progetto Blazor WASM, ad esempio:

Soluziona.Apps.Magazzino.csproj

Aggiungere questo blocco prima di:

</Project>

<ItemGroup>
  <None Include="SettingClienti\**\*.json" />
</ItemGroup>

<ItemGroup Condition="'$(WasmApplicationEnvironmentName)' != '' 
                  and '$(WasmApplicationEnvironmentName)' != 'Development'
                  and Exists('SettingClienti\$(WasmApplicationEnvironmentName)\appsettings.$(WasmApplicationEnvironmentName).json')">

  <Content Include="SettingClienti\$(WasmApplicationEnvironmentName)\appsettings.$(WasmApplicationEnvironmentName).json"
           Link="wwwroot\appsettings.$(WasmApplicationEnvironmentName).json"
           CopyToOutputDirectory="PreserveNewest"
           CopyToPublishDirectory="PreserveNewest" />

</ItemGroup>

Cosa fa questo blocco

Quando si pubblica con ambiente:

Comside

il .csproj prende:

SettingClienti\Comside\appsettings.Comside.json

e lo pubblica come:

wwwroot\appsettings.Comside.json

Quando si pubblica con ambiente:

Demo

il .csproj prende:

SettingClienti\Demo\appsettings.Demo.json

e lo pubblica come:

wwwroot\appsettings.Demo.json


6. Profili di pubblicazione

I profili vanno creati da Visual Studio con:

Tasto destro sul progetto
→ Publish
→ New profile
→ Folder

Dopo la creazione, modificare i file .pubxml.


Profilo Demo

Percorso:

Properties\PublishProfiles\Demo.pubxml

Contenuto:

<?xml version="1.0" encoding="utf-8"?>
<Project>
  <PropertyGroup>
    <DeleteExistingFiles>true</DeleteExistingFiles>
    <ExcludeApp_Data>false</ExcludeApp_Data>
    <LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>

    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>

    <PublishProvider>FileSystem</PublishProvider>
    <PublishUrl>C:\Repos\Pubblicati\AppListeDiCarico\Demo</PublishUrl>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <_TargetId>Folder</_TargetId>

    <WasmApplicationEnvironmentName>Demo</WasmApplicationEnvironmentName>
  </PropertyGroup>
</Project>


Profilo Comside

Percorso:

Properties\PublishProfiles\Comside.pubxml

Contenuto:

<?xml version="1.0" encoding="utf-8"?>
<Project>
  <PropertyGroup>
    <DeleteExistingFiles>true</DeleteExistingFiles>
    <ExcludeApp_Data>false</ExcludeApp_Data>
    <LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>

    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>

    <PublishProvider>FileSystem</PublishProvider>
    <PublishUrl>C:\Repos\Pubblicati\AppListeDiCarico\Comside</PublishUrl>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <_TargetId>Folder</_TargetId>

    <WasmApplicationEnvironmentName>Comside</WasmApplicationEnvironmentName>
  </PropertyGroup>
</Project>


7. Proprietà fondamentale: WasmApplicationEnvironmentName

La riga più importante del profilo è questa:

<WasmApplicationEnvironmentName>Comside</WasmApplicationEnvironmentName>

oppure:

<WasmApplicationEnvironmentName>Demo</WasmApplicationEnvironmentName>

Questa proprietà decide quale file ambiente Blazor deve caricare.

Esempio:

WasmApplicationEnvironmentName = Comside
→ carica appsettings.json
→ carica appsettings.Comside.json

WasmApplicationEnvironmentName = Demo
→ carica appsettings.json
→ carica appsettings.Demo.json

Il valore deve combaciare esattamente con:

nome cartella cliente
nome file appsettings

Esempio corretto:

Comside
→ SettingClienti\Comside\appsettings.Comside.json

Esempio errato:

COMSIDE
→ SettingClienti\Comside\appsettings.Comside.json