Calling a WCF Web Service Method
Register Application with Software Potential
Calls to the Software Potential web services must be authenticated via OAuth Client Credentials Flow. You must first register your application as a client with Software Potential as detailed in the document Register client Application With Software Potential.
Add a Web Service reference
In the Visual Studio project select Add -> Service Reference and enter the following endpoint address "https://srv.softwarepotential.com/SLMServerWS/LicenseManagementWS.svc".
Create Client
Create a LicenseManagementApi class to wrap the LicenseManagementWS client (see the LicenseManagementApi section below for more details).
Pass the application's ClientId and ClientSecret, together with the required Scope(s) as registered with Software Potential.
var serviceCredentials = GetServiceCredentials(); //Read credentials from configuration setting
var api = LicenseManagementApiFactory.Create(serviceCredentials.Username,
serviceCredentials.ClientId,
serviceCredentials.ClientSecret,
serviceCredentials.Scope );
Call a Method
Execute the call to the web service method via a lambda in LicenseManagementApi.Execute(). For example, to retrieve the available products named "Console Application" in Software Potential:
static Product[] GetProducts(LicenseManagementApi api) { try { return api.Execute(client => { return client.GetProducts().Where(p => p.Name.Contains("Console Application")).ToArray(); }); } catch (Exception ex) // NB: Execute already handles error messages, but throws the exception on { Console.WriteLine(ex.StackTrace); return null; } }
It is also possible to wrap multiple web service method calls in a single call to LicenseManagementApi. For example to issue a license based on a SKU:
static License IssueLicenseBySku(LicenseManagementApi api, string skuId) { try { return api.Execute(client => { var sku = client.GetSkuById(skuId); return client.IssueLicense(sku.LicenseInfo); }); } catch (Exception ex) // NB: Execute already handles error messages, but throws the exception on { Console.WriteLine(ex.StackTrace); return null; } }
LicenseManagementApi Class
It is recommend that developers use the LicenseManagementApi class to wrap, and execute methods on, the web service client proxy. This class correctly handles communications exceptions that can fault the client proxy and prevent creation of a new proxy client.
// Allows correct execution of multiple API calls handling exceptions // (when LicenseManagementWSClient is faulted a fresh client needs to be generated) // Also provides a single place in the code to load the credentials from e.g. a config file static class LicenseManagementApiFactory { public static LicenseManagementApi Create() { var credentials = GetCredentials(); //Read credentials from configuration file return new LicenseManagementApi(() => InternalCreateRaw(credentials.Username, credentials.Password)); } public static LicenseManagementApi Create(string username, string password) { return new LicenseManagementApi(() => InternalCreateRaw(username, password)); } public static LicenseManagementWSClient InternalCreateRaw(string username, string password) { var client = new LicenseManagementWSClient( "WSHttpBinding_ILicenseManagementWS", "https://srv.softwarepotential.com/SLMServerWS/LicenseManagementWS.svc"); var clientCreds = client.ClientCredentials.UserName; clientCreds.UserName = username; clientCreds.Password = password; return client; } } // Safe wrapper that manages cleaning up WCF proxies correctly class LicenseManagementApi { readonly Func _createClient; public LicenseManagementApi(Func createClient) { _createClient = createClient; } public TResult Execute(Func<LicenseManagementWSClient, TResult> serviceCalls) { var client = _createClient(); try { return serviceCalls(client); } catch (Exception ex) { client.Abort(); throw; } finally { client.IfNotFaultedCloseAndCleanupChannel(); } } public void Execute(Action<LicenseManagementWSClient> serviceCalls) { var client = _createClient(); try { return serviceCalls(client); } catch (Exception ex) { client.Abort(); throw; } finally { client.IfNotFaultedCloseAndCleanupChannel(); } } } static class WcfExtensions { /// <summary> /// Safely closes a service client connection. /// </summary> /// <param name="client">The client connection to close.</param> public static void IfNotFaultedCloseAndCleanupChannel(this ICommunicationObject client) { // Don't try to Close if we are Faulted - this would cause another exception which would hide the primary one if (client.State == CommunicationState.Opened) try { // Close this client client.Close(); } catch (CommunicationException) { client.Abort(); } catch (TimeoutException) { client.Abort(); } catch (Exception) { client.Abort(); throw; } } } }
Comments
0 comments
Article is closed for comments.