View a markdown version of this page

Esecuzione di più applicazioni e applicazioni ASP.NET principali con un manifesto di distribuzione - AWS Elastic Beanstalk

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Esecuzione di più applicazioni e applicazioni ASP.NET principali con un manifesto di distribuzione

È possibile utilizzare un manifest di distribuzione per indicare a Elastic Beanstalk come distribuire l'applicazione. Utilizzando questo metodo, non è necessario generare un pacchetto di sorgenti per una singola ASP.NET applicazione che viene eseguita nel percorso principale del sito Web. MSDeploy Piuttosto, è possibile utilizzare un file manifest per eseguire più applicazioni in percorsi diversi. Oppure, in alternativa, puoi dire a Elastic Beanstalk di distribuire ed eseguire l'app con Core. ASP.NET È inoltre possibile utilizzare un manifest di distribuzione per configurare un pool di applicazioni in cui eseguire le applicazioni.

I manifest di distribuzione aggiungono il supporto per Applicazioni .NET Core su Elastic Beanstalk. È possibile distribuire un'applicazione .NET Framework senza un manifest di distribuzione. Tuttavia, le applicazioni .NET Core richiedono un manifest di distribuzione per essere eseguite su Elastic Beanstalk. Quando utilizzi un manifest di distribuzione, è necessario creare un archivio del sito per ogni applicazione e quindi raggruppare gli archivi del sito in un secondo archivio ZIP che contiene il manifest di distribuzione.

I manifest di distribuzione aggiungono anche la possibilità di eseguire più applicazioni in diversi percorsi. Un manifest di distribuzione definisce una gamma di obiettivi di distribuzione, ognuno con un archivio del sito e un percorso su cui IIS dovrebbe eseguirlo. Ad esempio, è possibile eseguire un'API Web nel percorso /api per servire richieste asincrone e un'app Web nel percorso root che utilizza l'API.

È possibile utilizzare un manifesto di distribuzione per configurare i siti Web IIS con collegamenti personalizzati e percorsi fisici. Ciò consente di configurare siti Web in ascolto su porte o nomi host specifici prima di distribuire le applicazioni.

È inoltre possibile utilizzare un manifest di distribuzione per eseguire più applicazioni utilizzando pool di applicazioni in IIS o Kestrel. È possibile configurare un pool di applicazioni per riavviare le proprie applicazioni periodicamente, eseguire applicazioni a 32 bit o utilizzare una versione specifica del runtime di .NET Framework.

Per una personalizzazione completa, puoi scrivere i tuoi script di distribuzione in Windows PowerShell e indicare a Elastic Beanstalk quali script eseguire per installare, disinstallare e riavviare l'applicazione.

I manifest di distribuzione e le relative caratteristiche richiedono una piattaforma Windows Server versione 1.2.0 o più recente.

Per informazioni dettagliate su tutte le opzioni di configurazione, le proprietà e le funzionalità avanzate disponibili, come saltare le reimpostazioni di IIS, consulta il riferimento allo schema del manifesto di distribuzione. Riferimento allo schema del manifesto di distribuzione

App .NET Core

È possibile utilizzare un manifest di implementazione per eseguire applicazioni .NET Core su Elastic Beanstalk. .NET Core è una versione multipiattaforma di .NET fornita con uno strumento a riga di comando (dotnet). È possibile utilizzarlo per generare un'applicazione, eseguirla in locale e prepararla per la pubblicazione.

Per eseguire un'applicazione .NET Core su Elastic Beanstalk, esegui dotnet publish e raggruppa l'output in un archivio ZIP senza includere le directory. Posiziona l'archivio del sito in un bundle di origine con un manifest di distribuzione con una destinazione di distribuzione di tipo aspNetCoreWeb.

Il seguente manifest di distribuzione esegue un'applicazione .NET Core da un archivio del sito denominato dotnet-core-app.zip al percorso root.

Esempio aws-windows-deployment-manifest.json - .NET core
{ "manifestVersion": 1, "deployments": { "aspNetCoreWeb": [ { "name": "my-dotnet-core-app", "parameters": { "archive": "dotnet-core-app.zip", "iisPath": "/" } } ] } }

Raggruppa il manifest e l'archivio del sito in un archivio ZIP per creare un bundle di origine.

