WCF Example


To build a service, you follow the steps outlined in the following list:

  1. Define the service contract in a Visual Basic interface.

  2. Implement the service contract in a service class.

  3. Build the host application to run the service.

  4. Configure the service to specify bindings and endpoints.

  5. Run the service.

After you build the service, follow these steps to build a client:

  1. Use the SvcUtil tool to discover information about the service contract and build Visual Basic code to implement a client class.

  2. Write the client application that uses the client class.

The book’s web site contains two programs for this chapter. The FortuneServerHost program is a server application that provides a single subroutine GetFortune that takes no parameters and returns a random quote. Program ShowFortune is a client application that invokes the GetFortune service method.

Define the Service Contract

The first step in building the service is to define the service contract. WCF makes this process so easy, its downright fun.

First, create a new application to contain the service. In this example, the host program is a console application, so I created a new console application project. You won’t need it right away to build the service class, but you will need it later to build the host, so you may as well create it now.

Next, add the server class. In this example, it’s called FortunePicker. It provides the service method.

To use WCF in the application, you must add a reference to the .NET Framework 3.0 libraries that contain its classes. Double-click My Project and select the References tab. Click the Add button, select the System.ServiceModel library, and click OK.

After you’ve set up the project, you must make a Visual Basic interface that defines the service contract. The following code shows the beginning of the FortunePicker class’s file, including this interface:

  Imports System.ServiceModel Imports System.IO Namespace VBHelper.FortuneServer     ' Define the service contract.     <ServiceContract([Namespace]:="http://VBHelper.FortuneServer")> _     Public Interface IFortunePicker         ' Return a random fortune.         <OperationContract()> _         Function GetFortune() As String     End Interface 

The service contract is decorated with WCF attributes that define the service contract. To make using the attributes easier, the file starts by importing the System.ServiceModel namespace that contains them. The service also uses objects in the System.IO namespace, so the file imports it, too.

The interface and the FortunePicker service class are contained in the VBHelper.FortuneServer namespace. You will use this namespace to later identify the service in the program’s configuration file. To make things simpler, I also removed the program’s root namespace. Double-click My Project, select the Application tab, and clear the “Root namespace” text box.

The IFortunePicker interface defines the service contract. The interface itself uses the ServiceContract attribute to tell Visual Basic that it defines a service contract. The service’s contract namespace is http:// VBHelper.FortuneServer.

The interface defines a single method, the GetFortune function. This method includes an Operation?Contract attribute to identify it as a service method.

That’s all you need to do to define the service contract.

Implement the Service Contract

