Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro CSharp 2008 And The .NET 3.5 Platform [eng]

.pdf
Скачиваний:
78
Добавлен:
16.08.2013
Размер:
22.5 Mб
Скачать

902 CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

Figure 25-12. Testing the WCF service using WcfTestClient.exe

Once you do, you will be able to invoke ObtainAnswerToQuestion() in a similar manner.

Altering Configuration Files Using SvcConfigEditor.exe

Another benefit of making use of the WCF Service Library project is that you are able to right-click on the App.config file within the Solution Explorer to activate the GUI-based Service Configuration Editor, SvcConfigEditor.exe (see Figure 29-13). This same technique can be used from a client application that has referenced a WCF service.

Figure 25-13. GUI-based *.config file editing starts here.

Once you activate this tool, you are able to change the XML-based data using a friendly user interface. There are many obvious benefits of using a tool such as this to maintain your *.config files. First and foremost, you can rest assured that the generated markup conforms to the expected format and is typo-free. Next, it is a great way to see the valid values that could be assigned to a given attribute. Last but not least, you no longer need to manually author tedious XML data.

CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

903

Figure 25-14 shows the overall look and feel of the Service Configuration Editor. Truth be told, an entire chapter could be written describing all of the interesting options SvcConfigEditor.exe supports (COM+ integration, creation of new *.config files, etc.). Be sure to take time to investigate this tool, and be aware that you can access a fairly detailed help system by pressing F1.

Note The SvcConfigEditor.exe utility can edit (or create) configuration files even if you do not select an initial WCF Service Library project. Using a Visual Studio 2008 command window, launch the tool and make use of the File Open menu option to load an existing *.config file for editing.

Figure 25-14. Working with the WCF Service Configuration Editor

We have no need to further configure our WCF MathService, so at this point we can move on to the task of building a custom host.

Hosting the WCF Service As a Windows Service

As you might agree, hosting a WCF service from within a console application (or within a GUI desktop application, for that matter) is not an ideal choice for a production-level server, given that the host must remain running visibly in the background to service clients. Even if you were to minimize the hosting application to the Windows taskbar, it would still be far too easy to accidentally shut down the host, thereby terminating the connection with any client applications.

904 CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

Note While it is true that a desktop Windows application does not have to show a main window, a typical *.exe does require user interaction to load the executable. A Windows service (described next) can be configured to run even if no users are currently logged on to the workstation.

If you are building an in-house WCF application, another alternative is to host your WCF service library from within a dedicated Windows service. One benefit of doing so is that a Windows service can be configured to automatically start when the target machine boots up. Another benefit is that Windows services run invisibly in the background (unlike our console application) and do not require user interactivity.

To illustrate how to build such a host, begin by creating a new Windows service project named MathWindowsServiceHost (see Figure 25-15). Once you have done so, rename your initial Service1. cs file to MathWinService.cs using Solution Explorer.

Figure 25-15. Creating a Windows service to host our WCF service

Specifying the ABCs in Code

Now, assuming you have set a reference to your MathServiceLibrary.dll and System.ServiceModel. dll assemblies, all you need to do is make use of the ServiceHost type within the OnStart() and OnStop() methods of your Windows service type. Open the code file for your service host class (by right-clicking the designer and selecting View Code), and add the following logic:

// Be sure to import these namespaces: using MathServiceLibrary;

using System.ServiceModel;

CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

905

public partial class MathWinService: ServiceBase

{

// A member variable of type ServiceHost. private ServiceHost myHost;

public MathWinService()

{

InitializeComponent();

}

protected override void OnStart(string[] args)

{

//Just to be really safe. if (myHost != null)

{

myHost.Close(); myHost = null;

}

//Create the host.

myHost = new ServiceHost(typeof(MathService));

// The ABCs in code!

Uri address = new Uri("http://localhost:8080/MathServiceLibrary"); WSHttpBinding binding = new WSHttpBinding();

Type contract = typeof(IBasicMath);

//Add this endpoint. myHost.AddServiceEndpoint(contract, binding, address);

//Open the host.

myHost.Open();

}

protected override void OnStop()

{

// Shut down the host. if(myHost != null)

myHost.Close();

}

}

