Building the WCF Consumer


Now that a TCP service is out there, which you built using the WCF framework, the next step is to build a consumer application that uses the simple Calculator service. The consumer sends its request via TCP using SOAP. Using TCP means that the consumption can actually occur with a binary encoding of the SOAP message on the wire, substantially decreasing the size of the payload being transmitted.

This section describes how to consume this service. The first step is to open Visual Studio 2005 and create a new Windows Forms application. Though we are using a Windows Forms application, you can make this consumer call through any other application type within .NET as well.

Call the new Windows Forms application WCF_Consumer. This application will consume the Calculator service, so it should be laid out as shown in Figure 30-7.

image from book
Figure 30-7

Adding a Service Reference

Once you have laid out this form, make a reference to the new WCF service. You do this in a manner quite similar to how it is done with XML Web Service references. Right-click on the solution name from the Solution Explorer in Visual Studio and select Add Service Reference from the dialog. This capability to add a service reference is new to .NET 3.0 - previously, you only had the Add Reference and Add Web Reference options.

Once you have selected Add Service Reference, you are presented with the dialog shown in Figure 30-8.

image from book
Figure 30-8

The Add Service Reference dialog asks you for two things: the Service URI (basically a pointer to the WSDL file) and the name you want to give to the reference. The name you provide the reference is the name that will be used for the instantiated object that enables you to interact with the service.

Referring to Figure 30-8, you can see that the name provided to the Service URI setting is http://localhost:8000/docs. Remember that this is the location you defined earlier when you built the service. This URI was defined in code directly in the service:

 Dim smb As New ServiceMetadataBehavior() smb.HttpGetEnabled = True smb.HttpGetUrl = New Uri("http://localhost:8000/docs") serviceHost.Description.Behaviors.Add(smb)

Press the OK button in the Add Service Reference dialog. This adds to your project a Service References folder containing some proxy files, as shown in Figure 30-9.

image from book
Figure 30-9

Indeed, the Service References folder is added and two files are contained within this folder: CalculatorService.map and CalculatorService.vb. The other important addition to note is the System.ServiceModel reference, made for you in the References folder. This reference was not there before you made reference to the service through the Add Service Reference dialog.

Reviewing the Reference

Looking at the CalculatorService.map file, you can see that it is a simple XML file that provides some information about where the WSDL file is located, as well as the location of the service:

  <?xml version="1.0" encoding="utf-8"?> <ServiceReference>    <ProxyGenerationParameters       ServiceReferenceUri="http://localhost:8000/docs"       Name="CalculatorService"       NotifyPropertyChange="True"       UseObservableCollection="False">    </ProxyGenerationParameters>    <EndPoints>       <EndPoint    Address="net.tcp://192.168.1.102:8080/Calculator/"    BindingConfiguration="NetTcpBinding_ICalculator"             Contract="CalculatorService.ICalculator"             >       </EndPoint>    </EndPoints> </ServiceReference> 

This file provides the capability to later update the reference to the service if needed, due to a change in the service interface. You can see this capability by right-clicking on the CalculatorService.map file; an Update Service Reference option appears in the provided menu.

The other file, CalculatorService.vb, is your proxy to interact with the service. This file is presented here:

  Option Strict Off Option Explicit On Namespace CalculatorService     <System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", _          "3.0.0.0"),  _      System.ServiceModel.ServiceContractAttribute( _         ConfigurationName:="CalculatorService.ICalculator")>  _     Public Interface ICalculator        <System.ServiceModel.OperationContractAttribute( _         Action:="http://tempuri.org/ICalculator/Add", _         ReplyAction:="http://tempuri.org/ICalculator/AddResponse")>  _         Function Add(ByVal a As Integer, ByVal b As Integer) As Integer        <System.ServiceModel.OperationContractAttribute( _         Action:="http://tempuri.org/ICalculator/Subtract", _         ReplyAction:="http://tempuri.org/ICalculator/SubtractResponse")>  _         Function Subtract(ByVal a As Integer, ByVal b As Integer) As Integer        <System.ServiceModel.OperationContractAttribute( _         Action:="http://tempuri.org/ICalculator/Multiply", _         ReplyAction:="http://tempuri.org/ICalculator/MultiplyResponse")>  _         Function Multiply(ByVal a As Integer, ByVal b As Integer) As Integer        <System.ServiceModel.OperationContractAttribute( _         Action:="http://tempuri.org/ICalculator/Divide",  _         ReplyAction:="http://tempuri.org/ICalculator/DivideResponse")>  _         Function Divide(ByVal a As Integer, ByVal b As Integer) As Integer     End Interface     <System.CodeDom.Compiler.GeneratedCodeAttribute( _      "System.ServiceModel", "3.0.0.0")>  _     Public Interface ICalculatorChannel         Inherits CalculatorService.ICalculator, System.ServiceModel.IClientChannel     End Interface     <System.Diagnostics.DebuggerStepThroughAttribute(),  _      System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", _      "3.0.0.0")>  _     Partial Public Class CalculatorClient         Inherits System.ServiceModel.ClientBase(Of CalculatorService.ICalculator)         Implements CalculatorService.ICalculator         Public Sub New()             MyBase.New         End Sub         Public Sub New(ByVal endpointConfigurationName As String)             MyBase.New(endpointConfigurationName)         End Sub         Public Sub New(ByVal endpointConfigurationName As String, _            ByVal remoteAddress As String)             MyBase.New(endpointConfigurationName, remoteAddress)         End Sub         Public Sub New(ByVal endpointConfigurationName As String, _            ByVal remoteAddress As System.ServiceModel.EndpointAddress)             MyBase.New(endpointConfigurationName, remoteAddress)         End Sub         Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, _            ByVal remoteAddress As System.ServiceModel.EndpointAddress)             MyBase.New(binding, remoteAddress)         End Sub         Public Function Add(ByVal a As Integer, ByVal b As Integer) As Integer _            Implements CalculatorService.ICalculator.Add             Return MyBase.Channel.Add(a, b)         End Function         Public Function Subtract(ByVal a As Integer, ByVal b As Integer) _            As Integer Implements CalculatorService.ICalculator.Subtract             Return MyBase.Channel.Subtract(a, b)         End Function         Public Function Multiply(ByVal a As Integer, ByVal b As Integer) _            As Integer Implements CalculatorService.ICalculator.Multiply             Return MyBase.Channel.Multiply(a, b)         End Function         Public Function Divide(ByVal a As Integer, ByVal b As Integer) _           As Integer Implements CalculatorService.ICalculator.Divide             Return MyBase.Channel.Divide(a, b)         End Function     End Class End Namespace 

Here, an interface is defining the four methods and the implementing class CalculatorClient, which contains the functions that in turn call the service built earlier in the chapter.

Configuration File Changes

Another addition to your project is the app.config file. After the service reference is made, the app.config file contains several .NET 3.0 configuration settings. These configuration settings were automatically added by the Visual Studio WCF extensions. The new app.config file is presented in the following code block:

  <?xml version="1.0" encoding="utf-8" ?> <configuration>     <system.diagnostics>         <sources>             <!-- This section defines the logging configuration for                  My.Application.Log -->             <source name="DefaultSource" switchName="DefaultSwitch">                 <listeners>                     <add name="FileLog"/>                     <!-- Uncomment the below section to write to the                          Application Event Log -->                     <!--<add name="EventLog"/>-->                 </listeners>             </source>         </sources>         <switches>             <add name="DefaultSwitch" value="Information" />         </switches>         <sharedListeners>             <add name="FileLog"                  type="Microsoft.VisualBasic.Logging.FileLogTraceListener,                     Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral,                     PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"                  initializeData="FileLogWriter"/>             <!-- Uncomment the below section and replace APPLICATION_NAME                  with the name of your application to write to the                  Application Event Log -->             <!--<add name="EventLog"                  type="System.Diagnostics.EventLogTraceListener"                  initializeData="APPLICATION_NAME"/> -->         </sharedListeners>     </system.diagnostics>     <system.serviceModel>         <bindings>             <netTcpBinding>                 <binding name="NetTcpBinding_ICalculator" closeTimeout="00:01:00"                     openTimeout="00:01:00" receiveTimeout="00:10:00"                     sendTimeout="00:01:00"                     transactionFlow="false" transferMode="Buffered"                     transactionProtocol="OleTransactions"                     hostNameComparisonMode="StrongWildcard" listenBacklog="10"                     maxBufferPoolSize="524288" maxBufferSize="65536"                     maxConnections="10"                     maxReceivedMessageSize="65536">                     <readerQuotas maxDepth="32" maxStringContentLength="8192"                         maxArrayLength="16384"                         maxBytesPerRead="4096" maxNameTableCharCount="16384" />                     <reliableSession ordered="true" inactivityTimeout="00:10:00"                         enabled="false" />                     <security mode="None">                         <transport clientCredentialType="Windows"                          protectionLevel="EncryptAndSign" />                         <message clientCredentialType="Windows" />                     </security>                 </binding>             </netTcpBinding>         </bindings>         <client>             <endpoint address="net.tcp://192.168.1.102:8080/Calculator/"                 binding="netTcpBinding"                 bindingConfiguration="NetTcpBinding_ICalculator"                 contract="CalculatorService.ICalculator"                 name="NetTcpBinding_ICalculator" />         </client>     </system.serviceModel> </configuration> 

