Encapsuler un appel de web service avec les Tasks
Dans le précédent article, je vous montrais comment prototyper un service pour qu’il puisse être consommer de façon asynchrone de façon “moderne”.
Seulement il se peut que votre service encapsule l’appel à un service WCF ou à un service Web “classique”.
Prenons un exemple de WebService tout simple :
[ServiceContract] public interface IService1 { [OperationContract] string GetLastClientName(string countryName); } public class Service1 : IService1 { public string GetLastClientName(string countryName) { if (countryName == "FR") return "Richard Clark"; return null; } }
Je sais, ce n’est pas le service du siècle.
Maintenant, dans le code de l’application cliente, ajouter une référence de service en vérifiant bien que Visual Studio génère les méthodes asynchrones :
Visual Studio génère donc les méthodes BeginGetLastClientName et EndGetLastClientName (il génère également GetLastClientNameAsync, mais ici, l’approche est évènementielle).
Personnellement, j’ai toujours eu du mal avec ce pattern, je ne l’ai jamais trouvé “friendly”.
Heureusement, Task permet d’encapsuler tout cela très facilement.
On va donc créer une classe service qui sera un wrapper du service web. Et l’on va lui ajouter une méthode GetLastClientNameAsync qui retournera une Task<string> :
public class MyService { private readonly Service1Client _client = new Service1Client(); public Task<string> GetLastClientNameAsync(string country) { return Task<string>.Factory.FromAsync( _client.BeginGetLastClientName, _client.EndGetLastClientName, country, null); } }
Et voilà, c’est tout. On peut maintenant utiliser notre web service de façon très simple et de façon asynchrone :
var service = new MyService(); service.GetLastClientNameAsync("FR") .ContinueWith(t => { if (t.IsFaulted) { Console.WriteLine(t.Exception.InnerException.Message); return; } Console.WriteLine(t.Result); }, TaskScheduler.FromCurrentSynchronizationContext());
Cool non ?