SOA Patterns with BizTalk Server 2013 and Microsoft Azure(Second Edition)
上QQ阅读APP看书,第一时间看更新

Consuming WCF services

Now comes the most important part: using the service! How you go about consuming a WCF service depends greatly on the type of client application used.

Non-WCF clients

If you plan on calling a WCF service from a non-WCF client, have no fear, you're still in great shape. One of the design goals of WCF (and any quality SOA solution) is interoperability, which means that WCF services should be consumable on a wide variety of platforms and technology stacks.

Now, it is still the responsibility of the service designer to construct a service that's usable by non-WCF applications. For instance, a broadly used service would offer basicHttpBinding to ensure that applications based on .NET Framework 2.0, or JRE 1.4 would have no problem consuming it. An interoperable service would also use security schemes that rely upon commonly available certificates for transport security.

Let's assume that a WCF service with a basic HTTP endpoint has been exposed. Let's also assume that this service has a metadata "behavior" attached to it so that we can interrogate its WSDL contract. If you have a .NET Framework 2.0 application that typically consumes classic ASMX services (ASP.NET web services), they can consume a WCF service in the exact same fashion. That is, add a new web reference to the WCF service metadata definition.

If you have Visual Studio 2012 installed, the Add Web Reference option isn't immediately available on the project.

  1. You first right-click the project and choose the Add Service Reference menu item. Click on the button labeled Advanced, which you'll find at the bottom of the window:
  2. The next window that opens is a settings window, which has a button at the bottom for those who wish to add a traditional "web reference" that leverages older .NET technology:
  3. Choosing the Add Web Reference button finally opens up the traditional service browser, where we plug in the URL of our service and see the corresponding metadata:
  4. In the subsequent code that calls this service, the developer would use the assigned web reference just as if they were calling any standard SOAP web service:
    Console.WriteLine("Vendor client launched ...");
    try
    {
      AsmxProxy.VendorService svc = new AsmxProxy.VendorService();
      AsmxProxy.Vendor newVendor = new AsmxProxy.Vendor();
      newVendor.VendorId = "1234";
      newVendor.VendorName = "Watson Consulting";
      newVendor.VendorContactName = "Watson Seroter";
    
      svc.InsertVendor(newVendor);
      Console.WriteLine("Vendor " + newVendor.VendorId + " inserted ...");
      Console.ReadLine();
    }
    catch (System.Web.Services.Protocols.SoapException ex)
    {
    //grab "insert fault" part of message
       Console.WriteLine(ex.Detail.InnerText);
      Console.ReadLine();
    } 

The result? The HTTP host was opened successfully by WCF, and after the client executed the insert operation, the service wrote its confirmation message to the host console:

However, if our service fails and throws our custom fault message, our client code catches it as a SOAP exception and still has access to the custom fault details. Note that the exception's detail object contains the XML message of the InsertFault type, in the following screenshot:

WCF clients

If you have the benefit of using a WCF-enabled application to call a WCF service, the full might of Microsoft's communication stack is laid before you. You are no longer constrained by HTTP-only communication and you can exploit a wide range of encoding, security, and transaction capabilities in your service consuming application.

Note

While WCF-to-WCF communication scenarios offer a rich set of communication options, technically any WS*-compliant application should be able to take advantage of a majority of WCF's service characteristics. For example, an Oracle application that understands WS-Security can effectively participate in secure conversations with a WCF service.

The easiest way to consume WCF services from a WCF application is to generate a proxy class that shields us from the plumbing necessary to call the service. A WCF proxy can be generated in one of two ways. First, we use the ServiceModel Metadata Utility tool (svcutil.exe) command-line tool if we want full control of the way the proxy class is generated. This tool takes the service metadata and generates a .NET source code file that may be used to call the WCF service.

The power in this little utility lies in the ability to apply a cornucopia of command-line parameters that define attributes of the .NET source code file, such as its programming language, namespace, output location, and a whole lot more. For instance, executing the following command on our service results in a full WCF proxy class and merges the new WCF configurations with the existing configuration file of the client application:

Svcutil.exe http://localhost:8081/VServiceBase?WSDL /      out:WCFProxy.cs /language:c#  /config:app.config /mergeConfig

Because I built the WCF service proxy manually, my client application must have both the System.ServiceModel and System.Runtime.Serialization assemblies added as project references.

Consuming the WCF proxy class looks quite similar to consuming the ASMX proxy class. In fact, the only real difference that you'll notice here is more explicit interaction with the client proxy class. Note that we work with the proxy class within a try block and catch any exceptions (including our custom one) in well-defined catch blocks. While it is tempting to apply the C# using statement to WCF proxies, that practice can actually lead to swallowed exceptions and should be avoided. See http://msdn.microsoft.com/en-us/library/aa355056.aspx for more details. The other slight difference is that the WCF proxy class has an overloaded constructor. In this case, I'm passing in the name of the service endpoint name that resides in the application configuration file:

WcfProxy.VendorServiceClient svc = new WcfProxy.VendorServiceClient ("BasicHttpBinding_VendorService");

try
  {
WcfProxy.Vendor newVendor = new WcfProxy.Vendor();
  newVendor.VendorId = "9876";
  newVendor.VendorName = "Noah Partners";
  newVendor.VendorContactName = "Noah Seroter";

  svc.InsertVendor(newVendor);

Console.WriteLine("Vendor " + newVendor.VendorId + " inserted ...");

  svc.Close();
  }
  catch (System.ServiceModel.FaultException<WcfProxy.InsertFault> ex)
    {
      Console.WriteLine(ex.Detail.FriendlyMessage);
      
      Console.ReadLine();
    }
catch (System.ServiceModel.CommunicationException) { svc.Abort(); }
catch (System.TimeoutException) { svc.Abort(); }
catch (System.Exception) { svc.Abort(); throw; }

If you're looking for an easier way to generate a WCF proxy class, look no further! Visual Studio also offers an Add Service Reference option, which enables us to generate our proxy class from within our development environment. This is depicted as follows:

By either using the ServiceModel Metadata Utility tool explicitly to generate proxy classes or, instead, using Visual Studio (which uses svcutil.exe underneath the covers), you have some efficient options for generating WCF-compliant code for use by service clients.