Debugging WCF services

Introduction

Microsoft established with the Windows Communication Foundation (WCF) a sophisticated way to communicate between different components and devices in a service orientated world. A fundamental effort was taken to create a model that is not following a monolithic approach to enable communication between two applications, but a new form that is flexible and configurable in the way modern applications initiate communication and what kind of, more or less secure, channels they use to transmit data. Those different bindings and behaviours are often based on industrial standards and need to be interoperable. That adds complexity, unfortunately.

WCF Exception, faults and security

An important aspect in WCF messaging is security. If you express the actual error, exception or fault message to the client, it’s like expressing the reason of the problem to the rest of the world. In other words you could twitter the error message. Okay, this could be embarrassing for the developer, but what else, you might ask? The actual problem is actually, that those error messages can provide cautious information about the server system. Imaging the exception message would include the connection string to the database server there is used in the backend.

That is the reason, why WCF is so less verbose if you use the default settings. I hope the following list might help you out if you are struggling with WCF services. The list is escalating, from easy things you can do, to configuration changes you can do to optimize tracing.

Use Fiddler

The correct HTTP status code is important. If you see that Fiddler is reporting a 500, then you know that the service is generally accessible, but for some reason not working. Reasons for that might be a corrupt installation or out of date files in the C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files folder.

If Fiddler is reporting a 404, then maybe WCF Components are not installed or not correct registered in IIS. Run ServiceModelReg.exe from C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation.

Check date/time on server and client if services are SSL/TLS secured

Before I start I search for differences in date, time and daylight time saving between server and client. The client and server time is taken independently and mapped to UTC, but if it differs more than 5 minutes, what is the WCF default value, the SSL session key cannot be negotiated and securing the communication with https is not possible. Even if time and date is in sync on server and client, and one machine is adjusted to use daylight savings and the other machine not, communication will fail!

Check Eventlog

The first thing I do always on the server is to look into the Windows Eventlog and especially into the Application Eventlog. Unfortunately, in case of WCF you possibly won’t find any entry if WCF is configured with default settings. But, it’s worth to have a look anyway.

Service call test on Server

Try the service URL within a browser on the server. Often you get a different error message, providing more detail on the server than on the client. If you receive a service activation error, then possibly the files in C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files are out of date. Stop IIS, delete the subfolder that has the application name you are interested in and restart IIS. The folder will be recreated and the fresh assemblies are compiled. Usually that fixes this issue.

Adding a ServiceSecurityAudit element to the service behaviour

WCF adds typically three sections to the application or web.config files of the application that is initiating the service. Those three sections are: Bindings, Behaviors and Services. For us the behaviors are of interest, because we need to manipulate the service behaviour to get more information.

First we search for the behaviour that is responsible for the service. Let’s say we have problem in the borderservice, then the behaviour definition looks like:

<behavior name="MyServiceBehavior"> 
<serviceMetadata httpGetEnabled="true"/> 
<serviceDebug includeExceptionDetailInFaults="false"/> 
<serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" suppressAuditFailure="true" /> 
</behavior>

The yellow line is what we need to add to the behavior. That tells WCF to write error messages to the Windows Application Eventlog. That doesn’t change the information the client will receive, but you can now logon to the server and open the Eventlog.

Enable WCF tracing and diagnostics

Okay, if you are still struggling, then you can enable tracing for WCF, what completely logs any action into a file. Really, any action, as long as its WCF specific. What you need to do is to add Diagnostics section to the System.ServiceModel section in the application config file.

<diagnostics performanceCounters="All" wmiProviderEnabled="true"> 
<messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" maxMessagesToLog="100000" /> 
</diagnostics>

And you need to add System.Diagnostics section to the Configuration section in the application config file, like this

<system.diagnostics> 
<sharedListeners>
<add name="sharedListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\temp\service.svclog" />
    </sharedListeners>
    <sources>
      <source name="System.ServiceModel" switchValue="Verbose, ActivityTracing">
        <listeners>
          <add name="sharedListener" />
        </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging" switchValue="Verbose">
        <listeners>
          <add name="sharedListener" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

Finally you need to tell the trace listener where to store the log file (In the sample above it’s c:\temp\service.log)

If you now run the application and reproduce the error, you can open the log file, using the WCF Diagnostics tool (what you can get from the Windows SDK) and search for the concrete error.

UPDATE ! Other pitfals you might fall into

Keyset does not exist
On the server you might stumble over the following error message: Keyset does not exist. This indicates that application pool identity that is accessing the certificate to secure the web application or WCF service is not allowed to access the private key of the certificate.

To allow the app-pool identity to access the private key, open the certificate store and navigate to Local Computer/Personal/Certificates and right click on the certificate. From the context menu select All Tasks/Manage Private Keys… In the next dialog you can set the permission for user by adding the user first to the ACL and then granting the user read permissions.

Missing behaviorConfiguration section in client config
If the WCF service requests client authentication by a certificate don’t forget to add an endpointBehavior to the client config that provides information what certificate to send to the server.

   <behaviors>
        <endpointBehaviors>
          <behavior name="ClientCertEndpointBehavior">
            <clientCredentials>
              <clientCertificate storeLocation="CurrentUser"  storeName="My" x509FindType="FindBySubjectName" findValue="YOUR CERTIFICATE" />
            </clientCredentials>
          </behavior>
        </endpointBehaviors>
      </behaviors>

Here I add a new endpointBahvior to the endpointBehaviors in the system.serviceModel section of the client config file. I named this endpointBehavior ClientCertEndpointBehavior, the name is important because the endpointBehavior needs to be assigned in the client/endpoint definition:

      <client>
        <endpoint address="whateverService.svc" binding="whateverBiding" bindingConfiguration="whateverConfiguration" contract="whateverContract" name="whateverName"
        behaviorConfiguration="ClientCertEndpointBehavior" />
      </client>

have fun!

Advertisements