Dublin: Windows Application Server
di Roberto Brunetti
Questo articolo vuole essere una introduzione sulla prima CTP di Dublin ovvero Windows Application Server, almeno per adesso: il nome in codice Dublin fa riferimento anche ad altri meandri della tecnologia. In questa introduzione vediamo all'opera la parte del Windows Application Server.
E' costruito sopra il .NET Framework 4.0 e integra IIS e SQL Server per fornire una piattaforma per la gestione, la configurazione, lo sviluppo e il deploymnet di soluzioni WF/WCF (4.0 appunto).
Si compone di estensioni per integrare Visual Studio (2010) nel processo di deployment di una soluzione WF/WCF verso l'application server e una serie di strumenti per gestire, localmente o remotamente, la configurazione dell'applicazione ospitata sull'application server.
Attualmente è necessario creare il proprio ambiente di host, sia esso un servizio windows, un Windows Activated Service (WAS) o una applicazione ASP.NET, a mano, ricorrendo a file di configurazione .config, installazione di componenti, configurazione dei binding rispetto alle porte IIS e così via. Il Windows Application Server consente di gestire tutte queste componenti tramite una interfaccia di amministrazione che consente di esportare e importare applicazioni, vedere le istanze in esecuzione, tracciare i dati di tracking di un workflow, analizzare e terminare le istanze fallite.
Iniziamo a capire meglio il tutto partendo da uno screenshot (cliccare sulle immagine per visualizzarle a dimensione originale):
Siamo sul Default Web Site di IIS Manager (su un Windows Server 2008). Come si nota nella parte in basso delle Features View, l'installazione del Windows Application Server ha aggiunto dei moduli per
1) Esportazione e importazione di applicazioni: come vedremo più avanti è possibile esportare una applicazione, ad esempio dall'ambiente di test e importarla, completa di configurazione, nell'ambiente di produzione
2) Database Configuration: consente di gestire le connessioni verso i database di persistenza, tracking e monitoraggio.
3) Diagnostics: consente di configurare il livello di tracing degli errori e message logging rispetto al tipo di errore nell'applicazione e ai messaggi in ingresso
4) Persisted Instances: visualizza le istanza di workflow persistite nei vari database configurati
5) Tracking Configuration e Profile: consentono di gestire profili di tracking per i worflow in esecuzione (come i Tracking Profile di Workflow 3.0) e associarli al database che dovra accogliere queste informazioni.
Procediamo per gradi, questa la maschera di configurazione dei DB:

