Hosting a WCF Service in a user application relies on the user starting and stopping the service and not logging off. A better solution is to host a WCF service in a Windows service. This way, you can configure the Windows service to run automatically when Windows starts, but an administrator can still stop and restart the service if required.
Important | The exercises in this section require that you have Administrator access to your computer. If you do not have this level of access, you will not be able to install, start, and stop Windows services. |
In the exercises in this section, you will create a Windows service to act as a host for the ProductsService service. This service will limit requests only to client applications running on the same computer, and so you will configure it to use the named pipe transport listening to a fixed address.
More Info | The exercises in this section assume you are familiar with how Windows services function, and that you understand how to use Windows Service Visual Studio template to create a new service. Windows services are distinct from WCF services, and a detailed discussion of how they work is outside the scope of this book. For further information about creating Windows services see the “Windows Service Applications” section in the Visual Studio 2005 Help documentation. |
Using Visual Studio 2005, create a new project. Select the Windows project types, and use the Windows Service template. Name the project WindowsProductsService and save it in the Microsoft Press\WCF Step By Step\Chapter 2 folder under your \My Projects folder.
Using Solution Explorer, change the name of the Service1.cs to ServiceHostController.cs.
Add a reference to the System.ServiceModel assembly.
Add a reference to the ProductsService.dll assembly, located in the Microsoft Press\WCF Step By Step\Chapter 2\ProductsService folder under your \My Projects folder.
In the Project menu, click Add Existing Item and add the Web.config file located in the Microsoft Press\WCF Step By Step\Chapter 2\Config folder under your \My Projects folder to the project.
Rename the Web.config file as App.config.
Edit the App.config file and remove the <system.serviceModel> section. The file should look like this:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary. Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" /> </configSections> <dataConfiguration defaultDatabase="AdventureWorksConnection" /> <connectionStrings> <add name="AdventureWorksConnection" connectionString="Database=AdventureWorks ;Server=(local)\SQLEXPRESS;Integrated Security=SSPI;" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>
In the earlier exercises, you provided a URI and used the configuration file to associate the URI with a binding. You have just removed this configuration information. In the next exercise, you will bind the service to an endpoint by using code; the Windows service will use a named pipe for its endpoint because you want to restrict access to local client applications only.
Open the ServiceHostController.cs file. In the design view window, click the link to switch to the code view.
In the code view window, add the following using statements to the list at the top of the file:
using System.ServiceModel; using Products;
Add the following variable to the ServiceHostController class:
private ServiceHost productsServiceHost;
You will use this variable to control the ProductsService service.
Add the following statements shown in bold to the ServiceHostController constructor:
public ServiceHostController() { InitializeComponent(); // The name of the service that appears in the Registry this.ServiceName = "Products Service"; // Allow an administrator to stop (and restart) the service this.CanStop = true; // Report Start and Stop events to the Windows event log this.AutoLog = true; }
Add the code shown in bold to the OnStart method of the ServiceHostController class, replacing the TODO comment in this method:
protected override void OnStart(string[] args) { productsServiceHost = new ServiceHost(typeof(ProductsServiceImpl)); }
This statement creates a new instance of the ProductsService service, but remember that the App.config file does not specify an address or binding. You will supply the endpoint information for the service in the next step.
Add the statements shown below in bold to the OnStart method, after creating the productsServiceHost object:
protected override void OnStart(string[] args) { productsServiceHost = new ServiceHost(typeof(ProductsServiceImpl)); NetNamedPipeBinding binding = new NetNamedPipeBinding(); productsServiceHost.AddServiceEndpoint(typeof(IProductsService), binding, "net.pipe://localhost/ProductsServicePipe"); productsServiceHost.Open(); }
The first statement creates a NetNamedPipeBinding object. The second statement creates a new endpoint using this binding. It associates the binding with the “//localhost/ProductsServicePipe” named pipe and specifies that the service listening to the pipe implements the IProductsService service contract. The code then opens the service and waits for clients to connect.
Add the code shown in bold to the OnStop method of the ServiceHostController class, replacing the TODO comment in this method:
protected override void OnStop() { productsServiceHost.Close(); }
This statement closes the service when the service is shut down. Remember that WCF closes services gracefully, so the Close method can take some time to perform.
In the next exercise, you will add an installer for the Windows service. You will configure the service to run using the LocalSystem account. If you want to select a different account, ensure that the account you specify has access to the tables in the AdventureWorks database.
In Solution Explorer, double-click the ServiceHostController.cs file to display the class in the design view window.
Right-click the design view, and then click Add Installer.
The service installer is created and displays the serviceProcessInstaller1 and serviceInstaller1 components in the design view window.
Click the serviceInstaller1 component. In the Properties window, set the ServiceName property to ProductsService, and set the StartType property to Automatic.
In the design view window, click the serviceProcessInstaller1 component. In the Properties window, set the Account property to LocalSystem.
Build the solution.
The next stage is to install the service and start it running.
On the Windows Start menu, point to All Programs, point to Microsoft Visual Studio 2005, point to Visual Studio Tools, and then click Visual Studio 2005 Command Prompt.
In the Visual Studio 2005 Command Prompt window, move to the folder Microsoft Press\WCF Step By Step\Chapter 2\WindowsProductService\WindowsProductService\bin\Debug under your \My Documents folder.
Run the following command to install the WindowsProductsService service:
installutil WindowsProductsService.exe
The installutil utility outputs messages indicating the progress of the installation process. Verify that the service is installed successfully, without reporting any errors.
Using the Windows Control Panel, click Performance and Maintenance, click Administrative Tools, and double-click the Services applet.
Note | If you are using Windows Vista, use click System and Maintenance in the Control Panel rather than Performance and Maintenance. |
In the Services window, verify that the ProductsService service is present and configured using the property values specified by the service installer:
Start the service.
In the final exercise, you will use another copy of the ProductsClient application to test the Windows service. You will reconfigure the ProductsClient application to connect to the Windows service and verify that the service functions correctly.
Return to Visual Studio editing the WindowsProductsService solution. Add the ProductsClient project in the Microsoft Press\WCF Step By Step\Chapter 2\ProductsClient\ folder under your \My Documents folder, to the WindowsProductsService solution.
Edit the app.config file for the ProductsClient project by using the WCF Service Configuration Editor. In the Client folder, right-click the Endpoints node, and then click New Client Endpoint. Add a new client endpoint with the following property values:
Property | Value |
---|---|
Name | NetNamedPipeBinding_IProductsService |
Address | net.pipe://localhost/ProductsServicePipe |
Binding | netNamedPipeBinding |
Contract | ProductsClient.ProductsService.IProductsService |
Save the client configuration file and exit the WCF Service Configuration Editor.
Edit the Program.cs file. In the Main method, modify the statement that instantiates the proxy object to use the named pipe endpoint, as follows:
// Create a proxy object and connect to the service ProductsServiceClient proxy = new ProductsServiceClient("NetNamedPipeBinding_IProductsService");
Build the solution.
In Solution Explorer, right-click the ProductsClient project and then click Set as StartUp Project.
On the Debug menu, click Start Without Debugging to start the client application running. Press Enter in the client console window.
The ProductsClient application should run exactly as before. This time, however, the client is communicating with the WCF service running in the Windows service by using a named pipe.
Press Enter to close the ProductsClient application.
Return to the Services applet and stop the ProductsService service.
If you want to verify that the client application uses the Windows service and not some other instance of the ProductsService service that might be running (such as the Web service), try running the client after stopping the Windows service. It should fail with an EndpointNotFoundException stating that there is no endpoint listening at the address net.pipe://localhost/ProductsServicePipe.
Tip | You can uninstall the WindowsProductsService service by executing the command installutil /u WindowsProductsService.exe in a Visual Studio 2005 Command Prompt Window, in the bin\Debug folder for the WindowsProductsService project. |