Esempio dotnet-core-bundle.zip
. |-- aws-windows-deployment-manifest.json `-- dotnet-core-app.zip

L'archivio del sito contiene il codice compilato dell'applicazione, le dipendenze e il file web.config.

Esempio dotnet-core-app.zip
. |-- Microsoft.AspNetCore.Hosting.Abstractions.dll |-- Microsoft.AspNetCore.Hosting.Server.Abstractions.dll |-- Microsoft.AspNetCore.Hosting.dll |-- Microsoft.AspNetCore.Http.Abstractions.dll |-- Microsoft.AspNetCore.Http.Extensions.dll |-- Microsoft.AspNetCore.Http.Features.dll |-- Microsoft.AspNetCore.Http.dll |-- Microsoft.AspNetCore.HttpOverrides.dll |-- Microsoft.AspNetCore.Server.IISIntegration.dll |-- Microsoft.AspNetCore.Server.Kestrel.dll |-- Microsoft.AspNetCore.WebUtilities.dll |-- Microsoft.Extensions.Configuration.Abstractions.dll |-- Microsoft.Extensions.Configuration.EnvironmentVariables.dll |-- Microsoft.Extensions.Configuration.dll |-- Microsoft.Extensions.DependencyInjection.Abstractions.dll |-- Microsoft.Extensions.DependencyInjection.dll |-- Microsoft.Extensions.FileProviders.Abstractions.dll |-- Microsoft.Extensions.FileProviders.Physical.dll |-- Microsoft.Extensions.FileSystemGlobbing.dll |-- Microsoft.Extensions.Logging.Abstractions.dll |-- Microsoft.Extensions.Logging.dll |-- Microsoft.Extensions.ObjectPool.dll |-- Microsoft.Extensions.Options.dll |-- Microsoft.Extensions.PlatformAbstractions.dll |-- Microsoft.Extensions.Primitives.dll |-- Microsoft.Net.Http.Headers.dll |-- System.Diagnostics.Contracts.dll |-- System.Net.WebSockets.dll |-- System.Text.Encodings.Web.dll |-- dotnet-core-app.deps.json |-- dotnet-core-app.dll |-- dotnet-core-app.pdb |-- dotnet-core-app.runtimeconfig.json `-- web.config

Esecuzione di più applicazioni

È possibile eseguire più applicazioni con un manifest di distribuzione definendo più target di distribuzione.

Il seguente manifesto di distribuzione configura due applicazioni .NET Core. L'WebApiSampleAppapplicazione implementa una semplice API Web e fornisce richieste asincrone sul percorso. /api DotNetSampleApp è un'applicazione Web che fornisce richieste al percorso root.

Esempio aws-windows-deployment-manifest.json - molteplici app
{ "manifestVersion": 1, "deployments": { "aspNetCoreWeb": [ { "name": "WebAPISample", "parameters": { "appBundle": "WebApiSampleApp.zip", "iisPath": "/api" } }, { "name": "DotNetSample", "parameters": { "appBundle": "DotNetSampleApp.zip", "iisPath": "/" } } ] } }

Un'applicazione di esempio con più applicazioni è disponibile qui:

Configurare i siti Web IIS

È possibile configurare i siti Web IIS con collegamenti personalizzati e percorsi fisici utilizzando il manifesto di distribuzione. Ciò è utile quando è necessario configurare siti Web in ascolto su porte specifiche, utilizzare nomi host personalizzati o pubblicare contenuti da directory specifiche.

Il seguente manifesto di distribuzione configura un sito Web IIS personalizzato in ascolto su HTTP con un numero di porta specifico e un percorso fisico personalizzato:

Esempio aws-windows-deployment-manifest.json - Configurazione del sito Web IIS
{ "manifestVersion": 1, "iisConfig": { "websites": [ { "name": "MyCustomSite", "physicalPath": "C:\inetpub\wwwroot\mysite", "bindings": [ { "protocol": "http", "port": 8080, "hostName": "mysite.local" } ] } ] }, "deployments": { "aspNetCoreWeb": [ { "name": "my-dotnet-core-app", "parameters": { "appBundle": "dotnet-core-app.zip", "iisWebSite": "MyCustomSite", "iisPath": "/" } } ] } }

In questo esempio:

  • Un sito Web denominato "" viene creato con un percorso fisico personalizzato MyCustomSite

  • Il sito Web ha un'associazione HTTP sulla porta 8080 con un nome host specifico

  • L'applicazione ASP.NET Core viene distribuita su questo sito Web personalizzato utilizzando il parametro iisWebSite