While nothing is preventing you from using a configuration file when building a Windows service host for a WCF service, here (for a change of pace) notice that you are programmatically establishing the endpoint using the Uri, WSHttpBinding, and Type classes, rather than making use of a *.config file. Once you have created each aspect of the ABCs, you inform the host programmatically by calling AddServiceEndpoint().

Enabling MEX

While we could enable MEX programmatically as well, we will opt for a configuration file. Insert a new App.config file into your Windows service project that contains the following MEX settings:

<?xml version="1.0" encoding="utf-8" ?> <configuration>

<system.serviceModel>

<services>

906 CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

<service name="MathServiceLibrary.MathService" behaviorConfiguration = "MathServiceMEXBehavior">

<!-- Enable the MEX endpoint -->

<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

<!-- Need to add this so MEX knows the address of our service -->

<host>

<baseAddresses>

<add baseAddress ="http://localhost:8080/MathService"/> </baseAddresses>

</host>

</service>

</services>

<!--

A behavior definition for MEX --

>

<behaviors>

<serviceBehaviors>

<behavior name="MathServiceMEXBehavior" > <serviceMetadata httpGetEnabled="true" />

</behavior>

</serviceBehaviors>

</behaviors>

</system.serviceModel>

</configuration>

Creating a Windows Service Installer

In order to register your Windows service with the operating system, you need to add an installer to your project that will contain the necessary code to allow you to register the service. To do so, simply right-click the Windows service designer surface and select Add Installer (see Figure 25-16).

Figure 25-16. Adding an installer for the Windows service

Once you have done so, you will see two components have been added to a new designer surface. The first component (named serviceProcessInstaller1 by default) represents a type that is able to install a new Windows service on the target machine. Select this type on the designer and use the Properties window to set the Account property to LocalSystem.

CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

907

The second component (named serviceInstaller1) represents a type that will install your particular Windows service. Again, using the Properties window, change the ServiceName property to Math Order Service (as you might have guessed, this represents the friendly display name of the registered Windows service), set the StartType property to Automatic, and add a friendly description of your Windows service via the Description property. At this point you can compile your application.

Installing the Windows Service

A Windows service can be installed on the host machine using a traditional setup program (such as an *.msi installer) or via the installutil.exe command-line tool. Using a Visual Studio 2008 command prompt, change into the \bin\Debug folder of your MathWindowsServiceHost project. Now, enter the following command:

installutil MathWindowsServiceHost.exe

Assuming the installation succeeded, you can now open the Services applet located under the Administrative Tools folder of your Control Panel. You should see the friendly name of your Windows service listed alphabetically. Once you locate it, you can start the service on your local machine (see Figure 25-17).

Figure 25-17. Viewing our Windows service, which is hosting our WCF service

Now that the service is alive and kicking, the last step is to build a client application to consume its services.

Source Code The MathWindowsServiceHost project is located under the Chapter 25 subdirectory.

908 CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

Invoking a Service Asynchronously

Create a new Console Application named MathClient and set a Service Reference to your running WCF service that is current hosted by the Windows service running in the background using the Add Service Reference option of Visual Studio. Don’t click the OK button yet, however (see

Figure 25-18).

Figure 25-18. Referencing our MathService

Notice that the Add Service Reference dialog box has an Advanced button in the lower-left corner. Click this button now to view the additional proxy configuration settings (see Figure 25-19).

Using this dialog box, we can elect to generate code that allows us to call the remote methods in an asynchronous manner, provided we check the Generate Asynchronous Operators check box. Go ahead and check this option for the time being.

The other option on this dialog box you should be aware of is the Add Web Reference button. If you have a background in building XML web services in Visual Studio 2005 or earlier, you may recall that you had an Add Web Reference option rather than an Add Service Reference option. If you click this particular button, you will be able to receive proxy code that will allow you to communicate with a traditional web service described within an *.asmx file.