Come si nota, la mia configurazione prevede un database ProcessServerDB come store di default per le istanze persistite di workflow e un database ProductionStore (che in realtà si appoggia sempre allo stesso database fisico) dove appoggiare le istanze dei workflow persistiti. Sempre nello stesso database fisico vengono appoggiati i dati di monitoring (per il tracking delle istanze di workflow) denominato DefaultMonitoringStore. Nel database fisico troveremo quindi le tabelle adibite al monitoring, tabelle con il prefisso defaultStore per tenere le istanze persistite.
Come è facile intuire i servizi in esecuzione si baseranno sul nome indicato nella colonna Persistence e i dati ad essi associati verranno memorizzati nei (nel caso indicato nell'unico) database fisici configurati.
Accedendo al modulo Services, si accede alla seguente maschera che consente di visualizzare i servizi installati, di cui vengono riepilogati il nome, il path rispetto alla Virtual directory IIS, il nome del site che ospita la virtual directory, e l'application pool in cui gira il servizio.
Nel mio caso, ho aperto la maschera dei services, sulla virtual directory ProductionPizzaOrderService e quindi ottengo la lista dei servizi presenti in questa virtual directory.
Aprendo il maschera dal default web site ottengo ovviamente la visualizzazione di tutti i servizi ospitati sul site di default:
Su ogni servizio è possibile visualizzare gli endpoint disponibili. Ecco un esempio della maschera che riepiloga i binding di tutti i servizi.
E' possibile visualizzare le istanze dei workflow in esecuzione, dei workflow andati in errore, dei workflow bloccati, dei workflow sospesi, dei workflow Ready-to-run: nella versione attuale di workflow foundation è possibile accedere ai valori numerici solo dal performance monitor, che non fornisce però i dettagli rispetto ai counter. Con il Windows Application Server, oltre ai counter riepilogativi che si vedono nella seguente immagine

è possibile cliccare sui vari contatori per capire a cosa si riferiscono i numeri. Ad esempio cliccando su Instances Running (2 sono le istanze riportate anche come suspended) si accede al dettaglio di ogni istanza:
Come si nota appare il dettaglio che indica che ci sono due istanze del PizzaOrderService, ospitate dal Default Web Site, sulla virtual directory Production... che stanno girando.
Su ogni istanza è possibile, tramite il tasto destro, sospendere l'instanza, terminarla, abortirla o visualizzare i dati di tracking, ovvero l'elenco dei passi (in base al profilo di tracking scelto) che sono stati eseguiti.
Ad esempio, se sul servizio PizzaOrderService (nella maschera che abbiamo visto prima riguardante i Services) si sceglie Configure Tracking, è possibile abilitare la configurazione di tracking più appropriata: ogni configurazione comprende il riferimento allo store di monitoring (indicando il nome logico come abbiamo visto nello screenshot relativo) e il profilo di tracking (esiste anche nella versione 3.0 il concetto di Tracking Profile) da utilizzare. Il profilo indica quali attività e quali eventi tracciare su ognuna di esse e può essere completamente personalizzato come vedremo più avanti.
Una volta impostata la configurazione di tracking su un certo servizio è possibile, dalla mascherina precedente visualizzare i dati di tracking per ogni istanza: tramite il filtro in alto è possibile scegliere lo stato fra Running, Suspended, Blocked, Ready To Run.
Ecco il risultato:
Come si può notare per l'instanza selezionata si vedono gli eventi che indicano lo stato (AEC) di ogni activity e il "momento" in cui si sono scatenati.
Attualmente esiste nell'SDK di Workflow 3.x un editor di Tracking Profile, prodotto efficace ma abbastanza rudimentale. Nella prossima versione il Tracking Profile Editor si presenta così (almeno in questa primissima CTP di ottobre 2008):
Il TPE consente di vedere il workflow e indicare quali sono gli eventi da tracciare (la mia freccia rossa indica da dove eseguire questa impostazione) e volendo le variabili (è una novità di workflow 4.0 poter definire variabili a livello di composite activity) da inserire nei dati di tracking.
Come dicevano all'inizio è possibile esportare e importare una applicazione da un server all'altro portandosi dietro la configurazione.
Questa la maschera di esportazione:
In pratica si sceglie il servizio da esportare e si indica il nome di un file .zip da creare. Il contenuto dello zip è il seguente:

Il file applicationManifest.xml contiene le informazioni sull'applicazione, sull'application pool (e relativa configurazione) che la ospita, la virtual directory e il path fisico, oltre ad una serie di informazioni sulle modifiche, il tipo di accesso, i protocolli abilitati e la descrizione di tutti i file (dll, proj, etc) che compongono l'applicazione. Ecco il contenuto facilmente intuibile anche se lunghetto :-). Ho evidenziato i punti salienti.
- <Application xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Id>85c8dc43-1161-4188-8324-de5a831f1431</Id>
<LpsVersion>3.0.1341.0</LpsVersion>
- <Modules>
- <Module>
- <ApplicationPool>
<CpuAffinityEnabled>false</CpuAffinityEnabled>
<CpuAffinityMask>4294967295</CpuAffinityMask>
<CpuLimit>0</CpuLimit>
<CpuLimitAction>NoAction</CpuLimitAction>
<CpuLimitInterval>PT5M</CpuLimitInterval>
<FrameworkVersion>v4.0</FrameworkVersion>
<IdentityType>SpecificUser</IdentityType>
<IdleTimeout>PT20M</IdleTimeout>
<ManagedPipelineMode>Integrated</ManagedPipelineMode>
<MaxWorkerProcesses>1</MaxWorkerProcesses>
<Name>User Services Application Pool</Name>
<OverlappedRecycleDisabled>false</OverlappedRecycleDisabled>
<PingEnabled>true</PingEnabled>
<PingMaxResponseTime>PT1M30S</PingMaxResponseTime>
<PingPeriod>PT30S</PingPeriod>
<ProcessOrphaningEnabled>false</ProcessOrphaningEnabled>
<ProcessOrphaningExecutable />
<ProcessOrphaningExecutableParameters />
<QueueLength>1000</QueueLength>
<RapidFailProtectionEnabled>true</RapidFailProtectionEnabled>
<RapidFailProtectionFailureInterval>PT5M</RapidFailProtectionFailureInterval>
<RapidFailProtectionMaxFailures>5</RapidFailProtectionMaxFailures>
<RapidFailProtectionResponseType>HttpLevel</RapidFailProtectionResponseType>
<RapidFailProtectionShutdownExecutable />
<RapidFailProtectionShutdownExecutableParameters />
<RecyclingEventLogs>Time, Memory, PrivateMemory</RecyclingEventLogs>
<RecyclingForConfigurationChangesDisabled>false</RecyclingForConfigurationChangesDisabled>
<RecyclingPrivateMemoryLimit>0</RecyclingPrivateMemoryLimit>
<RecyclingRegularTimeInterval>P1DT5H</RecyclingRegularTimeInterval>
<RecyclingRequestLimit>0</RecyclingRequestLimit>
<RecyclingSpecificTimes xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<RecyclingVirtualMemoryLimit>0</RecyclingVirtualMemoryLimit>
<ShutdownTimeLimit>PT1M30S</ShutdownTimeLimit>
<StartAutomatically>true</StartAutomatically>
<StartupTimeLimit>PT1M30S</StartupTimeLimit>
<UserName>Administrator</UserName>
</ApplicationPool>
<Id>6ca9913a-a35a-49a8-8420-2d6d069541be</Id>
<IisVersion>7.0</IisVersion>
<MachineName>ROBDUBLIN</MachineName>
<Name>/PizzaOrderService</Name>
<Technology>WAS</Technology>
<TimeStamp>2008-11-04T13:26:38.8691696-08:00</TimeStamp>
- <VirtualApplication>
<AccessPolicy>513</AccessPolicy>
<AnonymousAccess>true</AnonymousAccess>
<ApplicationPoolName>User Services Application Pool</ApplicationPoolName>
<DirectoryBrowsing>true</DirectoryBrowsing>
<EnabledProtocols>http</EnabledProtocols>
<LogVisits>true</LogVisits>
- <VirtualDirectories>
- <VirtualDirectory>
<Attributes>Normal</Attributes>
- <Directories>
- <Directory>
<Attributes>Normal</Attributes>
<Directories />
<Files />
<FullPath>C:\HandsOnLabs\Lab6\PizzaOrderingApplication\PizzaOrderService\App_Data</FullPath>
<Name>App_Data</Name>
</Directory>
- <Directory>
<Attributes>Normal</Attributes>
<Directories />
- <Files>
- <File>
<Attributes>Archive</Attributes>
<CreationTime>2008-09-23T12:56:08-07:00</CreationTime>
<LastAccessTime>2008-09-23T12:56:08-07:00</LastAccessTime>
<LastWriteTime>2008-09-23T12:56:08-07:00</LastWriteTime>
<Name>PizzaOrderingService.dll</Name>
<PackageKey>PizzaOrderService\bin\PizzaOrderingService.dll</PackageKey>
</File>
- <File>
<Attributes>Archive</Attributes>
<CreationTime>2008-09-23T12:56:08-07:00</CreationTime>
<LastAccessTime>2008-09-23T12:56:08-07:00</LastAccessTime>
<LastWriteTime>2008-09-23T12:56:08-07:00</LastWriteTime>
<Name>PizzaOrderingService.pdb</Name>
<PackageKey>PizzaOrderService\bin\PizzaOrderingService.pdb</PackageKey>
</File>
</Files>
<FullPath>C:\HandsOnLabs\Lab6\PizzaOrderingApplication\PizzaOrderService\bin</FullPath>
<Name>bin</Name>
</Directory>
- <Directory>
<Attributes>Normal</Attributes>
- <Directories>
- <Directory>
<Attributes>Normal</Attributes>
- <Directories>
- <Directory>
<Attributes>Normal</Attributes>
<Directories />
<Files />
<FullPath>C:\HandsOnLabs\Lab6\PizzaOrderingApplication\PizzaOrderService\obj\Debug\TempPE</FullPath>
<Name>TempPE</Name>
</Directory>
</Directories>
- <Files>
- <File>
<Attributes>Archive</Attributes>
<CreationTime>2008-09-23T12:56:10-07:00</CreationTime>
<LastAccessTime>2008-09-23T12:56:10-07:00</LastAccessTime>
<LastWriteTime>2008-09-23T12:56:10-07:00</LastWriteTime>
<Name>PizzaOrderingService.dll</Name>
<PackageKey>PizzaOrderService\obj\Debug\PizzaOrderingService.dll</PackageKey>
</File>
- <File>
<Attributes>Archive</Attributes>
<CreationTime>2008-09-23T12:56:10-07:00</CreationTime>
<LastAccessTime>2008-09-23T12:56:10-07:00</LastAccessTime>
<LastWriteTime>2008-09-23T12:56:10-07:00</LastWriteTime>
<Name>PizzaOrderingService.pdb</Name>
<PackageKey>PizzaOrderService\obj\Debug\PizzaOrderingService.pdb</PackageKey>
</File>
- <File>
<Attributes>Archive</Attributes>
<CreationTime>2008-09-23T12:56:10-07:00</CreationTime>
<LastAccessTime>2008-09-23T12:56:10-07:00</LastAccessTime>
<LastWriteTime>2008-09-23T12:56:10-07:00</LastWriteTime>
<Name>PizzaOrderService.csproj.FileListAbsolute.txt</Name>
<PackageKey>PizzaOrderService\obj\Debug\PizzaOrderService.csproj.FileListAbsolute.txt</PackageKey>
</File>
</Files>
<FullPath>C:\HandsOnLabs\Lab6\PizzaOrderingApplication\PizzaOrderService\obj\Debug</FullPath>
<Name>Debug</Name>
</Directory>
</Directories>
<Files />
<FullPath>C:\HandsOnLabs\Lab6\PizzaOrderingApplication\PizzaOrderService\obj</FullPath>
<Name>obj</Name>
</Directory>
- <Directory>
<Attributes>Normal</Attributes>
<Directories />
- <Files>
- <File>
<Attributes>Normal</Attributes>
<CreationTime>2008-09-02T19:50:26-07:00</CreationTime>
<LastAccessTime>2008-09-02T19:50:26-07:00</LastAccessTime>
<LastWriteTime>2008-09-02T19:50:26-07:00</LastWriteTime>
<Name>AssemblyInfo.cs</Name>
<PackageKey>PizzaOrderService\Properties\AssemblyInfo.cs</PackageKey>
</File>
</Files>
<FullPath>C:\HandsOnLabs\Lab6\PizzaOrderingApplication\PizzaOrderService\Properties</FullPath>
<Name>Properties</Name>
</Directory>
</Directories>
- <Files>
- <File>
<Attributes>Normal</Attributes>
<CreationTime>2008-09-02T19:50:26-07:00</CreationTime>
<LastAccessTime>2008-09-02T19:50:26-07:00</LastAccessTime>
<LastWriteTime>2008-09-02T19:50:26-07:00</LastWriteTime>
<Name>DataContracts.cs</Name>
<PackageKey>PizzaOrderService\DataContracts.cs</PackageKey>
</File>
- <File>
<Attributes>Normal</Attributes>
<CreationTime>2008-09-09T15:33:48-07:00</CreationTime>
<LastAccessTime>2008-09-09T15:33:48-07:00</LastAccessTime>
<LastWriteTime>2008-09-09T15:33:48-07:00</LastWriteTime>
<Name>PizzaOrderService.csproj</Name>
<PackageKey>PizzaOrderService\PizzaOrderService.csproj</PackageKey>
</File>
- <File>
<Attributes>Normal</Attributes>
<CreationTime>2008-09-16T19:17:18-07:00</CreationTime>
<LastAccessTime>2008-09-16T19:17:18-07:00</LastAccessTime>
<LastWriteTime>2008-09-16T19:17:18-07:00</LastWriteTime>
<Name>PizzaOrderService.csproj.user</Name>
<PackageKey>PizzaOrderService\PizzaOrderService.csproj.user</PackageKey>
</File>
- <File>
<Attributes>Normal</Attributes>
<CreationTime>2008-09-16T19:17:18-07:00</CreationTime>
<LastAccessTime>2008-09-16T19:17:18-07:00</LastAccessTime>
<LastWriteTime>2008-09-16T19:17:18-07:00</LastWriteTime>
<Name>PizzaOrderService.suo</Name>
<PackageKey>PizzaOrderService\PizzaOrderService.suo</PackageKey>
</File>
- <File>
<Attributes>Normal</Attributes>
<CreationTime>2008-09-16T19:17:18-07:00</CreationTime>
<LastAccessTime>2008-09-16T19:17:18-07:00</LastAccessTime>
<LastWriteTime>2008-09-16T19:17:18-07:00</LastWriteTime>
<Name>PizzaOrderService.xamlx</Name>
<PackageKey>PizzaOrderService\PizzaOrderService.xamlx</PackageKey>
</File>
- <File>
<Attributes>Archive</Attributes>
<CreationTime>2008-09-23T12:43:42-07:00</CreationTime>
<LastAccessTime>2008-11-04T13:21:57.6702032-08:00</LastAccessTime>
<LastWriteTime>2008-11-04T13:21:57.674216-08:00</LastWriteTime>
<Name>Web.config</Name>
<PackageKey>PizzaOrderService\Web.config</PackageKey>
</File>
</Files>
<FullPath>C:\HandsOnLabs\Lab6\PizzaOrderingApplication\PizzaOrderService</FullPath>
<Name>PizzaOrderService</Name>
<AuthenticationMethod>ClearText</AuthenticationMethod>
<Username />
<VirtualPath>/</VirtualPath>
</VirtualDirectory>
</VirtualDirectories>
<VirtualPath>/PizzaOrderService</VirtualPath>
<WindowsAuthentication>false</WindowsAuthentication>
</VirtualApplication>
- <Website>
<Name>Default Web Site</Name>
</Website>
</Module>
</Modules>
<Name>Default</Name>
</Application>
Oltre questo file viene preparata anche la sottodirectory archiveDir che contiene gli effettivi file che costituiscono l'applicazione.
E' possibile poi importare nuovamente l'applicazione (modificandone alcuni dati per adattarli al server su cui si effettua l'import)
Visto che il server di import sarà probabilmente diverso dal server da cui si è esportata l'applicazione è possibile modificare il nome dell'applicazione, l'application pool che la ospita e il path fisico in cui scompattare il file zip e su cui punterò la virtual directory.
In un prossimo articolo vedremo un altro strumento di configurazione, a livello di macchina e i servizi che l'application server espone: XAML Activation, Durable Timer Service, Forwarding Service e andremo più nel dettaglio delle configurazioni.
Roberto Brunetti