The important part of this configuration document is the <client> element. This element contains a child element called <endpoint> that defines the where and how of the service consumption process.

The <endpoint> element provides the address of the service - net.tcp://192.168.1.102:8080/ Calculator - and it specifies which binding of the available WCF bindings should be used. In this case, the netTcpBinding is the required binding. Even though you are using an established binding from the WCF framework, from the client side you can customize how this binding behaves. The settings that define the behavior of the binding are specified using the bindingConfiguration attribute of the <endpoint> element. In this case, the value provided to the bindingConfiguration attribute is NetTcpBinding_ICalculator, which is a reference to the <binding> element contained within the <netTcpBinding> element:

 <binding name="NetTcpBinding_ICalculator" closeTimeout="00:01:00"  openTimeout="00:01:00" receiveTimeout="00:10:00"  sendTimeout="00:01:00"  transactionFlow="false" transferMode="Buffered"  transactionProtocol="OleTransactions"  hostNameComparisonMode="StrongWildcard" listenBacklog="10"  maxBufferPoolSize="524288" maxBufferSize="65536"  maxConnections="10"  maxReceivedMessageSize="65536">    <readerQuotas maxDepth="32" maxStringContentLength="8192"     maxArrayLength="16384"     maxBytesPerRead="4096" maxNameTableCharCount="16384" />    <reliableSession ordered="true" inactivityTimeout="00:10:00"      enabled="false" />    <security mode="None">       <transport clientCredentialType="Windows"        protectionLevel="EncryptAndSign" />       <message clientCredentialType="Windows" />    </security> </binding>

As demonstrated, the new Visual Studio 2005 extensions for WCF do make the consumption of these services fairly trivial. The next step is to code the consumption of the service interface to the GUI that was created as one of the first steps.

Writing the Consumption Code

The code to consume the interface is quite minimal. End users will select the radio button of the operation that they are interested in performing. The default radio button selected is Add. The end user places a number in each of the two text boxes provided and clicks the Calculate button to call the service to perform the designated operation on the provided numbers. Here is the code for the form:

  Public Class Form1     Private Sub Button1_Click(ByVal sender As System.Object, _        ByVal e As System.EventArgs) Handles Button1.Click         Dim result As Integer         Dim svc As New CalculatorService.CalculatorClient()         svc.Open()         If RadioButton1.Checked = True Then             result = svc.Add(Integer.Parse(TextBox1.Text), _                Integer.Parse(TextBox2.Text))         ElseIf RadioButton2.Checked = True Then             result = svc.Subtract(Integer.Parse(TextBox1.Text), _                Integer.Parse(TextBox2.Text))         ElseIf RadioButton3.Checked = True Then             result = svc.Multiply(Integer.Parse(TextBox1.Text), _                Integer.Parse(TextBox2.Text))         ElseIf RadioButton4.Checked = True Then             result = svc.Divide(Integer.Parse(TextBox1.Text), _                Integer.Parse(TextBox2.Text))         End If         svc.Close()         Label1.Text = result.ToString()     End Sub End Class 

This is quite similar to what is done when working with Web references from the XML Web Services world. First is an instantiation of the proxy class, as shown with the creation of the svc object:

 Dim svc As New CalculatorService.CalculatorClient()

