21 September 2010

WCF Service Errors and Serializing Enums

When consuming a WCF service, you may run into this common exception:

System.ServiceModel.CommunicationException: The underlying connection was closed: The connection was closed unexpectedly. ---> System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly.
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result) --- End of inner exception stack trace ---

and the server stack trace looks like this:

at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndRequest(IAsyncResult result)

If you're invoking the WCF service from BizTalk, you will probably get the same exception above wrapped by an outer exception that looks like this:

Microsoft.XLANGs.Core.XlangSoapException: An error occurred while processing the message, refer to the details section for more information

with more stack trace info:

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 System.ServiceModel.Channels.IRequestChannel.EndRequest(IAsyncResult result)
at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.RequestCallback(IAsyncResult result)

at Microsoft.BizTalk.XLANGs.BTXEngine.BTXPortBase.VerifyTransport(Envelope env, Int32 operationId, Context ctx)
at Microsoft.XLANGs.Core.Subscription.Receive(Segment s, Context ctx, Envelope& env, Boolean topOnly)
at Microsoft.XLANGs.Core.PortBase.GetMessageId(Subscription subscription, Segment currentSegment, Context cxt, Envelope& env, CachedObject location)
at ETMS.BizTalk.Orchestrations.ImportAutoWindData.segment2(StopConditions stopOn)
at Microsoft.XLANGs.Core.SegmentScheduler.RunASegment(Segment s, StopConditions stopCond, Exception& exp)

It turns out that the return object had a property which was an enumeration which had trouble serializing.
A colleague of mine introduced me to an excellent tool called WCFStorm. Basically it saved me from knocking up a quick client console app to test the WCF service. All I need to do is pass the service wsdl url to the utility. It discovers the types and properties, lets you populate the fields easily and send the request.
That allowed us to quickly deal with real issue, which turned out to be a property of the return type that was an enum. Having a [DataContract] attribute on the enum type itself is not enough, you will need to decorate each enum value with the[EnumMember] attribute:

using System.Runtime.Serialization;
...

[DataContract(Namespace="...")]
public enum PersonalityTypes
{
[EnumMember(Value="Introvert")]
Introvert,
...

After adding this attribute to each enum value, the WCF service will have no problem serializing the object and sending the results back successfully.

No comments: