Debug a WCF Service with Edit and Continue Support
Debuging a WCF service through a provider class
Introduction
WCF default debugging does not support edit and continue features, as I have said in my blog post.
Background
In that post, I said that there is an easy way to do it, but I didn't give any code. So this article is about how to do it. The reason I wrote this article is because a fellow member wrote a useful article about WCF, and in tip 1 he suggested using a console application.
My scenario for WCF service consuming and debugging is a Client Server application. I believe my solution can apply to other scenarios.
How To Do It
You need this class DebugServiceHosta
:
internal class DebugServiceHost:IDisposable
{
private static string serviceExecuteTypeName =
"ServiceSide.ExecutionService.ServiceExecute, ServiceSide.ExecutionService,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
private static string iServiceExecuteTypeName =
"ServiceSide.ExecutionService.IServiceExecute,
ServiceSide.ExecutionService, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null";
public static string Address = @"http://localhost:9999/ExecutionService/ServiceExecute/";
public static Binding Binding = new WSHttpBinding();
static DebugServiceHost()
{
isEnabled = Type.GetType(serviceExecuteTypeName) != null;
}
public DebugServiceHost()
{
Type serviceType = Type.GetType(serviceExecuteTypeName);
Type iServiceType = Type.GetType(iServiceExecuteTypeName);
this.debugHost = new ServiceHost(serviceType);
this.debugHost.AddServiceEndpoint(iServiceType, Binding, Address);
this.debugHost.Open();
}
private System.ServiceModel.ServiceHost debugHost;
private static bool isEnabled = false;
public static bool IsEnabled
{
get { return isEnabled; }
}
#region IDisposable Members
private bool disposed = false;
public void Dispose()
{
if (this.disposed)
{
return;
}
this.debugHost.Close();
GC.SuppressFinalize(this);
}
#endregion
}
where ServiceSide.ExecutionService.ServiceExecute
is the namespace of the WCF service and ServiceSide.ExecutionService
the assembly containing it.
Using the Code
I use a provider class, but it's up to you how to implement the above feature.
DebugServiceHost
has a static
property IsEnabled
, which basically checks whether the service is locally located to the running client execution folder. If that is true
, then using an instance of the class, host the service as well, which is automatically disposed.
This a sample code from my project that consumed the true or debug hosted service.
public static class Provider
{
private static DebugServiceHost dbh;
public static void CheckAndRunDebugService()
{
if (DebugServiceHost.IsEnabled)
{
dbh = new DebugServiceHost();
}
}
public static string RemoteURL { get; set; }
private static IServiceExecute iServiceExecute = null;
private static IServiceExecute GetInterface()
{
if (iServiceExecute != null)
return iServiceExecute;
iServiceExecute = CreateClient();
return iServiceExecute;
}
private static ServiceExecuteClient CreateClient()
{
string address = "";
if (DebugServiceHost.IsEnabled)
{
address = DebugServiceHost.Address;
}
else
{
address = String.Format("{0}/Service.svc", Provider.RemoteURL);
}
return new ServiceExecuteReference.ServiceExecuteClient("DefaultEndPoint", address);
}
}
where:
IServiceExecute
is the Interface created when you add the service referenceServiceExecuteReference.ServiceExecuteClient
is the client created when you add the service referenceDefaultEndPoint
is the endpoint in my config file
Points of Interest
At the first call to the service, I create the host. But as I mentioned in my post, there was a problem with that implementation.
Last Problem Hopefully
Finally a point of interest which was my last obstacle that took me a half day to find. I had implemented a provider class for the remoting part, which if needed, fired up the service host. Everything worked just great in the test projects, but at some point I tried to extend the framework with WPF.
The trick was that at first request, through static constructor I checked if the service was required to be hosted, and did that. But this did not work when I made the call from WPF. The only error was a timeout exception. I was going crazy, and then it kicked in. Never trust completely a 3 party library.
Solution
I made three clients, one Console, one Windows one WPF and stripped down the functionality of my framework to test. On each UI Client I made the call (and raised subsequently the host) after a UI reaction. I turns out that neither Windows Forms played correctly, when for example the call is made through a button click event. When I saw that, I made the host come up before the UI part was ever initialized and guess what? It all played just fine.
I really can't understand how this has not been mentioned.
So I refactored the code, and at the program main entry method, I call Provider.CheckAndRunDebugService()
.
Final thing is that, you must implement a trick in order for all serverside assemblies to be found in the client execution folder when you are debugging. There are a number of ways to do achieve this mainly by using post build event or by just adding the references and deleting them when in the deployment face. I use the first.
Apologies
There is no project code, because the above resides in a framework project I have written for the company that I work for.
History
- 28th June, 2008: Initial post