Home .NET Example of creating a WCF service running inside a Windows service

Example of creating a WCF service running inside a Windows service

by admin

Windows Communication Foundation is a software platform from Microsoft for creating, configuring and deploying distributed network services. WCF-runtime and its namespace System.ServiceModel, which represents its main program interface, is the successor of distributed systems creation technologies successfully used by developers to create distributed applications on the Windows platform during the last decade. Let’s take a test example of WCF service creation.
Open Visual Studio 2015 and create a new project of the Class Library type. Let’s call the project WCFMyServiceLibrary.
Example of creating a WCF service running inside a Windows service
Let’s rename the file Class1.cs to MyService.cs and add another class, the file for which we call IMyService.cs.
Let’s add a reference to the assembly of System.ServiceModel.
In the file IMyService.cs describe the interface :

using System.ServiceModel;namespace WCFMyServiceLibrary{[ServiceContract]public interface IMyService{[OperationContract]string Method1(string x);[OperationContract]string Method2(string x);}}

In the file MyService.cs let’s describe the implementation of the interface :

namespace WCFMyServiceLibrary{public class MyService : IMyService{public string Method1(string x){string s = $"1 You entered: {x}= = = 1";return s;}public string Method2(string x){string s = $"2 you entered: {x}= = = 2";return s;}}}

This completes the design of the service. Let’s move on to creating the Windows service which will be the container for this service.
In the same Solution, create a new project of the "Windows Service" type. Let’s call the project WindowsServiceHostForMyService.
Example of creating a WCF service running inside a Windows service
Then let’s rename the file Service1.cs (of the newly created project) to MyService.cs. In this project we will add a reference to the assembly System.ServiceModel, and also do not forget to specify in the file MyService.cs directives :

using System.ServiceModel;using System.ServiceModel.Description;

In the MyService class we add a new member :

private ServiceHost service_host = null;

You should also add a link to the WCFMyServiceLibrary project, which is in the same solution :
Example of creating a WCF service running inside a Windows service
Then in the MyService class let’s change the OnStart method so that our service endpoints are added in this method:
OnStart method

protected override void OnStart(string[] args){if (service_host != null) service_host.Close();string address_HTTP = "http://localhost:9001/MyService";string address_TCP = "net.tcp://localhost:9002/MyService";Uri[] address_base = { new Uri(address_HTTP), new Uri(address_TCP) };service_host = new ServiceHost(typeof(WCFMyServiceLibrary.MyService), address_base);ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();service_host.Description.Behaviors.Add(behavior);BasicHttpBinding binding_http = new BasicHttpBinding();service_host.AddServiceEndpoint(typeof(WCFMyServiceLibrary.IMyService), binding_http, address_HTTP);service_host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");NetTcpBinding binding_tcp = new NetTcpBinding();binding_tcp.Security.Mode = SecurityMode.Transport;binding_tcp.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;binding_tcp.Security.Message.ClientCredentialType = MessageCredentialType.Windows;binding_tcp.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;service_host.AddServiceEndpoint(typeof(WCFMyServiceLibrary.IMyService), binding_tcp, address_TCP);service_host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");service_host.Open();}

Then we implement the service stop in the onStop method:

protected override void OnStop(){if (service_host != null){service_host.Close();service_host = null;}}

Then in the Solution Browser, double-clicking on the file MyService.cs (of the WindowsServiceHostForMyService project) will open that file in Design Mode.
Example of creating a WCF service running inside a Windows service
On the empty space, call the context menu (right-click) and select "Add Installer".
Example of creating a WCF service running inside a Windows service
This will create a new class ProjectInstaller.cs
Rename the ProjectInstaller.cs file to MyServiceInstaller.cs.
This will bring up a window asking if you want to rename the dependent objects – answer "yes".
Let’s add a link to the file

using System.ServiceProcess;

Then let’s change the code of the constructor of the MyServiceInstaller class:

public MyServiceInstaller(){// InitializeComponent();serviceProcessInstaller1 = new ServiceProcessInstaller();serviceProcessInstaller1.Account = ServiceAccount.LocalSystem;serviceInstaller1 = new ServiceInstaller();serviceInstaller1.ServiceName = "WindowsServiceHostForMyService";serviceInstaller1.DisplayName = "WindowsServiceHostForMyService";serviceInstaller1.Description = "WCF Service Hosted by Windows NT Service";serviceInstaller1.StartType = ServiceStartMode.Automatic;Installers.Add(serviceProcessInstaller1);Installers.Add(serviceInstaller1);}

Note that we have blocked the InitializeComponent() method call with a comment.
This completes the development of the Windows service. Let’s build the whole solution and move on to the next step which is installing the Windows service.
To install our service, create a bat file (with an arbitrary name, for example Install_Windows_Service.bat) of the following content :

C:WindowsMicrosoft.NETFrameworkv4.0.30319InstallUtil.exe WindowsServiceHostForMyService.exe

You need to copy this bat-file to the same folder where the compiled file WindowsServiceHostForMyService.exe is located (you need to think beforehand in which folder this file will be, which will always run as a Windows service).
Run the bat-file, then our program WindowsServiceHostForMyService.exe will be installed as a Windows service.
Let’s start this service with the standard service management program.
The next step is to develop a client application to use the services provided by the service.
To do this, you first need to set up a so-called "adapter" – Service Proxy – a set of settings that describe the service for the client application.
Let’s use the standard utility SvcUtil.exe for this. Let’s create the Generate_Proxy.bat file with the following content

SvcUtil http://localhost:9001/MyService /out:MyServiceProxy.cs /config:App.config

Run this file (the standard utility SvcUtil.exe is located in the folder C:Program FilesMicrosoft SDKsWindowsv7.0Bin).
This file needs to be run while our service is running, which in this case is after the WindowsServiceHostForMyService has successfully started.
If run successfully, SvcUtil.exe will generate 2 files – MyServiceProxy.cs and App.config.
These files need to be added for the client application so that the client application can call methods of our service (you will find below that I decided not to add the App.config file, we can live without it).
Note. A similar result could have been achieved by running

SvcUtil net.tcp://localhost:9002/MyService /out:MyServiceProxy.cs /config:App.config

I.e. you can run this utility by specifying only one endpoint, either http or net.tcp.
In the same solution, create a normal Windows Forms application. Let’s call it WindowsFormsApplication1
Example of creating a WCF service running inside a Windows service
Let’s add a reference to System.ServiceModel to this project and, of course,

using System.ServiceModel in the form file.

Let’s add the MyServiceProxy.cs file to this project (it is what we generated with the SvcUtil.exe utility). You should add the following lines into file MyServiceProxy.cs :

namespace ServiceReference1{using System.Runtime.Serialization;using System;... then comes the contents of the file MyServiceProxy.cs ...and of course don't forget to put a closing parenthesis for namespace}

After that, we can refer to the class MyServiceClient (this class was created by SvcUtil.exe) by specifying the directive in the form file.

using ServiceReference1;

An example of finished MyServiceProxy.cs file (comments removed):

namespace ServiceReference1{using System.Runtime.Serialization;using System;[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")][System.ServiceModel.ServiceContractAttribute(ConfigurationName="IMyService")]public interface IMyService{[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService/Method1", ReplyAction="http://tempuri.org/IMyService/Method1Response")]string Method1(string x);[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService/Method2", ReplyAction="http://tempuri.org/IMyService/Method2Response")]string Method2(string x);}[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]public interface IMyServiceChannel : IMyService, System.ServiceModel.IClientChannel{}[System.Diagnostics.DebuggerStepThroughAttribute()][System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]public partial class MyServiceClient : System.ServiceModel.ClientBase<IMyService> , IMyService{public MyServiceClient(){}public MyServiceClient(string endpointConfigurationName) :base(endpointConfigurationName){}public MyServiceClient(string endpointConfigurationName, string remoteAddress) :base(endpointConfigurationName, remoteAddress){}public MyServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :base(endpointConfigurationName, remoteAddress){}public MyServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :base(binding, remoteAddress){}public string Method1(string x){return base.Channel.Method1(x);}public string Method2(string x){return base.Channel.Method2(x);}}}

Let’s do something unconventional and not add the App.Config file to the client project!
Then let’s put 3 buttons on the form, textBox1 (the user enters here a string to be sent to the server) and richTextbox1 (an imitation of our application’s message subsystem – this is where the service will receive messages from the program, including those returned to us)
Button btn_Start – creates a client
Button btn_Send – sends a text string from a text field to the service
The button btn_Close – removes the client from memory and closes the application
Form Code :

using System;using System.ServiceModel;using System.Windows.Forms;using ServiceReference1;namespace WindowsFormsApplication1{public partial class Form1 : Form{MyServiceClient client = null;public Form1(){InitializeComponent();}private void Print(string text){richTextBox1.Text += text + "nn";richTextBox1.SelectionStart = richTextBox1.Text.Length;richTextBox1.ScrollToCaret();}private void Print(Exception ex){if (ex == null) return;Print(ex.Message);Print(ex.Source);Print(ex.StackTrace);}private void Create_New_Client(){if (client == null)try { Try_To_Create_New_Client(); }catch (Exception ex){Print(ex);Print(ex.InnerException);client = null;}else{Print("Cannot create a new client. The current Client is active.");}}private void Try_To_Create_New_Client(){try{NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport);binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;string uri = "net.tcp://192.168.1.2:9002/MyService";EndpointAddress endpoint = new EndpointAddress(new Uri(uri));client = new MyServiceClient(binding, endpoint);client.ClientCredentials.Windows.ClientCredential.Domain = "";client.ClientCredentials.Windows.ClientCredential.UserName = "Vasya";client.ClientCredentials.Windows.ClientCredential.Password = "12345";Print("Creating new client ....");Print(endpoint.Uri.ToString());Print(uri);string test = client.Method1("test");if (test.Length < 1){throw new Exception("Connection check failed");}else{Print("test is OK ! " + test);}}catch (Exception ex){Print(ex);Print(ex.InnerException);client = null;}}private void btn_Start_Click(object sender, EventArgs e){Create_New_Client();}private void btn_Send_Click(object sender, EventArgs e){Print("sending message . . .");string s = textBox1.Text;string x = "";if (client != null){x = client.Method1(s);Print(x);x = client.Method2(s);Print(x);}else{Print("Error! Client does not exist!");}}private void btn_Close_Click(object sender, EventArgs e){if (client != null){Print("Closing a client ...");client.Close();client = null;}else{Print("Error! Client does not exist!");}this.Close();}}}

Compile and run from another machine on the same network – and test the service by first pressing btn_Start and then sending messages to the service by pressing btn_Send.
Example of creating a WCF service running inside a Windows service
Note that in this example on the client we did not use the endpoint at all
http://localhost:9001/MyService
and have only worked with
net.tcp://localhost:9002/MyService
(you can easily do it yourself – since you can do net.tcp, you can do http with a blind eye).
In addition, we didn’t use the App.config file and created the endpoint on the client using C# code instead of settings. The reasons for that are subjective – the author doesn’t like to mess around with XML settings and does everything explicitly in the code, if possible. Thanks for your attention!
Lyrical digression. The author of this article got acquainted with C# in March of this year, and wrote his first C# application in May (before that he was using Delphi and even MS Access for many years).

You may also like