Working with the ws object now, the IntelliSense options provide you with the appropriate Add(), Subtract(), Multiply(), and Divide() methods. Running this application provides results similar to those presented in Figure 30-10.

image from book
Figure 30-10

In this case, the Add() method is invoked from the service when the form’s Calculate button is pressed. If you add some kind of TCP trace on your machine, you will see results similar to the following:

 00000000  0B 06 92 01 55 2A 68 74  74 70 3A 2F 2F 74 65 6D   ....U*ht tp://tem 00000010  70 75 72 69 2E 6F 72 67  2F 49 43 61 6C 63 75 6C   puri.org /ICalcul 00000020  61 74 6F 72 2F 41 64 64  52 65 73 70 6F 6E 73 65   ator/Add Response 00000030  0B 41 64 64 52 65 73 70  6F 6E 73 65 13 68 74 74   .AddResp onse.htt 00000040  70 3A 2F 2F 74 65 6D 70  75 72 69 2E 6F 72 67 2F   p://temp uri.org/ 00000050  09 41 64 64 52 65 73 75  6C 74 56 02 0B 01 73 04   .AddResu ltV...s. 00000060  0B 01 61 06 56 08 44 0A  1E 00 82 AB 01 44 12 AD   ..a.V.D. .....D.. 00000070  A1 8F 9D 89 5A B0 FF 45  A1 D5 29 A9 F4 57 2B A3   ....Z..E ..)..W+. 00000080  44 0C 1E 00 82 AB 14 01  56 0E 42 03 0A 05 42 07   D....... V.B...B. 00000090  8B 00 01 01 01 01                                  ......

The response will return something such as the following:

 00000000  00 01 00 01 02 02 28 6E  65 74 2E 74 63 70 3A 2F   ......(n et.tcp:/ 00000010  2F 31 39 32 2E 31 36 38  2E 31 2E 31 30 32 3A 38   /192.168 .1.102:8 00000020  30 38 30 2F 43 61 6C 63  75 6C 61 74 6F 72 2F 03   080/Calc ulator/. 00000030  08 0C 06 B0 01 68 22 68  74 74 70 3A 2F 2F 74 65   .....h"h ttp://te 00000040  6D 70 75 72 69 2E 6F 72  67 2F 49 43 61 6C 63 75   mpuri.or g/ICalcu 00000050  6C 61 74 6F 72 2F 41 64  64 28 6E 65 74 2E 74 63   lator/Ad d(net.tc 00000060  70 3A 2F 2F 31 39 32 2E  31 36 38 2E 31 2E 31 30   p://192. 168.1.10 00000070  32 3A 38 30 38 30 2F 43  61 6C 63 75 6C 61 74 6F   2:8080/C alculato 00000080  72 2F 03 41 64 64 13 68  74 74 70 3A 2F 2F 74 65   r/.Add.h ttp://te 00000090  6D 70 75 72 69 2E 6F 72  67 2F 01 61 01 62 56 02   mpuri.or g/.a.bV. 000000A0  0B 01 73 04 0B 01 61 06  56 08 44 0A 1E 00 82 AB   ..s...a. V.D..... 000000B0  01 44 1A AD A1 8F 9D 89  5A B0 FF 45 A1 D5 29 A9   .D...... Z..E..). 000000C0  F4 57 2B A3 44 2C 44 2A  AB 14 01 44 0C 1E 00 82   .W+.D,D* ...D.... 000000D0  AB 03 01 56 0E 42 05 0A  07 42 09 89 17 42 0B 8B   ...V.B.. .B...B.. 000000E0  E9 00 01 01 01                                     .....

As before, the requests and responses are sent over TCP as binary, dramatically decreasing the size of the payload for large messages. This is something that .NET Remoting was used for prior to the release of the WCF framework. This concludes the short tutorial demonstrating how to build your own WCF service using the TCP protocol and consume this service directly into a .NET Windows Forms application.




Professional VB 2005 with. NET 3. 0
Professional VB 2005 with .NET 3.0 (Programmer to Programmer)
ISBN: 0470124709
EAN: 2147483647
Year: 2004
Pages: 267

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net