Search code examples
.netwcf

WCF service runs in Debug mode but not in Release


I've come up against a weird problem: The WCF web service I'm building runs in debug mode but not in release.

I've got a simple Hello web method in the web service that just returns a string and does nothing else (no logging, exception handling, nothing). I run the WCFTestClient from within Visual Studio by selecting the .svc file and clicking F5 to start debugging. When the WCFTestClient is open I double-click on the Hello web method and Invoke it. In Debug mode it runs fine. In Release mode almost instantly I get the following error:

Object reference not set to an instance of an object.

Server stack trace: 
   at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at IVehicleRisk.Hello()
   at VehicleRiskClient.Hello()

(the web service is VehicleRisk.svc and the service contract is IVehicleRisk).

Adding breakpoints to the application I can see when I invoke the Hello web method the Application_BeginRequest method in Global.asax.cs is being called (it's an empty method). When the exception is thrown no breakpoints in VehicleRisk.svc.cs are being hit, in either the constructor or the Hello method (when the web method works, the breakpoints are being hit).

I looked at the project build properties in Visual Studio (right click on the project in Solution Explorer, select Properties, open the Build tab in the Properties window). The only difference I can see between Debug and Release modes are:

  1. Define DEBUG constant: Set on in Debug mode, off in Release;

  2. Optimize code: Set off in Debug mode, on in Release;

  3. Advanced > Output Debug Info: Set to full in Debug mode, pdb-only in Release.

Experimenting with changing the Build properties in Release mode, I found that I can get the web method to work only when Optimize code is set off and Advanced > Output Debug Info is set to full. Setting the DEBUG constant on or off makes no difference.

Does anyone have any idea why a simple web method would fail when code optimization is turned on, or when debug info is set to pcb-only?


Solution

  • It turns out the problem wasn't to do with WCF per se.

    I was calling a simple Hello method in the service class but the constructor of that class was setting up logging (although I wasn't actually using the logging in the Hello method). The logging helper class that was being instantiated in the service class constructor had a method GetCallingMethodName. This method walks up through the stack trace to determine the names of the class and method logging a message, to include the names in the log message.

    The key to the problem was that GetCallingMethodName skipped the first method call in the stack trace, which would normally be the GetCallingMethodName method itself. The 64-bit JIT compiler on the web server must have been inlining the method, so there was no second stack frame in the stack trace. Attempting to skip the first frame in the stack trace was therefore causing an error.

    The solution was to start walking the stack trace from the first stack frame instead of the second.

    This problem didn't appear when the web service was deployed to the server in Debug mode as the compiler optimizations were turned off, so the compiler couldn't inline the method. Nor did it appear on my development PC in Release mode as the 32-bit JIT compiler must have been optimizing the code differently from the 64-bit compiler on the server.