Web application developer

Self hosting WCF service

wcf console application

Written by: willem | Nov 21 2014 1:57 PM

In this final post of my series about WCF I will show you how to make a WCF service available by hosting it in executable code. In the example I use a console application. In a real world situation this should be a windows service but for debugging purposes and since this is only a proof of concept I use a console app.

Hosting a WCF service in executable code requires extra permissions to access some namespaces that we need. Configuring this is outside the scope of this article so to keep it simple make sure you run Visual Studio as administrator.

I use the code of the previous post and will add a self hosting service project. You can download the solution here.

Open the solution in Visual Studio. Right click the solution and choose add –> new project.

001

Select C# and choose Console Application. Enter a project name and click OK.

002

In the Console Application project add references to System.ServiceModel (for the WCF libraries) and to the MessageService project (for the service definitions).

003  

005

Click ok to add the references.

Next right click the solution and select “Select StartUp Projects”.

006

Set the action field of the WcfClient project and the console project (SelfHost) to Start and click OK.

007

Open program.cs in the console application project and replace the Main method with this code:

	

static void Main(string[] args)
{
	Uri baseAddress = new Uri("http://localhost:8080/messageservice");

	ServiceHost serviceHost = new ServiceHost(typeof(MessageService.MessageService), baseAddress);

	ServiceMetadataBehavior metaDataBehavior = new ServiceMetadataBehavior();
	metaDataBehavior.HttpGetEnabled = true;
	metaDataBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
	serviceHost.Description.Behaviors.Add(metaDataBehavior);

	serviceHost.AddServiceEndpoint(
		typeof(MessageService.IMessageService),
		new BasicHttpBinding(),
		"http://localhost:8080/messageservice"
	);

	Console.WriteLine("Service is running at http://localhost:8080/messageservice");

	NetTcpBinding netTcpBinding = new NetTcpBinding();
	netTcpBinding.Security.Mode = SecurityMode.None;

	serviceHost.AddServiceEndpoint(
		typeof(MessageService.IMessageService),
		netTcpBinding,
		"net.tcp://localhost:8081/messageservice"
	);

	Console.WriteLine("Service is running at net.tcp://localhost:8081/messageservice");

	NetNamedPipeBinding netNamedPipeBinding = new NetNamedPipeBinding();
	netNamedPipeBinding.Security.Mode = NetNamedPipeSecurityMode.None;

	serviceHost.AddServiceEndpoint(
		typeof(MessageService.IMessageService),
		netNamedPipeBinding,
		"net.pipe://localhost/messageservice"
	);

	Console.WriteLine("Service is running at net.pipe://localhost/messageservice");

	serviceHost.Open();

		
			
	Console.WriteLine("Press any key to stop service.");
	Console.ReadLine();


	// Close the ServiceHost.
	serviceHost.Close();
}

static void ProductHost_Faulted(object sender, EventArgs e)
{
	Console.WriteLine("Something went wrong.");
}


In the code three main steps are taken.

First it creates a base service by creating a ServiceHost.

Then the ServiceMetaDataBehavior is added to this ServiceHosts. This allows the service to give information about itself. If you don’t do this you cannot connect with the WCF test client to test the service. You can test the service in this test client by adding the service url: http://localhost:8080/messageservice.

Next all bindings are added to the ServiceHost. In this case I added a http binding, tcp binding and a named pipe binding.

Now change the code of the MainWindow.xaml and MainWindows.xaml.cs in the WcfClient project.

<Window x:Class="WcfClients.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="340">
<Grid>
  <Button Content="Send" HorizontalAlignment="Left" Margin="145,44,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
  <TextBox Name="InputTextBox" HorizontalAlignment="Left" Height="23" Margin="10,41,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
  <TextBox Name="OutputTextBox" HorizontalAlignment="Left" Height="66" Margin="100,81,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
  <Label Content="Response" HorizontalAlignment="Left" Margin="10,78,0,0" VerticalAlignment="Top"/>
  <Button Content="Use Named Pipes" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="99" Click="Button_Click_1"/>
  <Button Content="Use TCP" HorizontalAlignment="Left" Margin="114,10,0,0" VerticalAlignment="Top" Width="99" Click="Button_Click_2"/>
  <Button Content="Use HTTP" HorizontalAlignment="Left" Margin="218,10,0,0" VerticalAlignment="Top" Width="99" Click="Button_Click_3"/>
</Grid>
</Window>

 

public partial class MainWindow : Window
{
	ChannelFactory factory;

	public MainWindow()
	{
		InitializeComponent();
	}

	private void Button_Click(object sender, RoutedEventArgs e)
	{
		try
		{

			if (factory != null)
			{
				IMessageService service = factory.CreateChannel();

				MessageService.Message message = new MessageService.Message();
				message.Reverse = true;
				message.StringValue = InputTextBox.Text;

				OutputTextBox.Text = service.ProcessMessage(message);
			}
			else
			{
				OutputTextBox.Text = "No connection available";
			}
		}
		catch
		{
			OutputTextBox.Text = "error";
		}
	}

	private void Button_Click_1(object sender, RoutedEventArgs e)
	{
		EndpointAddress endpoint = new EndpointAddress("net.pipe://localhost/messageservice");
		NetNamedPipeBinding binding = new NetNamedPipeBinding();
		binding.Security.Mode = NetNamedPipeSecurityMode.None;

		factory = new ChannelFactory(binding, endpoint);
	}

	private void Button_Click_2(object sender, RoutedEventArgs e)
	{
		EndpointAddress endpoint = new EndpointAddress("net.tcp://localhost:8081/messageservice");
		NetTcpBinding binding = new NetTcpBinding();
		binding.Security.Mode = SecurityMode.None;

		factory = new ChannelFactory(binding, endpoint);
	}

	private void Button_Click_3(object sender, RoutedEventArgs e)
	{
		EndpointAddress endpoint = new EndpointAddress("http://localhost:8080/MessageService");
		Binding binding = new BasicHttpBinding();

		factory = new ChannelFactory(binding, endpoint);
	}
}

Now run the solution. You might get a message from your firewall about the connections you open up. If so, click "”Allow access”.

008

The two projects will start up now. The console:

009

and the test application:

010

That’s it! Have fun with it.

Download the final code here.

No Comments

Add a Comment

About Me

I'm a web application developer specializing in asp.net. I have skills in asp.net, C#, html5, javascript, asp.net mvc, design patterns and more.

more about me

Random background module

This module for Orchard CMS lets you upload a list of images. For every page it chooses one randomly and sets it a the background image.

Go to project page on CodePlex
Download module

The Monack Framework

This open source framework makes it easy to build and develiver custom web applications. Unfortunately I can't spent much time on it so it is still work in progress. 

More about MonackFr
Project page at CodePlex

Orchard

Since I decided to create this website in Orchard and didn't know anything about
it when I started, I also post my experiences with this CMS.