Utilizzo dell'Application Request Routing (ARR)

I moduli Application Request Routing (ARR) e URL Rewrite sono preinstallati e disponibili nelle AMI Windows di Elastic Beanstalk. Questi moduli consentono scenari di routing avanzati e la manipolazione degli URL tramite la configurazione IIS utilizzando ebextensions o la configurazione dell'applicazione.

L'esempio seguente mostra un semplice manifesto di distribuzione che configura un sito Web con una porta personalizzata, combinato con una configurazione ebextensions che imposta il routing ARR di base:

Esempio aws-windows-deployment-manifest.json - Configurazione ARR semplice
{ "manifestVersion": 1, "iisConfig": { "websites": [ { "name": "ARRSite", "physicalPath": "C:\\inetpub\\wwwroot\\arrsite", "bindings": [ { "protocol": "http", "port": 8080, "hostName": "localhost" } ] } ] }, "deployments": { "aspNetCoreWeb": [ { "name": "BackendApp", "parameters": { "appBundle": "backend-app.zip", "iisWebSite": "ARRSite", "iisPath": "/backend" } } ] } }

La configurazione ARR viene eseguita tramite ebextensions. La seguente configurazione imposta le regole di routing ARR di base:

Esempio. ebextensions/arr-config.config - Configurazione ARR di base
files: "C:\\temp\\configure-arr.ps1": content: | # Enable ARR proxy at server level Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/proxy' -Name 'enabled' -Value 'True' # Clear any existing global rules to avoid conflicts Clear-WebConfiguration -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/rewrite/globalRules' # Add global rule to route all requests to backend Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' ` -Filter 'system.webServer/rewrite/globalRules' ` -Name '.' ` -Value @{ name = 'Route_to_Backend' stopProcessing = 'True' match = @{ url = '^(?!backend/)(.*)' } action = @{ type = 'Rewrite' url = 'http://localhost:8080/backend/{R:1}' } } container_commands: 01_configure_arr: command: powershell -ExecutionPolicy Bypass -File "C:\\temp\\configure-arr.ps1" waitAfterCompletion: 0

Questa configurazione crea un sito Web sulla porta 8080 e imposta ARR per indirizzare tutte le richieste in arrivo all'applicazione backend in esecuzione su quel sito.

Configurazione dei pool delle applicazioni

È possibile supportare più applicazioni nell'ambiente Windows. Sono disponibili due approcci:

  • È possibile utilizzare il modello di hosting out-of-process con il server Web Kestrel. Con questo modello, è possibile configurare più applicazioni per l'esecuzione in un unico pool di applicazioni.

  • È possibile utilizzare il modello di hosting in-process. Con questo modello, si utilizzano più pool di applicazioni per eseguire più applicazioni con una sola applicazione in ogni pool. Se utilizzi il server IIS e desideri eseguire più applicazioni, devi utilizzare questo approccio.

Per configurare Kestrel ed eseguire più applicazioni in un pool di applicazioni, aggiungi hostingModel="OutofProcess" nel file web.config. Considera i seguenti esempi:

Esempio web.config - per il modello di hosting out-of-process di Kestrel
<configuration> <location path="." inheritInChildApplications="false"> <system.webServer> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> </handlers> <aspNetCore processPath="dotnet" arguments=".\CoreWebApp-5-0.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="OutofProcess" /> </system.webServer> </location> </configuration>
Esempio aws-windows-deployment-manifest.json - più applicazioni
{ "manifestVersion": 1, "deployments": {"msDeploy": [ {"name": "Web-app1", "parameters": {"archive": "site1.zip", "iisPath": "/" } }, {"name": "Web-app2", "parameters": {"archive": "site2.zip", "iisPath": "/app2" } } ] } }

IIS non supporta più applicazioni in un pool di applicazioni perché utilizza il modello di hosting in-process. Pertanto, è necessario configurare più applicazioni assegnando ciascuna applicazione a un pool di applicazioni. In altre parole, assegnare una sola applicazione a un pool di applicazioni.

