Self hosting WCF service
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.
Select C# and choose Console Application. Enter a project name and click OK.
In the Console Application project add references to System.ServiceModel (for the WCF libraries) and to the MessageService project (for the service definitions).
Click ok to add the references.
Next right click the solution and select “Select StartUp Projects”.
Set the action field of the WcfClient project and the console project (SelfHost) to Start and click OK.
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 { ChannelFactoryfactory; 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”.
The two projects will start up now. The console:
and the test application:
That’s it! Have fun with it.
Download the final code here.
No Comments