After you define the service contract, you must build the server class that will implement it. To do this, simply build the FortunePicker class and make it implement the IFortunePicker interface. The following code shows how the example (available for download) works:

      ' Implement the IFortunePicker interface.     Public Class FortunePicker         Implements IFortunePicker         Private m_Random As Random         Public Sub New()             m_Random = New Random()         End Sub         ' Return a random fortune.         Public Function GetFortune() As String Implements IFortunePicker.GetFortune             Dim quotes() As String = { _                 "I stand by all the misstatements that I've                 "You can observe a lot just by watching. -- Yogi Berra", _                 .... other quotes omitted ...                 "Two nations divided by a common language. -- Winston Churchill" _             }             ' Pick a random quote.             Dim quote As String = quotes(m_Random.Next(0, quotes.Length))             ' Write to the Console window so we can see             ' that the server is doing something.             Console.WriteLine(Now.ToString() & ": " & quote)             ' Save a record in the log file.             Using stream_writer As StreamWriter = _              File.AppendText("C:\Windows\Fortunes.log")                 stream_writer.WriteLine(Now.ToString() & ": " & quote)             End Using             ' Return the selected quote.             Return quote         End Function     End Class End Namespace 

The class uses the Implements statement to indicate that it implements the interface and, therefore, the service contract.

The class’s constructor creates a new Random object that the program later uses to pick random quotes.

The GetFortune function implements the IFortunePicker.GetFortune service method. It defines an array of strings containing quotes. A more complicated version of the program might get quotes from a database.

The subroutine uses the class’s Random object to pick a random quote from the array. It writes the current date, time, and quote into the console window so that you can see that the server is doing something.

It also appends the date, time, and quote to the file C:\Windows\Fortunes.log. The server will be running with administrator privileges, so it can write into this file, something that a normal user cannot do because it is in the Windows directory.

Finally, the function returns the selected quote. WCF packages the quote in a message and sends it to the client.

Build the Host

In this example, the host is a console application. The following code shows the Main subroutine that the application runs when it starts:

  Imports System.ServiceModel Namespace VBHelper.FortuneServer     Module SubMain         Sub Main()             ' Create a ServiceHost for the CalculatorService type.             Using service_host As New ServiceHost(GetType(FortunePicker))                 ' Open the ServiceHost to listen for requests.                 service_host.Open()                 Console.WriteLine("Server running. Press Enter to stop.")                 Console.ReadLine()                 ' Close the service.                 service_host.Close()             End Using         End Sub     End Module End Namespace 

The program creates a new ServiceHost object, passing its constructor the type of the FortunePicker service class.

It opens the host to start listening for service request messages. The call to Open makes the ServiceHost listen for messages asynchronously, so the program continues running. To prevent the application from immediately stopping, the program displays a message in the console window and then uses ReadLine to wait for the user to press Enter.

When the ServiceHost receives a service request, the FortunePicker class handles the request, adding messages to the console window and the log file, and returning the selected quote to the client.

When you press Enter in the console window, the host program calls the ServiceHost object’s Close method. After that point, the host will finish honoring any client requests that it has already received, but it will not accept new requests.

Finally, after the host finishes with any pending requests, the program ends.

Configure the Service

The next step is to configure the service. This is one of the more complicated steps in creating the service.

You can add code in the host application to configure the service, but Microsoft recommends against that approach for a couple of reasons. Probably the most important of these reasons is that service definitions often change. For example, developers may build the server on a test computer and then move it to another computer for production use. Sometimes hosts must also be moved to other servers after they have been built to rebalance computer or network loads, or to move to a faster computer. In any of these cases, if you hard-code the endpoint definitions into the code, you would need to rebuild the host whenever you move it to a new computer.

Instead of putting this information inside the code, you can add it to a configuration file. If you later need to move the server, you only need to change the configuration file.

To add a configuration file to the host program, open the Project menu and run the Add New Item command. Select the Application Configuration File template. Leave the default filename app.config unchanged and click Add.

Visual Studio will create the file, add it to your project, and insert some default configuration stuff. It’s moderately long and not relevant to this discussion, so it’s not shown here. The only important piece for current purposes is that it has a root <configuration> element that contains all of the file’s information. You need to add the service’s configuration information to this app.config file in a <system.serviceModel> element.

The following code shows a configuration file for the example service. The <system.serviceModel> element contains sub-elements to describe services (there’s only one in this example), bindings, and behaviors.

  <?xml version="1.0" encoding="utf-8" ?> <configuration>   <system.serviceModel>     <services>       <service name="VBHelper.FortuneServer.FortunePicker"                behaviorConfiguration="FortunePickerBehavior">         <host>           <!-- The base address -->           <baseAddresses>             <add baseAddress="http://localhost:8000/FortuneServer/service"/>           </baseAddresses>         </host>         <!-- This named pipe endpoint is exposed               at the base address provided by the host:               net.pipe://localhost/FortuneServer/service           -->         <endpoint address="net.pipe://localhost/FortuneServer/service"                   binding="netNamedPipeBinding"                   bindingConfiguration="Binding1"                    contract="VBHelper.FortuneServer.IFortunePicker" />         <!-- This MEX (Metadata Exchange) endpoint is exposed at               http://localhost:8000/FortuneServer/service/mex          -->         <endpoint address="mex"                   binding="mexHttpBinding"                   contract="IMetadataExchange" />       </service>     </services>     <bindings>       <!-- Configure the NetNamedPipeBinding. -->       <netNamedPipeBinding>         <binding name="Binding1">           <security mode="Transport">             <transport protectionLevel="EncryptAndSign" />           </security>         </binding>       </netNamedPipeBinding>     </bindings>     <!-- For debugging purposes set the          includeExceptionDetailInFaults attribute to true-->     <behaviors>       <serviceBehaviors>         <behavior name="FortunePickerBehavior">           <serviceMetadata httpGetEnabled="True"/>           <serviceDebug includeExceptionDetailInFaults="False" />         </behavior>       </serviceBehaviors>     </behaviors>   </system.serviceModel> </configuration> 

The <services> element contains service definitions. Each service gives its name and the names of the behaviors it provides. This example gives the behavior of the FortunePicker class the name FortunePickerBehavior. The <host> element tells where the service will listen for requests.

Next, the <service> element contains endpoint definitions. These contain definitions for endpoints’ addresses, bindings, and contracts. The binding attribute gives the name of the binding that the endpoint uses. The binding is also described shortly in the configuration file.

The contract attribute names the Visual Basic interface that defines the service contract.

The second binding in this example is a Metadata Exchange (MEX) endpoint. It exposes metadata that describes the service to potential clients. A potential client can use a tool such as SvcUtil to use this binding to learn about the service. The section “Use SvcUtil” later in this chapter explains how to do that.

The configuration file’s <bindings> section describes the bindings used by the endpoints. They give the bindings’ name, security characteristics, and other parameters. A binding’s name should match the name used in the endpoint’s bindingConfiguration attribute.

Finally, behaviors can modify the service’s behavior. These can describe such things as a service’s authorization policy, credentials, and debugging features.

Run the Service

After you have created the service class, host application, and configuration, you can compile the host application as usual. Visual Basic converts the app.config file into a configuration file named after the application. In this example, the host program is called FortuneServerHost.exe, so the output configuration file is called FortuneServerHost.exe.config. This file must be in the same directory as the executable program when it runs.

If you run the FortuneServerHost example program right now, you will get an error. How much you learn about the error depends on how you run the application. If you simply double-click on the executable program in Windows Explorer, you’ll see a generic error message that says the server has stopped working. You won’t learn anything about the cause of the problem.

If you run the host in the Visual Basic IDE and you place the code inside a Try Catch block, you’ll probably only see the last error generated by the server saying that the server is in a faulted state. That doesn’t really tell you much either, except that the server has a problem.

If you don’t use a Try Catch block, the program will crash at the first error it encounters, and you can get a hint about the real problem. In this case, the error message says the following:

 HTTP could not register URL http://+:8000/FortuneServer/service/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).

You can also see this error information plus the faulted message and other messages if you run the program in a command window.

The underlying problem is that the host doesn’t have the privileges it needs to listen for service requests. The URL shown in the error message explains how to configure HTTP or IIS to allow certain users to listen to the address so you can run the server.

This example also writes into the restricted file C:\Windows\Fortunes.log, and it doesn’t have permission to do that either. If you right-click the server application and select Run as administrator, the host will be able to listen to the necessary address and will be able to write into the file.

When you run the application, a console window will appear and display “Server running. Press Enter to stop.” When you press the Enter key, the server exits.

Use SvcUtil

If it can use the service, the client application must learn about the service contract. It must then include code and appropriate configuration information to let it connect to the service.

Fortunately, the SvcUtil tool makes all of this relatively easy. It can discover information about the service contract, and build a configuration file and an easy-to-use client class that connects to the service for you.

The following code shows the syntax for calling SvcUtil in this example. You would execute this code in a command window all on one line.

  SvcUtil /language:vb /out:ClientCode.vb /config:app.config     http://localhost:8000/FortuneServer/service/mex 

The following list describes the parameters passed to SvcUtil in this example.

  • /language - Tells SvcUtil what language it should use when it generates the client class.

  • /out - Gives the name of the output file that should contain the generated client class code.

  • /config - Gives the name of the configuration file that SvcUtil should create.

The final parameter is the address where SvcUtil can find the service information. Notice that this is the same as the MEX address defined in the host’s configuration file.

To make executing this command easier, the ShowFortune example project includes a batch file named makecode.bat that sets its path to the SvcUtil tool’s location (on my system, it’s C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\IDE), runs the command, and then pauses so that you can read the output.

Write the Client Application

Using the class created by the SvcUtil tool is easy. Create a new application and add the files that SvcUtil generated to it. Use the Project menu’s Add Existing Item command to add both the app.config file and the code file (ClientCode.vb in this example).

The generated code file defines a class named after the service class with the word Client added at the end. In this example, the class is called FortunePickerClient. The class includes several constructors, so you can determine such things as the configuration and binding that the client should use. The simplest constructor takes no parameters and uses default connection information.

The generated code also includes methods to implement the service contract. In this example, that just includes a GetFortune function.

When you want the client program to use the service, add code to instantiate the client class and call its methods. The following code shows how the ShowFortune program displays a quote when you click the Get Fortune button. It simply makes an instance of the FortunePickerClient class and calls its GetFortune method.

  Private Sub btnGetFortune_Click(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles btnGetFortune.Click     Dim fortune_client As New FortunePickerClient()     MessageBox.Show(fortune_client.GetFortune()) End Sub 

That’s all there is to it.




Visual Basic 2005 with  .NET 3.0 Programmer's Reference
Visual Basic 2005 with .NET 3.0 Programmer's Reference
ISBN: 470137053
EAN: N/A
Year: 2007
Pages: 417

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