È possibile configurare IIS per utilizzare diversi pool di applicazioni nel file aws-windows-deployment-manifest.json. Apporta i seguenti aggiornamenti consultando il file di esempio successivo:

  • Aggiungi una sezione iisConfig che includa una sottosezione denominata appPools.

  • Nel blocco appPools, elenca i pool di applicazioni.

  • Nella sezione deployments, definisci una sezione parameters per ogni applicazione.

  • Per ogni applicazione, la sezione parameters specifica un archivio, un percorso per eseguirla e un appPool in cui eseguirla.

Il seguente manifest di distribuzione consente di configurare due pool di applicazioni che riavviano l'applicazione ogni 10 minuti. Essi inoltre allegano le loro applicazioni a un'applicazione Web .NET Framework che viene eseguita nel percorso specificato.

Esempio aws-windows-deployment-manifest.json - un'applicazione per pool di applicazioni
{ "manifestVersion": 1, "iisConfig": {"appPools": [ {"name": "MyFirstPool", "recycling": {"regularTimeInterval": 10} }, {"name": "MySecondPool", "recycling": {"regularTimeInterval": 10} } ] }, "deployments": {"msDeploy": [ {"name": "Web-app1", "parameters": { "archive": "site1.zip", "iisPath": "/", "appPool": "MyFirstPool" } }, {"name": "Web-app2", "parameters": { "archive": "site2.zip", "iisPath": "/app2", "appPool": "MySecondPool" } } ] } }

Definizione delle distribuzioni personalizzate

Per un maggiore controllo, è possibile personalizzare completamente la distribuzione di un'applicazione definendo una distribuzione personalizzata. Con una distribuzione personalizzata, Elastic Beanstalk esegue solo PowerShell gli script forniti dall'utente e non esegue alcuna gestione IIS per conto dell'utente. Ciò è diverso dalle aspNetCoreWeb distribuzioni, in cui Elastic Beanstalk arresta automaticamente IIS prima dell'installazione, lo avvia successivamente msDeploy e lo riavvia quando necessario. Per una distribuzione personalizzata, gli script inseriscono il contenuto dell'applicazione, configurano l'ambiente (ad esempio, IIS) e riavviano l'applicazione.

Importante

In un ambiente di server Web con bilanciamento del carico, Elastic Beanstalk verifica lo stato dell'istanza richiedendo il percorso di controllo dello stato dell'ambiente (per impostazione predefinita) sulla porta 80. / Qualcosa deve seguire questo percorso, altrimenti l'ambiente diventa malsano anche se ogni script di distribuzione ha esito positivo, una causa comune di una distribuzione personalizzata che viene completata senza errori ma lascia l'ambiente in uno stato inattivo. Per una distribuzione personalizzata autonoma, servite l'applicazione dalla radice del sito Web predefinito. È valido inserire un'applicazione personalizzata in un sottopercorso quando un'altra distribuzione serve già il percorso di controllo dello stato, ad esempio in un manifesto con più applicazioni. Esecuzione di più applicazioni Per ulteriori informazioni sullo stato dell'ambiente, vedere Monitoraggio degli ambienti. Ambienti di monitoraggio in Elastic Beanstalk

Una distribuzione personalizzata definisce fino a tre script. La tabella seguente descrive ogni script, quando Elastic Beanstalk lo esegue e cosa deve fare lo script.

Script Quando Elastic Beanstalk lo esegue Responsabilità
uninstall Prima dell'installazione di ogni nuova versione dell'applicazione, ovvero prima di ogni distribuzione dell'applicazione. Arrestare il servizio o rimuovere i file della versione precedente.
install Durante ogni distribuzione dell'applicazione. Distribuisci i file, configura IIS o il tuo servizio e servi l'applicazione nel percorso di controllo dello stato di salute.
restart Dopo ogni distribuzione dell'applicazione e dopo ogni modifica della configurazione. Se è impostato su skipIISResettrue, Elastic Beanstalk salta questo script sulle distribuzioni delle applicazioni ma lo esegue comunque in caso di modifiche alla configurazione. La scelta di Restart App Server viene eseguita a livello di piattaforma iisreset e non richiama lo script di riavvio personalizzato. Riavvia IIS (iisreset) o il tuo servizio in modo che la nuova versione sia attiva.

Questi script vengono eseguiti anche ogni volta che Elastic Beanstalk distribuisce l'applicazione su un'istanza appena avviata, ad esempio durante la creazione iniziale dell'ambiente e quando Auto Scaling aggiunge un'istanza (scale-out), perché ogni nuova istanza installa l'applicazione al momento del bootstrap.

