Previous posts have dealt successfully with how to consume a web service and how to use the SmartOffice DynamicWs classes. This post will help if you need something which is dynamic, yet decoupled from SmartOffice.
This is a sample based on the WCF Dynamic Proxy classes available under a Microsoft Public License in the msdn archive.
For initial reference we have a standard C# invocation using a generated service reference. The web service we are using is API_MNS150MI_GetUserData.
The only tricky part here is ensuring the http authentication is set so that Web services accepts you as a valid user.
Here is the code for the static call against the generated service reference.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.IO; using WebServiceStatic.API131; using System.ServiceModel; namespace WebServiceStatic { class Program { static void Main(string[] args) { // Create a client with basic http credentials API_MNS150MI_GetUserDataClient client = new API_MNS150MI_GetUserDataClient(); System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding(); binding.Security.Mode = BasicHttpSecurityMode.Transport; binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; binding.MaxReceivedMessageSize = 25 * 1024 * 1024; client.Endpoint.Binding = binding; // show endpoint address Console.WriteLine(client.Endpoint.Address); Console.WriteLine(client.Endpoint.Name); // ask for UserID and password Console.Write("User ID : "); client.ClientCredentials.UserName.UserName = Console.ReadLine().Trim(); Console.Write("Password: "); client.ClientCredentials.UserName.Password = Console.ReadLine().Trim(); // Create LWS header lws header = new lws(); header.user = client.ClientCredentials.UserName.UserName; header.password = client.ClientCredentials.UserName.Password; // Create a requests item GetUserDataItem item1 = new GetUserDataItem(); item1.USID = client.ClientCredentials.UserName.UserName; // construct a collection for the request item (only 1 accepted?) GetUserDataCollection collection = new GetUserDataCollection(); collection.GetUserDataItem = new GetUserDataItem[] { item1 }; try { // execute the web service GetUserDataResponseItem[] response = client.GetUserData(header, collection); // loop through the response items (only 1) and output to console foreach (GetUserDataResponseItem responseItem in response) { Console.WriteLine("User '{0}' description '{1}'", responseItem.USID, responseItem.TX40); } } catch (Exception e) { // catch and display any errors Console.WriteLine(e.Message); } // wait for user to press a key Console.WriteLine("Press any key to continue..."); Console.ReadKey(); } } }
The result shows we have connected to the web service and retrieved the Users ID (USID) and description (TX40).
Now we have the basic hard-coded example code as a template, we can use the DynamicProxyLibrary to do the same.
This dynamically creates an Assembly (dll) containing the service reference which we can use in place of a hard-coded Service reference.
This can be done without the DynamicProxyLibrary however as the DynamicProxy handles most of the Assembly/Reflection plumbing it is much easier to read and work with.
First create a project referencing the DynamicProxyLibrary in Visual Studio.
Now it is possible to use the Dynamic proxy to call the web service without using a hard-coded service references, all field/property/class references can be coded as text.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WebServiceDynamic { using WcfSamples.DynamicProxy; using System.ServiceModel.Description; using System.ServiceModel; using System.Reflection; class Program { static void Main(string[] args) { string serviceWsdlUri = "https://m3app-2013.gdeinfor2.com:41964/mws-ws/services/API_MNS150MI_GetUserData?wsdl"; if (args.Length > 0) serviceWsdlUri = args[0]; // create the dynamic proxy factory, that downloads the service metadata // and create the dynamic factory. Console.WriteLine("Creating DynamicProxyFactory for " + serviceWsdlUri); DynamicProxyFactory factory = new DynamicProxyFactory(serviceWsdlUri); // list the endpoints. int count = 0; foreach (ServiceEndpoint endpoint in factory.Endpoints) { // create proxy client Console.WriteLine("Service Endpoint[{0}]", count); Console.WriteLine("\tAddress = " + endpoint.Address); Console.WriteLine("\tContract = " + endpoint.Contract.Name); Console.WriteLine("\tBinding = " + endpoint.Binding.Name); DynamicProxy clientProxy = factory.CreateProxy(endpoint.Contract.Name); // Create a client with basic http credentials System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding(); binding.Security.Mode = BasicHttpSecurityMode.Transport; binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; binding.MaxReceivedMessageSize = 25 * 1024 * 1024; ServiceEndpoint clientEndpoint = (ServiceEndpoint)clientProxy.GetProperty("Endpoint"); clientEndpoint.Binding = binding; // ask for UserID and password ClientCredentials credentials = (ClientCredentials)clientProxy.GetProperty("ClientCredentials"); Console.Write("User ID : "); credentials.UserName.UserName = Console.ReadLine().Trim(); Console.Write("Password: "); credentials.UserName.Password = Console.ReadLine().Trim(); // Create LWS header Type lwsType = clientProxy.ProxyType.Assembly.GetType("lws"); DynamicObject header = new DynamicObject(lwsType); header.CallConstructor(); header.SetProperty("user", credentials.UserName.UserName); header.SetProperty("password", credentials.UserName.Password); // Create a requests item Type itemType = clientProxy.ProxyType.Assembly.GetType("GetUserDataItem"); DynamicObject item = new DynamicObject(itemType); item.CallConstructor(); item.SetProperty("USID", credentials.UserName.UserName); // Add the user request item to an array of 1 Array itemArray = Array.CreateInstance(item.ObjectType, 1); itemArray.SetValue(item.ObjectInstance, 0); // construct a collection for the request item (only 1 accepted?) Type collectionType = clientProxy.ProxyType.Assembly.GetType("GetUserDataCollection"); DynamicObject collection = new DynamicObject(collectionType); collection.CallConstructor(); collection.SetProperty("GetUserDataItem", itemArray); try { // execute the web service Array responseCollection = (Array)clientProxy.CallMethod("GetUserData", new object[] { header.ObjectInstance, collection.ObjectInstance }); // loop through the response items (only 1) and output to console foreach (object responseItemObject in responseCollection) { DynamicObject responseItem = new DynamicObject(responseItemObject); Console.WriteLine("User '{0}' description '{1}'", responseItem.GetProperty("USID"), responseItem.GetProperty("TX40")); } } catch (Exception e) { // catch and display exceptions Console.WriteLine(e.Message); // catch and display inner exception (this is the real error from the web service call) if (e.InnerException != null) { Console.WriteLine(e.InnerException.Message); } } // close the connection clientProxy.Close(); } Console.WriteLine("Press any key..."); Console.ReadKey(); } } }
The result shows that we can use the DynamicProxyFactory to get some basic information about the web service, then consume the web service.
Regards,
Lee Flaherty
UPDATE: This was tested against M3 10.1 and M3 13.1 both running on the grid. It may, or may not, work on other versions.