I've been putting together a small WCF service that allows a client to upload a file to a server for processing. While the details of that are for another discussion, I want to focus on what should have been a simple operation but turned out to take up most of my afternoon and some of my evening: the generation of a client proxy class and configuration file.
By way of background, this particular WCF service is hosted by a simple Windows Service, runs (by default) under the Network Service account, and exposes a TCP end point for communication. I have a setup project that takes care of the installation and registration of the Windows Service and auto-runs it when installation is complete. This has been running great.
However, anytime I attempted to generate a proxy class for my service via the following command line, I would get some nasy error indicating that it “Cannot obtain Metadata from net.tcp://localhost:9999/myservice”.
svcutil net.tcp://localhost:9999/myservice/mex
My configuration file was as follows:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="mex">
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="MyService.ExampleSvc" behaviorConfiguration="mex">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:9999/myservice" />
</baseAddresses>
</host>
<!-- default endpoint -->
<endpoint
binding="netTcpBinding"
contract="MyService.IExampleSvc" />
<!-- metadata exchange (MEX) endpoint -->
<endpoint
address="mex"
binding="mexTcpBinding"
name="MEX"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
However, as I mentioned, everytime I attempted to retrieve the metadata via the /mex endpoint it failed. Right off the bat I suspected that the error had to do with the types used in the [ServiceContract] class, but I brushed that idea aside thinking that for sure it was something in the configuration file. So I kept on battling with it.
To that end, I created a very simple WCF service (in the same application) this time with an HTTP endpoint. I had to change the Windows Service credentials to a user with elevated permissions to register the HTTP channel (Network Service won't cut it) because I didn't want to manually mess with my HTTP security settings. Anyway, this was just a test. To my chagrin, it worked first try; I was able to retrieve the metadata.
So I returned to the TCP service.
Fortunately (and I'm no WCF whiz...yet :), I found a helpful behavior that I could add to the .config file that saved the day for me. By simply adding the <serviceDebug /> element with the includeExceptionDetailInFaults attribute to the mex behavior element I was able to get some diagnostics.
<serviceBehaviors>
<behavior name="mex">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata />
</behavior>
</serviceBehaviors>
Now, in the big, fat, honkin' exception stack that was output I saw immediately that one of the embedded types used in my [ServiceContract] implementation had a nested type that was not serializable. Once I added [Serializable()] to the offending types (there were a few of them) and recompiled it worked like a champ! So it turns out that my initial suspiscion was correct...I need to listen to my intuition more often!