One of the projects that I’ve been working on the past week is a conversion project that involves a web site that has a tightly coupled business logic layer. The goal of the project is to re-engineer the site so that the business logic and corresponding data access tiers are decoupled and distributed as services. For us the obvious choice for this is using the new Windows Communication Foundation framework to accomplish the task. After some heavy reading and a lot of trial and error, we’re very close to having this done and I’m proud of the outcome given the short span of the project (~ 5 weeks). We probably could have finished in 4 weeks if it weren’t for a seemingly innocuous problem with proxy generation that ended up costing me 3 day’s time to solve. If you’re using a tcp based Metadata Exchange binding and having trouble generating a service proxy with SvcUtil, read on!
The Error Rears It’s Ugly Head
This is the error that I was getting when trying to have SvcUtil generate my proxy class for a particular service of mine:
WS-Metadata Exchange Error URI: net.tcp://localhost:8888/MyServices/MyBigFatGreekService
Metadata contains a reference that cannot be resolved: ‘net.tcp://localhost:8888/MyServices/MyBigFatGreekService’.
The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was ‘00:04:59.9843748’.
An existing connection was forcibly closed by the remote host
Oh how silly of me! As you can see, SvcUtil was built to tell you exactly what’s going on, NOT!! this error is terribly vague because it leads you to believe that you have a network issue going on, which hey, you might. But in my case, I had 15 services hosted on the SAME address and I was able to generate 14/15 with no problem. Now, let’s take a look at what kind of problems cause this error to appear:
Common Beginner Mistakes
I’m going to take a small digression here to talk about some common mistakes that take 30 seconds to fix that could cause this error to occur. Most people who get errors from SvcUtil are missing something in the configuration of their services that is causing the problem. The biggest two culprits I’ve seen:
1.) Make sure you enable Metadata Exchange. you need to do this explicitly for each service and it’s commonly missed. This is done with a Service Behavior Configuration Section, like below. The key piece here is the serviceMetadata element:
<behaviors> <serviceBehaviors> <behavior name="MetaDataBehavior"> <serviceMetadata /> </behavior> </serviceBehaviors> </behaviors>
If you’re using a Tcp based binding, just making sure it’s there as above enables the exchange. For using an Http based binding, specify either HttpGetEnabled or HttpsGetEnabled, as in the below example:
<serviceMetadata httpGetEnabled="true" />
2.) Make sure that the security settings on your binding match what you want to achieve. If the discovery of your metadata is to be public, explicitly set your security to “None” so that you are sure not to encounter authentication issues. If not, make sure you configure the security correctly. In my example, we’re not securing the metadata endpoint.
<services> <service name="Service.MyService" behaviorConfiguration="MyServiceBehavior"> <host> <baseAddresses> <add baseAddress = "net.tcp://localhost:8888/MyService" /> </baseAddresses> </host> <endpoint address="" binding="netTcpBinding" contract="Service.IMyService" bindingConfiguration="myNetTcp" /> <endpoint address="mex" binding="netTcpBinding" contract="IMetadataExchange" bindingConfiguration="mexTcp" /> </service> </services> <bindings> <netTcpBinding> <binding name="myNetTcp" portSharingEnabled="true"> </binding> <binding name="mexTcp" portSharingEnabled="true"> <security mode="None" /> </binding> </netTcpBinding> </bindings>
In this case I’m using port sharing because we want all of our services to share the same Tcp port regardless of how many we have in the future. If you have port sharing enabled for one service, do yourself a favor and keep it consistent. For more detailed information about port sharing, read this blog post by Nicholas Allen to get a true understanding of why you need this.
None of my other services were having proxy generation problems, so I knew that I had the services set up correctly. I even double checked to make sure I didn’t have any syntax errors on that one service that could cause me problems. After this, I began seeing some strange things. Turns out, switching to an Http based binding like mexHttpBinding fixed the problem. But I didn’t want http, I wanted Tcp, so I pressed on. What could be the difference between the two bindings that could cause such a problem?
It turns out that the service I had trouble with was the largest of all the services I was trying to generate (~ 30 methods). I found that by commenting out a few of the methods in the service contract, the Tcp Metadata exchange WORKED! It also didn’t matter which methods were commented, which ruled out problems like an incorrectly serialized type or a duplicate operation name. Now, in Juval Lowy’s book on WCF, he states that service contracts should have no more than 5 – 7 methods if they are properly factored and this makes sense, but I didn’t have time to factor this class straight away due to time constraints. For now, the class has to stay big. There was no documentation stating that service contracts had a maximum size restriction, so again, WHY THIS ERROR?
I thought that maybe I needed to up the default throttling controls on the metadata exchange binding for the services, so I increased the maxReceivedMessageSize and all of the limits in the readerQuotas element, but received the same error. It should be noted here that the mexTcpBinding is a very specific type of netTcpBinding that doesn’t allow you to tweak these settings. So, just use netTcpBinding, there’s no rule against it.
Send In The Marines!
Hey everyone, SvcUtil has a limit on how much metadata it can receive! Did you know that? If you did, congratulations, because this is not well documented at all! Especially disconcerting is the apparent inconsistency with which this limit is imposed, which was the reason that my mexHttpBinding worked without a hitch. How do we tell SvcUtil to eat more fiber? It turns out I was on the right track with increasing the throttling controls on the binding, but not in the right place. It turns out that I needed to create an app.config for SvcUtil itself, place it in the directory with SvcUtil.exe and THEN run it. Here’s the config that finally made it work:
<configuration> <system.serviceModel> <client> <endpoint name="net.tcp" binding="netTcpBinding" bindingConfiguration="myTcp" contract="IMetadataExchange" /> </client> <bindings> <netTcpBinding> <binding name="myTcp" maxBufferPoolSize="60000000" maxBufferSize="60000000" maxReceivedMessageSize="60000000" > <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> </binding> </netTcpBinding> </bindings> </system.serviceModel> </configuration>
So there it is. Make sure that the binding configuration that you use in the svcutil app.config matches the one you’re using in the configuration file for your service host. If you don’t, you will be getting a different error when you run SvcUtil, explaining that you have mismatched service settings and therefore the action is invalid.
I can’t say I figured this problem out on my own. In fact, when I was so frustrated that I ripped all my hair out, I finally posted the MSDN Forums to see if ANYONE had the same problem as me. Thanks to the moderators there, I was pointed in the right direction which solved my problem. You can see my post here.
In my next post, I’ll be discussing why Visual Studio’s Service Reference Proxy Generation Tool isn’t adequate for those who are producing and consuming their own services and want to share multiple collection data types between the service and client, and how to use SvcUtil to overcome that inadequacy.