Hosting a WCF Service in a User Application


Apart from using an IIS Web service to host a WCF service, you have at least three further options. You can create an ordinary application that the user runs to start and stop the WCF service, or you can host the WCF service in a Windows service so that the WCF service is available as long as Windows is running. The third option, if you are using IIS version 7.0, is to use Windows Activation Services, or WAS. Using WAS, you can configure and host a WCF service without needing to run the World Wide Web Publishing Service. However, IIS 7.0 is not available for Windows XP, and we will not consider using WAS any further in this book.

More Info 

For detailed information about IIS 7.0, visit the IIS 7.0 Feature Reference Web site at http://technet2.microsoft.com/WindowsServer/en/Library/1033.mspx?mfr=true.

Using the ServiceHost Class

The discussion so far in this chapter has described the tasks that a host application for a WCF service must perform. You can achieve most of these tasks by using the ServiceHost class, available in the System.ServiceModel namespace. A ServiceHost object can instantiate a service object from an assembly holding the service class, configure the endpoints of the service by using bindings provided in a configuration file or in code, apply any security settings required by the service, and create listener objects for each address that you specify.

When you create a ServiceHost object, you specify the type of the class implementing the service. You can specify the addresses that the ServiceHost object should listen to for requests, like this:

 ServiceHost productsServiceHost = new     ServiceHost(typeof(ProductsServiceImpl),     new Uri("http://localhost:8000/ProductsService/ProductsService.svc"),     new Uri("tcp.net://localhost:8080/TcpProductsService");

This example uses the ProductsService service that you created in Chapter 1, and specifies two addresses: the first uses the HTTP transport, and the second uses TCP. Strictly speaking, the addresses that you specify in the ServiceHost constructor are base addresses. A base address is just the initial part of the address. If you provide an application configuration file that contains further address information, this information will be combined with the base addresses you specify here to generate the real addresses. For example, if you use the following code to instantiate the ServiceHost object:

 ServiceHost productsServiceHost = new     ServiceHost(typeof(ProductsServiceImpl),     new Uri("http://localhost:8000/ProductsService"));

and the application configuration contains an endpoint definition like this:

 <endpoint address="ProductsService.svc" binding="basicHttpBinding" name="ProductsServiceHttp Endpoint" contract="Products.IProductsService" />

the WCF runtime will combine the two elements together to generate an address of “http://localhost:8000/ProductsService/ProductsService.svc.” This is a very powerful feature that enables an administrator to direct a service to use a particular address on a specified site, but that also provides the developer with full control over the selection of the site hosting the service.

If you omit the base address information in the ServiceHost constructor, like this:

 ServiceHost productsServiceHost = new     ServiceHost(typeof(ProductsServiceImpl));

the WCF runtime will just use the address information specified in the application configuration file, and automatically listen for requests on all configured endpoints. This gives the administrator complete control over the addresses and transports used by the service. For convenience, in the examples in this book, you will adopt this approach and specify the complete address information in the application configuration file wherever possible. However, when building your own enterprise applications, you might prefer to provide the base addresses for service endpoints programmatically.

Note 

There is one minor side effect of specifying complete addresses in the application configuration file; if you are building a host application and you wish to enable metadata publishing, you must provide the URL for the service to use to publish its metadata in the HttpGetUrl or HttpsGetUrl properties of the serviceMetadata element of the service behavior.

After you have created the ServiceHost object, you can start listening for requests by using the Open method, like this:

 productsServiceHost.Open();

Opening a ServiceHost object causes the WCF runtime to examine the binding configuration for each endpoint of the service and start listening on each endpoint address. Opening a service can take some time. An overloaded version of the Open method is available that takes a TimeSpan object and that throws an exception if the Open method does not complete within the specified time. Additionally, the ServiceHost class supports the .NET Framework asynchronous mode of operations through the BeginOpen and EndOpen methods implementing the IAsynResult design pattern.

More Info 

The IAsyncResult design pattern is commonly used throughout the .NET Framework, and is not peculiar to WCF. For details, see the topic “Asynchronous Programming Design Patterns” in the .NET Framework Developer’s guide, available in the Microsoft Visual Studio 2005 Documentation, and also online at http://msdn2.microsoft.com/en-us/library/ms228969.aspx.

You stop a service by calling the Close method of the ServiceHost object. The Close method stops the WCF runtime listening for more requests and gracefully shuts the service down; any work in progress is allowed to complete. As with the Open method, you can close a service asynchronously by using the BeginClose and EndClose methods.

The ServiceHost class also provides events that you can use to track the state of a ServiceHost object. Table 2-2 summarizes these events.

Table 2-2: ServiceHost Events
Open table as spreadsheet

Event

Description

Opening

The ServiceHost object is opening the service and is processing the binding information for each endpoint so that it can start listening.

Opened

The ServiceHost object has successfully opened the service, which is now ready to accept client requests.

Closing

The ServiceHost is executing the close method and waiting for all current service requests to complete processing.

Closed

The service has shut down. No listeners are active, and clients cannot send requests.

Faulted

The service has encountered an unrecoverable error. You can examine the ServiceHost object to try and determine the cause of the fault, but clients can no longer use the service. You must close the service and open it again before clients can connect.

Building a Windows Presentation Foundation Application to Host a WCF Service

Let’s look at how to use the ServiceHost class to host a WCF application inside an ordinary application. You should have the .NET Framework 3.0 and the Microsoft Visual Studio Development Tools for .NET Framework 3.0 installed on your computer, so it makes sense to build a Windows Presentation Foundation (WPF) application.

Create a new Windows application to host the WCF service

  1. Using Visual Studio 2005, create a new project. Select the NET Framework 3.0 project types under Visual C#, and use the Windows Application (WPF) template. Name the project ProductsServiceHost and save it in the Microsoft Press\WCF Step By Step\Chapter 2 folder under your \My Projects folder.

  2. In Solution Explorer, rename the image from book Window1.xaml file as image from book HostController.xaml.

  3. Open the image from book App.xaml file. In the pane displaying the XAML description of the form, change the StartupUri attribute of the Application element to image from book HostController.xaml, as shown in bold below:

     <Application x:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     StartupUri="HostController.xaml"     >     <Application.Resources>     </Application.Resources> </Application>

  4. Open the image from book HostController.xaml file. In the pane displaying the XAML description of the form, change the class name to ProductsServiceHost.HostController, and add the code highlighted in bold below to the form:

     <Window x:bold">ProductsServiceHost.HostController"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     Title="ProductsServiceHost" Height="300" Width="300"     >     <Grid>       <Button Height="23" HorizontalAlignment="Left" Margin="51,60,0,0" Name="start" VerticalAlignment="Top" Width="75" Click="onStartClick">Start</Button>       <Button Height="23" HorizontalAlignment="Right" Margin="0,60,56,0" Name="stop" VerticalAlignment="Top" Width="75" IsEnabled="False" Click="onStopClick">Stop</Button>       <Label Height="23" HorizontalAlignment="Left" Margin="51.37,0,0,108" Name= "label1" VerticalAlignment="Bottom" Width="87.63">Service Status:</Label>       <TextBox IsReadOnly="True" Margin="133,0,59,107" Name="status" Text="Service Stopped" Height="26" VerticalAlignment="Bottom"></TextBox>     </Grid> </Window>

    This code in the <Window> element changes the class reference to refer to the new name of the form.

    The code in the <Grid> element adds two buttons, a label, and a text box to the form. The two buttons will enable a user to start and stop the WCF service, and the label and text box display a message indicating the current state of the WCF service (running or stopped). If you examine the Click attribute of the Start button, you can see that it invokes a method called onClickStart. Similarly, the Click attribute of the Stop button invokes a method called onClickStop. You will write the code that implements these methods in the next exercise.

  5. Click the Design tab to refresh the display of the ProductsServiceHost form. Verify that your form looks like the following image:

    image from book

    The Stop button is initially disabled. You will write code to enable it when the service has started.

  6. In Solution Explorer, expand the image from book HostController.xaml node and double-click the file image from book HostController.xaml.cs . The C# code behind the form is displayed in the code view window. Change all occurrences of Window1 in this file to HostController, to match the class named in the XAML description of the form, as shown below:

     namespace ProductsServiceHost {     /// <summary>     /// Interaction logic for HostController.xaml     /// </summary>     public partial class HostController : Window     {         public HostController()         {             InitializeComponent();         }     } }

You have now created a simple form that will act as the user interface for the service host. The next step is to add the code that actually starts and stops the service.

Add logic to start and stop the WCF service

  1. In the ProductsServiceHost project, expand the References folder in Solution Explorer. Notice that the project already contains a reference for the System.ServiceModel assembly required by WCF applications and services.

  2. Add a reference to the image from book ProductsService.dll assembly, located in the Microsoft Press\WCF Step By Step\Chapter 2\ProductsService\ folder under your \My Projects folder. This assembly contains the code that defines the service contract and implements the ProductsService service. It is a copy of the assembly you created in Chapter 1.

  3. In the code view window displaying the C# code behind the HostController form, add the following using statements to the list at the top of the file:

     using System.ServiceModel; using Products;

  4. Add the following variable to the HostController class:

     private ServiceHost productsServiceHost;

    You will use this variable to control the ProductsService service.

  5. In the HostController class, add the following method immediately after the HostController() constructor:

     void onStartClick(object sender, EventArgs e) {     productsServiceHost = new ServiceHost(typeof(ProductsServiceImpl));     productsServiceHost.Open();     stop.IsEnabled = true;     start.IsEnabled = false;     status.Text = "Service Running"; }

    This method is called when the user clicks the Start button on the form. The first line creates a new ServiceHost object. The parameter to the ServiceHost constructor is the type that implements the data contract for the service. The ServiceHost object will retrieve the endpoint containing the binding information containing the address from the application configuration file. The second line of this method starts the service host listening to this endpoint by calling the Open method. The remaining statements in this method enable the Stop button on the form, disable the Start button, and modify the status displayed on the form.

  6. Add the following method to the HostController class:

     void onStopClick(object sender, EventArgs e) {     productsServiceHost.Close();     stop.IsEnabled = false;     start.IsEnabled = true;     status.Text = "Service Stopped"; }

    This method is called when the user clicks the Stop button on the form. The Close method of the ServiceHost object stops it listening for more requests. The other statements re-enable the Start button, disable the Stop button, and update the service status displayed on the form.

  7. Build the solution.

The final step is to provide a configuration file that specifies the binding information for the WCF service. You can reuse the existing configuration file from the original Web service,and rename it as an application configuration file.

Configure the Windows host application

  1. In the Project menu, click Add Existing Item. Move to the Microsoft Press\WCF Step By Step\Chapter 2\Config\ folder under your \My Documents folder, and select the image from book Web.config file. This is a copy of the image from book Web.config file you used for the ProductsService Web service in Chapter 1.

    Tip 

    By default, the Add Existing Item dialog box for a C# project only displays files with a .cs suffix. To display configuration file, select All Files in the Files of type dropdown list box.

  2. In Solution Explorer, rename the image from book Web.config file as image from book App.config.

  3. Open the image from book App.config file, and add the address shown below in bold to the endpoint:

     … <system.serviceModel>     <services>       <service behaviorConfiguration="ProductsBehavior"                name="Products.ProductsServiceImpl">         <endpoint           address="http://localhost:8000/ProductsService/ProductsService.svc"           binding="basicHttpBinding"           contract="Products.IProductsService" />       </service>            </services> </system.serviceModel>

    The address used here specifies port 8000. The default port for the HTTP protocol (port 80) is used by IIS. Attempting to create a new ServiceHost object listening to an address on port 80 will result in an exception unless you stop IIS first.

    Also notice that the address still appears to reference the image from book ProductsService.svc service definition file. However, you have not added this file to the service host application. In fact, a service definition file is only really required by IIS, and is optional if you are creating your own custom host application, as the information required to identify the assembly containing the class that implements the service is specified in the ServiceHost constructor. The address that you specify following the scheme, machine, and port (“ProductsService/ProductsService.svc” in this example) is really just a logical identifier that the WCF service uses to advertise the service to clients, and to which clients can connect. As long as it is valid syntax for a Web URL this part of the address can be almost anything. For consistency, when using the http scheme, it is worthwhile retaining the service definition file element as part of the address in case you revert back to using IIS to host the service.

    Note 

    This only applies to endpoints that use the HTTP and HTTPS transports. If you use a different mechanism, such as TCP, avoid referencing what looks like a filename in addresses.

  4. Build the solution again. This action will generate the ProductsService.exe.config configuration file from the image from book App.config file.

You can reuse the client application that you created for testing the ProductsService Web service in Chapter 1 (a copy is supplied for this exercise) with one small change–you must modify the address of the service in the application configuration file.

Test the Windows host application

  1. In Solution Explorer, right-click the ProductsServiceHost solution, point to Add, and then click Existing Project.

  2. Move to the Microsoft Press\WCF Step By Step\Chapter 2\ProductsClient\ folder under your \My Documents folder, and select the ProductsClient project file.

  3. In the ProductsClient project in Solution Explorer, right-click the image from book App.config file and click Edit WCF Configuration.

    The WCF Service Configuration Editor starts. This editor provides a graphical means of editing a configuration file for a WCF service and client application. You can still edit the configuration file manually if you prefer, but using this tool can reduce the scope for many of the common configuration errors.

  4. In the WCF Service Configuration Editor, in the tree view in the Configuration pane in the left pane, select the BasicHttpBinding_IProductsService endpoint in the Endpoints folder under the Client folder. It should look like this, although the name of your computer in the Address field will probably be different:

    image from book

  5. In the Client Endpoint pane on the right side of the window, change the Address property to http://localhost:8000/ProductsService/ProductsService.svc.

    Note 

    Remember that this is a URL, or a logical address. Unlike the IIS implementation, there is not actually a physical file called ProductService.svc in this version of the ProductsService service. The service host just happens to be listening on an endpoint with an address that looks like a filename.

  6. On the File menu, click Save, and then exit the WCF Service Configuration Editor.

    Note 

    When you return to Visual Studio 2005, if you had the image from book App.config file open in a code view window, Visual Studio 2005 will detect that the contents of the file have changed and alert you with a message box displaying, “The file has been modified outside the source editor. Do you want to reload it?” Click Yes, otherwise you risk losing the changes you have made by using the WCF Service Configuration Editor.

  7. In Solution Explorer, double-click the image from book Program.cs file in the ProductsClient project. Add the statements shown in bold to the Main method of the Program class:

     static void Main(string[] args) {     Console.WriteLine("Press ENTER when the service has started");     Console.ReadLine();     // Create a proxy object and connect to the service     ProductsServiceClient proxy = new         ProductsServiceClient("BasicHttpBinding_IProductsService");    }

    These statements wait for the user to press the Enter key before creating the proxy object that connects to the service. This will give you time to start the service running.

  8. Build the solution.

  9. In Solution Explorer, right-click the ProductsServiceHost solution, and then click Set StartUp Projects.

  10. In the Property Pages dialog box, click Multiple startup projects, set the Action for the ProductsClient and the ProductsServiceHost projects to Start, and then click OK.

  11. On the Debug menu, click Start Without Debugging to start both projects running.

  12. In the ProductsServiceHost form, click Start, and wait for the Service Status text box to change to Service Running.

  13. In the console window running the ProductsClient application, press Enter. The application should run exactly as before, displaying a list of product numbers, displaying the details of product WB-H098, and then displaying and updating the stock level for this product.

  14. Press Enter again to close the ProductsClient application. Close the ProductsServiceHost form.

Reconfiguring the Service to Use Multiple Endpoints

The HTTP protocol is a good choice to use as a transport for connecting to Web services. However, when accessing a service deployed within an organization, the TCP protocol can prove to be more efficient. If you want to maintain connectivity and network performance inside and outside an organization, you should consider providing multiple endpoints: one for external clients accessing the service by using HTTP, and another for internal clients accessing the service by using TCP. This is what you will do in the next set of exercises.

Add a TCP endpoint to the WCF service

  1. In Solution Explorer, in the ProductsServiceHost project, right-click the image from book App.config file for the ProductsServiceHost project, and then click Edit WCF Configuration.

  2. In the WCF Service Configuration Editor, in the Configuration pane, expand the Products.ProductServiceImpl folder in the Services folder, and then expand the Endpoints folder. The existing endpoint is listed, with the name (Empty Name).

  3. Click the (Empty Name) endpoint. In the Service Endpoint pane, set the Name property to ProductsServiceHttpEndpoint.

  4. In the Configuration pane, right-click the Endpoints folder, and then click New Service Endpoint.

  5. In the Service Endpoint pane, set the properties of the endpoint using the values in the following table:

    Open table as spreadsheet

    Property

    Value

    Name

    ProductsServiceTcpEndpoint

    Address

    net.tcp://localhost:8080/TcpProductsService

    Binding

    netTcpBinding

    Contract

    Products.IProductsService

    Tip 

    If you click the ellipses button in the Contract field, you can search for the assembly containing the contract by using the Contract Type Browser. When you select an assembly, the Contract Type Browser will display all the contracts available in the assembly.

  6. Save the updated configuration, and then exit the WCF Service Configuration Editor.

  7. Examine the image from book App.config file by opening it in the code view window. Notice that the new endpoint has been added to the service, as follows:

     <services>       <service behaviorConfiguration="ProductsBehavior" name="Products.ProductsService Impl">         <endpoint address="" binding="basicHttpBinding" name="ProductsServiceHttpEndpo int" contract="Products.IProductsService" />         <endpoint address="net.tcp://localhost:8080/TcpProductsService" binding="netTcpBinding" bindingConfiguration="" name="ProductsServiceTcpEndpoint" contract="Products.IProductsService" />      </service> </services>

    When the host application instantiates the ServiceHost object, it automatically creates an endpoint for each entry in the configuration file.

Reconfigure the client to connect to the TCP endpoint

  1. In Solution Explorer, edit the image from book app.config file for the ProductsClient project by using the WCF Service Configuration Editor.

  2. In the WCF Service Configuration Editor, in the Client folder, right-click the Endpoints folder, and then click New Client Endpoint.

  3. In the Client Endpoint pane, set the properties of the endpoint using the values in the following table:

    Open table as spreadsheet

    Property

    Value

    Name

    NetTcpBinding_IProductsService

    Address

    net.tcp://localhost:8080/TcpProductsService

    Binding

    netTcpBinding

    Contract

    ProductsClient.ProductsService.IProductsService

    Note 

    The type defining the contract is part of the proxy code generated for the client in Chapter 1. This type was compiled into the client executable assembly, ProductsClient.exe, located in the bin\Debug folder underneath the client project folder.

  4. Save the client configuration file and exit the WCF Service Configuration Editor.

  5. Examine the image from book app.config file by opening it in the code view window. Notice that the new endpoint has been added to the client, as follows:

     <client>     <endpoint         address="http://localhost:8000/ProductsService/ProductsService.svc"         binding="basicHttpBinding"         bindingConfiguration="BasicHttpBinding_IProductsService"         contract="ProductsClient.ProductsService.IProductsService"         name="BasicHttpBinding_IProductsService" />     <endpoint         address="net.tcp://localhost:8080/TcpProductsService"         binding="netTcpBinding" bindingConfiguration=""         contract="ProductsClient.ProductsService.IProductsService"         name="NetTcpBinding_IProductsService" /> </client>

  6. Edit the image from book Program.cs file in the ProductsClient project. In the Main method, modify the statement that instantiates the proxy object to use the TCP endpoint, as follows:

     // Create a proxy object and connect to the service ProductsServiceClient proxy = new     ProductsServiceClient("NetTcpBinding_IProductsService");

  7. Build the solution.

Test the new endpoint

  1. On the Debug menu, click Start Without Debugging to start both projects running.

  2. In the ProductsServiceHost form, click Start, and wait for the Service Status text box to change to Service Running.

    Note 

    If you are running Windows Firewall, a Windows Security Alert will appear. In the alert, click Unblock to allow the service to open the TCP port.

  3. In the console window running the ProductsClient application, press Enter. The application should run exactly as before. This time, however, the client is connecting to the service by using the TCP protocol.

  4. Press Enter again to close the ProductsClient application. Close the ProductsServiceHost form.




Microsoft Windows Communication Foundation Step by Step
Microsoft Windows Communication Foundation Step by Step (Step By Step Developer Series)
ISBN: 0735623368
EAN: 2147483647
Year: 2007
Pages: 105
Authors: John Sharp

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