All of us (one that dialed WCF technologies) tried to make and run WCF host service project created by VS 2008 WCF Service Library template. It's very useful template that help us to configure and debug our service.
Two most effective tools executed at debugging are WcfSvcHost and WcfTestClient. When you press F5 key (Start Debugging) WCF Service Library project launch WcfSvcHost.exe with command line argument /client:"WcfTestClient.exe" that run WcfTestClient application. This is fine but what if you have Consol, Window or Web Application and you have no goodies of WCF Service Library project. Of course you can execute manually WcfTestClient in Command Prompt (Outside Visual Studio) but it's not useful (really, you aren’t going to do this each debug time). And what about to have some WcfTestClient instance during your debugging or you need to host some WCF services?
Ok, how am I going to do this? First I tried make a batch (*.bat) file and to change debug property from 'Start project' to 'Start external program:' with this batch file but, oops… The external program must to be executable file path (*.exe).

Alert if you try to run debagging

So I decided to create a simple Class Library Project with single help static that can to launch WcfTestClient tool with your needed settings. By the way this class can be included to your project as well. The class has static Start() overloaded functions that launch the WcfTestClient tool by specify path to WcfTestClient.exe file or by VS 2008 environment definition, plus the function uses all metadata addresses retrieved from ServiceHost instance or your provided metadata addresses.
Source Code
Using WcfTestClient Launcher snippet code:
Example 1
ServiceHost sh = new ServiceHost(typeof(Trading));
sh.Open();
//Self WcfTestClient.exe discovering and retriving metadata from ServiceHost instance
Process process1 = WcfTestClientLauncher.Start(sh);
process1.WaitForExit();
Example 2
string wcfTestClientPath = @"C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\WcfTestClient.exe";
string serviceMetadataAddresses = "http://localhost:8181/CustomBaseServer/Trading/";
Process process2 = WcfTestClientLauncher.Start(wcfTestClientPath, serviceMetadataAddresses);
process2.WaitForExit();
Example 3
ServiceHost sh1 = new ServiceHost(typeof(Trading));
sh1.Open();
ServiceHost sh2 = new ServiceHost(typeof(Trading1), new Uri("http://localhost:8181/CustomBaseServer/Trading1/"));
sh2.AddServiceEndpoint(typeof(ITrading), new BasicHttpBinding(), "");
ServiceMetadataBehavior metadataBehavior = sh2.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetEnabled = true;
sh2.Description.Behaviors.Add(metadataBehavior);
}
sh2.Open();
#if (DEBUG)
Process p1 = WcfTestClientLauncher.Start(sh1);
Process p2 = WcfTestClientLauncher.Start(sh2);
Console.ReadLine();
p1.CloseMainWindow();
p1.WaitForExit();
p2.CloseMainWindow();
p2.WaitForExit();
#endif
In this last example I have to test two services hosted both in one AppDomain, it's very simple to test them with WcfTestClient launched by my small tool.
Example 3 snapshot
In one of my discussions with my colleagues about WCF technology we talked about coupling concept and how come WCF solves this important issue. So my decision was creating a very simple code example that explains and shows a key moment of WCF coupling solution.
This example is a simple VS 2008 solution with two consol application projects, CustomBaseServer and CustomBaseClient. The CustomBaseServer is a service host project and the CustomBaseClient is a service client project that don't use client proxy generated by (Svcutil.exe) tool but use ChannelFactory (how to use ChannelFactory) object instead.
Example Source Code
-- CustomBaseServer - Service Host Project --
File: ITrading.cs - Service Contract Definition
using System;
using System.ServiceModel;
namespace CustomBaseServer
{
[ServiceContract]
interface ITrading
{
[OperationContract]
double GetRate(string symbol);
}
}
File: Trading.cs - Service Contract Implemetetion
using System;
namespace CustomBaseServer
{
class Trading : ITrading
{
public double GetRate(string symbol)
{
return 123.456;
}
}
}
File: Program.cs - Server Consol Runner
using System;
using System.ServiceModel;
namespace CustomBaseServer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Server start...");
ServiceHost sh = new ServiceHost(typeof(Trading));
sh.Open();
Console.ReadLine();
}
}
}
File: App.config - Service Application Configuration
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="CustomBaseServer.Trading">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8181/CustomBaseServer/Trading"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="CustomBaseServer.ITrading"/>
</service>
</services>
</system.serviceModel>
</configuration>
Note for Vista users: Visual Studio 2008 must be executed in administrator mode or you have to run the console (cmd) in administrator mode and launch next command "netsh http add urlacl url=http://+:8181/CustomBaseServer/Trading user=domain\vlad", learn more http://msdn.microsoft.com/en-us/library/ms733768.aspx.
-- CustomBaseClient - Service Client Project --
File: ITrading.cs - Service Contract Definition
using System;
using System.ServiceModel;
namespace CustomBaseClient
{
[ServiceContract(Name = "ITrading")]
interface ITrading1
{
[OperationContract(Name = "GetRate")]
double GetRate1(string symbol);
}
}
File: Program.cs - Client Consol Runner
using System;
using System.ServiceModel;
namespace CustomBaseClient
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Client start...");
var channelFactory = new ChannelFactory<ITrading1>("ITradingBasicHttp");
var trading = channelFactory.CreateChannel();
double rate = trading.GetRate1("EURUSD");
Console.WriteLine(string.Format("Rate: {0}", rate));
Console.ReadLine();
}
}
}
File: App.config - Client Application Configuration
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint
address="http://localhost:8181/CustomBaseServer/Trading/"
binding="basicHttpBinding"
contract="CustomBaseClient.ITrading1"
name="ITradingBasicHttp">
</endpoint>
</client>
</system.serviceModel>
</configuration>
First of all there is no reference between two projects. Also there is no reference from one of these projects to another common or shared one. Two projects are absolutely independent. Like in the standard client – server application the client has to know only server address to establish connection with him.
How can you see the service client defines self CustomBaseClient.ITrading1 interface with GetRate1 function. This interface and its function are different then service host CustomBaseServer.ITrading interface and its GetRate function. To use the service functionality client must to have same defined service contract otherwise client throws System.ServiceModel.ActionNotSupportedException at its interface methods excusing. Exception message example: "The message with Action 'http://tempuri.org/ITrading1/GetRate' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None".
In my case I used named parameter [Name] of ServiceContract and OperationContract Attributes for coordinating service ITrading and client ITrading1 interfaces name and their methods names.
By this example you can see how the WCF very elegantly solves the old and heavy coupling issues. Based on the SOAP protocol the WCF technologies provide us supporting for agile R&D process and Application Lifecycle Management (ALM).
Example Source Code