[UWP] Concetti importanti delle AppService
Un’app service è quel meccanismo di UWP che permette ad un’app di invocarne un’altra, di potergli passare determinati valori, per ottenere un risultato di qualche tipo. C’è quindi un legame tra “app client” ed “app service”, anche se tecnicamente si tratta di due app UWP che risiedono sullo stesso PC. Per poter dialogare, l’app client deve conoscere un po’ di informazioni:
- L’AppServiceName
- Il PackageFamilyName
- Di quali informazioni l’AppService necessita per poter svolgere il suo lavoro. Tra app client ed app service viaggia un’istanza di ValueSet, che può essere tranquillamente visto come un Dictionary<string, object>.
L’AppService deve essere implementato tramite un BackgroundTask, il quale però non ha bisogno di essere registrato come accadrebbe con un BackgroundTask tradizionale. Quindi, per riassumere:
- Abbiamo un’app UWP contenuta in una solution (l’AppService deve comunque sia essere hostato all’interno di un’app UWP tradizionale)
- All’interno di questa solution aggiungiamo un progetto di tipo “Windows Runtime Component”
- All’interno di questo progetto aggiungiamo una classe che implementa l’interfaccia IBackgroundTask, esattamente come un normalissimo BackgroundTask
Nel metodo Run previsto dall’interfaccia IBackgroundTask dobbiamo fare quanto segue:
- Dall’istanza IBackgroundTaskInstance che arriva in ingresso al metodo, dobbiamo sfruttare la proprietà TriggerDetails e farne il casting verso AppServiceTriggerDetails
- Sottoscriviamo l’evento RequestReceveid esposto dall’oggetto AppServiceConnection (ovvero, vedere la proprietà AppServiceConnection)
- All’interno dell’evento RequestReceveid, dobbiamo prelevare i valori che il client ci ha eventualmente passato. Questa cosa la si ottiene con:
var message = args.Request.Message;
int number = (int)message[“param1”];
string strValue = message[“param2”].ToString(); - All’interno dell’evento RequestReceveid, prima o poi dovremo restituire qualcosa al client. Questo si ottiene con la seguente riga:
ValueSet returnValue = new ValueSet();
returnValue["ReturnValue"] = result;
await args.Request.SendResponseAsync(returnValue);
Come si vede, “returnValue” è un’istanza di ValueSet al cui interno abbiamo inserito una o più chiavi con il corrispondente valore.
Questo delegate verrà invocato quando l’app client invocherà l’AppService. A proposito di client, come si attiva il dialogo tra client ed il nostro AppService? Il legame è molto loose coupled.
service = new AppServiceConnection();
service.AppServiceName = "randomNumberService";
service.PackageFamilyName = "bcbc4d41-504f-4d99-8a93-43f5b9d4c404_xe5ny6wrzrhn8";
var status = await this.service.OpenAsync();
if (status != AppServiceConnectionStatus.Success)
{
return;
}
La proprietà AppServiceName deve coincidere con quanto stabilito nel file di manifest dell’app UWP che hosta l’AppService. Idem per il PackageFamilyName. La chiamata al metodo OpenAsync() della classe AppServiceConnection ci restituisce un valore tratto dall’enum AppServiceConnectionStatus. Se qualcosa è andato storto, allora interrompiamo immediatamente l’esecuzione.
Altrimenti:
var message = new ValueSet();
message.Add("Operation", "Random");
message.Add("NumberA", 1);
message.Add("NumberB", 100);
AppServiceResponse response = await this.service.SendMessageAsync(message);
if (response.Status == AppServiceResponseStatus.Success)
{
int result = (int)response.Message["ReturnValue"];
}
Nel frammento di codice qui sopra, preparo un oggetto ValueSet, con alcune coppie di chiave/valore, ed invoco l’AppService. Notare che la chiamata a SendMessageAsync passa all’AppService il nostro ValueSet. Otteniamo un valore di risposta; se è Success possiamo prelevare il valore di ritorno.
Notare che all’interno di ValueSet possiamo inserire oggetti serializzabili: numeri, stringhe ma anche ovviamente classi complesse.
L’AppService va dichiarato nella sezione “Declarations” del file di manifest dell’app UWP che hosta il servizio. E’ necessario quantomeno specificare il Name e l’entrypoint. Quest’ultimo, come accade con i BackgroundTask tradizionali, deve contenere il nome della classe (compreso di namespace) che implementa l’AppService stesso. Ricordo ancora una volta che questo BackgroundTask non va registrato come accadrebbe con un BackgroundTask tradizionale.