Il seguente manifesto di distribuzione indica a Elastic Beanstalk di eseguire gli script in modalità a 32 bit. PowerShell Specifica uno script (), uno install script (install.ps1) e uno restart script (). restart.ps1 uninstall uninstall.ps1 Lo uninstall script è impostato true in ignoreErrors modo che la prima distribuzione, quando non c'è nulla da rimuovere, non abbia esito negativo.

Esempio aws-windows-deployment-manifest.json - distribuzione personalizzata
{ "manifestVersion": 1, "deployments": { "custom": [ { "name": "Custom site", "architecture": 32, "scripts": { "install": { "file": "install.ps1" }, "restart": { "file": "restart.ps1" }, "uninstall": { "file": "uninstall.ps1", "ignoreErrors": true } } } ] } }

Include eventuali artefatti necessari per eseguire l'applicazione nel bundle di origine con il manifest e gli script. Elastic Beanstalk non estrae questi artefatti per una distribuzione personalizzata: gli script devono estrarli. Nel seguente esempio, il contenuto dell'applicazione è impacchettato come. MyApp.zip

Esempio Custom-site-bundle.zip
. |-- aws-windows-deployment-manifest.json |-- install.ps1 |-- restart.ps1 |-- uninstall.ps1 `-- MyApp.zip

Gli script seguenti mostrano una distribuzione personalizzata completa e corretta per un'applicazione. IIS-hosted Lo install.ps1 script estrae il contenuto dell'applicazione e vi indirizza il percorso fisico del sito Web predefinito, in modo che l'applicazione venga servita dal percorso principale (/) in cui viene eseguito il controllo di integrità.

Esempio install.ps1
$ErrorActionPreference = "Stop" $appPath = "C:\inetpub\MyApp" if (Test-Path $appPath) { Remove-Item $appPath -Recurse -Force } # Elastic Beanstalk doesn't extract your bundle for custom deployments, so extract it yourself. # MyApp.zip ships in the bundle, alongside this script. Resolve it relative to the script's # own location so the path is reliable regardless of the current working directory. $scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { (Get-Location).Path } $bundleZip = Join-Path $scriptDir "MyApp.zip" Add-Type -AssemblyName "System.IO.Compression.FileSystem" [IO.Compression.ZipFile]::ExtractToDirectory($bundleZip, $appPath) # Serve from the Default Web Site root ("/"), where the health check looks. Import-Module WebAdministration Set-ItemProperty "IIS:\Sites\Default Web Site" -Name physicalPath -Value $appPath iisreset.exe /restart if ($LASTEXITCODE -ne 0) { exit 1 }
Esempio riavviare.ps1
$ErrorActionPreference = "Stop" iisreset.exe /restart if ($LASTEXITCODE -ne 0) { exit 1 }
Esempio disinstallare.ps1
# Stop IIS first. While the site is live, w3wp holds locks on files under the app directory, # which would make the following removal fail. iisreset.exe /stop | Out-Null Remove-Item "C:\inetpub\MyApp" -Recurse -Force -ErrorAction SilentlyContinue

Quando scrivi script di distribuzione personalizzati, tieni presente i seguenti punti:

  • Segui il percorso di controllo dello stato di salute. Indirizza il percorso fisico del sito Web predefinito all'applicazione o esegui l'implementazione in altro modo sul percorso di controllo dello stato, in modo che il controllo di integrità abbia esito positivo.

  • Includi un documento predefinito. Se la radice del sito non ha un documento predefinito, GET / restituisce HTTP 403 e il controllo dello stato ha esito negativo. Spedisci un web.config file che imposta un <defaultDocument> elemento o assegna un nome alla pagina di destinazione in modo che corrisponda a un nome di documento predefinito di IIS, ad esempio Default.htm oindex.htm.

  • Riavvia IIS tu stesso. Poiché Elastic Beanstalk non esegue alcuna gestione IIS per le distribuzioni personalizzate, gli script devono essere eseguiti iisreset affinché le modifiche abbiano effetto.

  • Individua i file raggruppati relativi allo script. Elastic Beanstalk estrae gli script e gli artefatti raggruppati nella stessa directory. Risolvi i file raggruppati utilizzando $PSScriptRoot (la cartella che contiene lo script in esecuzione) anziché assumere una particolare directory di lavoro corrente.

  • Fai in modo che gli errori falliscano la distribuzione. Imposta $ErrorActionPreference = "Stop" e controlla $LASTEXITCODE dopo i comandi esterni. In caso contrario, uno script danneggiato può uscire correttamente e Elastic Beanstalk considera la distribuzione come riuscita anche se l'applicazione non funziona correttamente.

Esempio: un servizio Windows ospitato autonomamente

Con una distribuzione personalizzata, è possibile eseguire un servizio Windows anziché un IIS-hosted sito. Le piattaforme Windows Elastic Beanstalk non supportano il livello dell'ambiente di lavoro. In un ambiente con bilanciamento del carico, il load balancer controlla il percorso di controllo dello stato sulla porta 80, quindi un servizio Windows deve rispondere a tale richiesta per mantenere l'ambiente intatto. L'esempio seguente è un servizio ospitato autonomamente che è in ascolto sulla porta 80 stessa, quindi non necessita di un sito IIS complementare.

Nota

Poiché le piattaforme Windows non hanno un livello di lavoro, un servizio in background deve comunque rispondere al controllo dello stato in un ambiente con bilanciamento del carico. Fai in modo che il servizio risponda anche al percorso di controllo dello stato (come mostrato qui) o esegua il lavoro in background insieme a un sito che lo fornisce.

Il manifest esegue gli script in modalità a 64 bit, corrispondente al compilatore C# a 64 bit utilizzato per creare il servizio.

Esempio aws-windows-deployment-manifest.json - Servizio Windows
{ "manifestVersion": 1, "deployments": { "custom": [ { "name": "EbCustomService", "architecture": 64, "scripts": { "install": { "file": "serviceInstall.ps1" }, "restart": { "file": "serviceRestart.ps1" }, "uninstall": { "file": "serviceUninstall.ps1", "ignoreErrors": true } } } ] } }

Il pacchetto include il manifest, i tre script, il codice sorgente del servizio e un version.txt file (il cui contenuto è ad esempio la stringa della versione). v1 Lo script di installazione compila il servizio sull'istanza, quindi non è necessaria una toolchain di compilazione nel pacchetto.

Esempio Custom-service-bundle.zip
. |-- aws-windows-deployment-manifest.json |-- EbCustomService.cs |-- serviceInstall.ps1 |-- serviceRestart.ps1 |-- serviceUninstall.ps1 `-- version.txt