The remaining options of this dialog box are used to control the generation of data contracts, which we will examine a bit later in this chapter. In any case, be sure you did indeed check the Generate Asynchronous Operators check box and click OK on each dialog box to return to the Visual Studio IDE.

CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

909

Figure 25-19. Advanced client-side proxy configuration options

At this point, the proxy code will contain additional methods that allow you to invoke each member of the service contract using the expected Begin/End asynchronous invocation pattern described in Chapter 18. Here is a simple implementation that makes use of a lambda expression rather than a strongly typed AsyncCallback delegate.

using System;

using MathClient.ServiceReference; using System.Threading;

namespace MathClient

{

class Program

{

static void Main(string[] args)

{

Console.WriteLine("***** The Async Math Client *****\n");

using (BasicMathClient proxy = new BasicMathClient())

{

proxy.Open();

// Add numbers in an async manner, using a lambda expression.

IAsyncResult result = proxy.BeginAdd(2, 3, ar =>

910 CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

{

Console.WriteLine("2 + 5 = {0}", proxy.EndAdd(ar)); }, null);

while (!result.IsCompleted)

{

Thread.Sleep(200); Console.WriteLine("Client working...");

}

}

Console.ReadLine();

}

}

}

Source Code The MathClient project is located under the Chapter 25 subdirectory.

Designing WCF Data Contracts

This chapter’s final example involves the construction of WCF data contracts. The previous WCF services defined very simple methods that operate on primitive CLR data types. When you are making use of any of the web service–centric binding types (basicHttpBinding, wsHttpBinding, etc.), incoming and outgoing data types are automatically formatted into XML elements using the

System.Runtime.Serialization.XmlFormatter type defined within the System.Runtime. Serialization.dll assembly. On a related note, if you make use of a TCP-based binding (such as netTcpBinding), the parameters and return values of simple data types are transmitted using a compact binary format.

Note The WCF runtime will also automatically encode any type marked with the [Serializable] attribute.

However, when you define service contracts that make use of custom types as parameters or return values, these types must be defined using a data contract. Simply put, a data contract is a type adorned with the [DataContract] attribute. Each field you expect to be used as part of the proposed contract is likewise marked with the [DataMember] attribute.

Note If a data contract contains fields not marked with the [DataMember] attribute, it will not be serialized by the WCF runtime.

To illustrate the construction of data contracts, let’s create a brand-new WCF service that interacts with the AutoLot database created back in Chapter 22. As well, this final WCF service will be created using the web-based WCF Service template. Recall that this type of WCF service will automatically be placed into an IIS virtual directory, and it will function in a similar fashion to a traditional .NET XML web service. Once you understand the composition of such a WCF service, you should have little problem porting an existing WCF service into a new IIS virtual directory.

CHAPTER 25 INTRODUCING WINDOWS COMMUNICATION FOUNDATION

911

Note This example assumes you are somewhat comfortable with the structure of an IIS virtual directory (and IIS itself). If this is not the case, Chapter 31 will examine the details.

Using the Web-Centric WCF Service Project Template

Using the File New Web Site menu option, create a new WCF service named AutoLotWCFService, exposed from the following URI: http://localhost/AutoLotWCFService (see Figure 25-20). Be sure the Location drop-down list has HTTP as the active selection.

Figure 25-20. Creating a web-centric WCF service

Once you have done so, set a reference to the AutoLotDAL.dll assembly you created in Chapter 22 (via the Website Add Reference menu option). Much like a WCF Service Library project, you have been given some example starter code (located under the App_Code folder), which you will obviously want to delete. To begin, rename the initial IService.cs file to IAutoLotService. cs, and define the initial service contract within your newly named file:

[ServiceContract]

public interface IAutoLotService

{

[OperationContract]

void InsertCar(int id, string make, string color, string petname);

[OperationContract]

void InsertCar(InventoryRecord car);

[OperationContract] InventoryRecord[] GetInventory();

}