Lo serviceInstall.ps1 script libera la porta 80 da IIS, compila il servizio dal sorgente fornito in dotazione con il compilatore C# integrato (csc.exe), lo registra come servizio e lo avvia. LocalSystem L'esecuzione come LocalSystem consente al servizio di associarsi http://+:80/ senza una prenotazione ACL URL, il che mantiene l'esempio minimo. In produzione, preferisci un account con privilegi minimi NetworkService e concedigli esplicitamente l'associazione con. netsh http add urlacl

Esempio servizio Install.ps1
# INSTALL: compile and register a self-hosted HTTP service that owns port 80. $ErrorActionPreference = "Stop" $svcName = "EbCustomService" $appPath = "C:\CustomService" $scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { (Get-Location).Path } # Free port 80 from IIS and keep it from reclaiming the port on reboot. Stop-Service W3SVC -Force -ErrorAction SilentlyContinue Set-Service W3SVC -StartupType Manual -ErrorAction SilentlyContinue # Fresh application directory. if (Test-Path $appPath) { Remove-Item $appPath -Recurse -Force } New-Item -ItemType Directory -Path $appPath | Out-Null # Compile the service with the in-box .NET Framework compiler (no build tooling needed). $csc = Join-Path $env:WINDIR "Microsoft.NET\Framework64\v4.0.30319\csc.exe" $src = Join-Path $scriptDir "EbCustomService.cs" $exe = Join-Path $appPath "EbCustomService.exe" & $csc /nologo /target:exe /out:"$exe" /reference:System.ServiceProcess.dll "$src" if ($LASTEXITCODE -ne 0) { exit 1 } # Write the content served at "/". A real service would serve its own responses; # here the install script writes a simple marker so the health check passes. $version = (Get-Content (Join-Path $scriptDir "version.txt") -Raw).Trim() Set-Content -Path (Join-Path $appPath "marker.txt") ` -Value "Custom service deployment $version succeeded" -NoNewline # Register as a LocalSystem service so it can bind http://+:80/ without a URL ACL. if (Get-Service $svcName -ErrorAction SilentlyContinue) { Stop-Service $svcName -Force -ErrorAction SilentlyContinue sc.exe delete $svcName | Out-Null # sc.exe delete is async; poll until gone so New-Service below doesn't hit # "service marked for deletion". $deadline = (Get-Date).AddSeconds(30) while ((Get-Service $svcName -ErrorAction SilentlyContinue) -and (Get-Date) -lt $deadline) { Start-Sleep -Milliseconds 500 } } New-Service -Name $svcName -BinaryPathName "`"$exe`"" ` -DisplayName "EB Custom Service" -StartupType Automatic | Out-Null Start-Service $svcName

Lo serviceRestart.ps1 script riavvia il servizio in modo che la nuova versione diventi attiva.

Esempio servizio Restart.ps1
# RESTART: restart the service so the new version becomes live. $ErrorActionPreference = "Stop" $svcName = "EbCustomService" Restart-Service $svcName -Force

Lo serviceUninstall.ps1 script interrompe ed elimina il servizio e rimuove i file della versione precedente. Il manifest è ignoreErrors impostato su true questo script perché nella prima distribuzione non è presente alcuna versione precedente da rimuovere.

Esempio servizio Uninstall.ps1
# UNINSTALL: stop and remove the previous version before the new install. # The manifest sets ignoreErrors:true because the first deploy has nothing to remove. $ErrorActionPreference = "Stop" $svcName = "EbCustomService" $appPath = "C:\CustomService" if (Get-Service $svcName -ErrorAction SilentlyContinue) { Stop-Service $svcName -Force -ErrorAction SilentlyContinue sc.exe delete $svcName | Out-Null # sc.exe delete is async; poll until the service is really gone so the next # deploy's New-Service doesn't hit "service marked for deletion". $deadline = (Get-Date).AddSeconds(30) while ((Get-Service $svcName -ErrorAction SilentlyContinue) -and (Get-Date) -lt $deadline) { Start-Sleep -Milliseconds 500 } } if (Test-Path $appPath) { Remove-Item $appPath -Recurse -Force -ErrorAction SilentlyContinue }

Il servizio stesso è un piccolo programma in C# che ospita un HttpListener on http://+:80/ e restituisce una risposta testualeGET /, che è ciò che soddisfa il controllo dello stato del load balancer.

Esempio EbCustomService.cs
// Minimal self-hosted HTTP Windows service. Hosts an HttpListener on http://+:80/ // and answers the load balancer's GET "/" health check with the content that the // install script wrote to marker.txt. using System; using System.IO; using System.Net; using System.ServiceProcess; using System.Text; using System.Threading; namespace EbCustomService { public class MarkerService : ServiceBase { private const string Root = @"C:\CustomService"; private HttpListener _listener; private Thread _worker; private volatile bool _running; public MarkerService() { this.ServiceName = "EbCustomService"; } protected override void OnStart(string[] args) { _running = true; _listener = new HttpListener(); _listener.Prefixes.Add("http://+:80/"); _listener.Start(); _worker = new Thread(Loop) { IsBackground = true }; _worker.Start(); } protected override void OnStop() { _running = false; try { if (_listener != null) _listener.Stop(); } catch { } } private void Loop() { while (_running) { HttpListenerContext ctx; try { ctx = _listener.GetContext(); } catch { break; } try { byte[] buf = Encoding.UTF8.GetBytes(ReadFile(Path.Combine(Root, "marker.txt"))); ctx.Response.StatusCode = 200; ctx.Response.ContentType = "text/plain"; ctx.Response.ContentLength64 = buf.Length; ctx.Response.OutputStream.Write(buf, 0, buf.Length); ctx.Response.OutputStream.Close(); } catch { } } } private static string ReadFile(string p) { try { return File.Exists(p) ? File.ReadAllText(p) : ""; } catch { return ""; } } public static void Main() { ServiceBase.Run(new MarkerService()); } } }
Nota

In questo esempio, la risposta fornita / è un piccolo indicatore di testo (marker.txt) che rappresenta il contenuto reale dell'applicazione. Un servizio di produzione fornirebbe invece le proprie risposte. Tutto il resto di questi script è il minimo richiesto per una distribuzione personalizzata funzionante di un servizio Windows.