Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Debugging a WCF REST/AJAX Serialization Problem


:P
On this page:

I’ve been working on my DevConnections demos today and as I was going through my demos I ended up significantly reworking a few of the samples and moving around projects. This actually went fairly smoothly but when I got to my AJAX StockPortfolio sample that mixes jQuery and WCF I got into a nasty mess of a problem that took me a good two hours to resolve. It turns out it was a typical problem of operator error on my part, but this still is one to write up and make others aware of.

My sample project consists of a WCF AJAX service that uses ASP.NET AJAX semantics for access from the client. This means the service is configured like this at the service level in the .SVC file:

<%@ ServiceHost Language="C#" Debug="true"
                Service="WcfAjax.JsonStockService"                
                Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"                                  
%>

This tells WCF to publish the service by default using similar semantics as the old ASMX style services. Note the Factory attribute which is set to WebScriptServiceHostFactory which provides a pre-configured factory for typical MS AJAX style behavior. This factory means that all requests by default use WebInvoke() attributes with POST as the method to send data to the server and using wrapped message format that the ASP.NET AJAX client expects messages to be sent and recieved with. Using the factory makes the process very easy as you don’t have to create any web.config entries to configure the service although you can still do that to override particular settings.

With this done setting up the service is as easy as creating a class and plopping the [ServiceContract] onto it. Since this is an in-application Ajax service only I’m defining both the implementation and contract on a single class rather than seperate service contract interface and implementation class:

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    [ServiceContract]
    public class JsonStockService 
    {
        private StockServer Stocks = new StockServer();
 
        private User User = null;
 
        [OperationContract]
        public StockQuote GetStockQuote(string symbol)
        {
            return Stocks.GetStockQuote(symbol);
        } 
 
        /// <summary>
        /// Returns a full list of items to the caller in the Items
        /// property for the PortfolioMessage
        /// </summary>
        /// <param name="userToken"></param>
        /// <returns></returns>
        [OperationContract]                
        public PortfolioMessage GetPortfolioItems(string userToken)
        {
            // Validate and get this.User instance
            this.ValidateToken(userToken);
 
            busPortfolioItem portfolioItem = new busPortfolioItem();
 
            IQueryable<PortfolioItem> items = portfolioItem.GetItemsForUser(this.User.Pk);
 
            PortfolioMessage msg = new PortfolioMessage
            {
                TotalValue = portfolioItem.GetPortfolioTotalValue(this.User.Pk),
                TotalItems = portfolioItem.GetPortfolioItemCount(this.User.Pk),
                Items = items.ToList()
            };
 
            return msg;
        }
 
 
    }
 
    /// <summary>
    /// Message Item sent to client. Contains Portfolio detail
    /// about a single item or complete portfolio
    /// </summary>
    [DataContract]
    public class PortfolioMessage
    {
        [DataMember]
        public decimal TotalValue { get; set; }
 
        [DataMember]
        public int TotalItems { get; set; }
 
        [DataMember]
        public PortfolioItem SingleItem { get; set; }
 
        [DataMember]
        public List<PortfolioItem> Items { get; set; }
 
    }

My service has about 20 different methods of varying complexity, but I ran into a problem with the GetPortfolioItems() method. When called from the service my client would receive an empty response from the server. No data returned, but no error either. No headers, no data – just a null response. This is a bit difficult to debug as you might expect and this is what ended up taking me 2 hours to figure out.

So what can I do to figure out what the problem is? As you can see in the method  above the result returned is a complex object. It’s basically a result message that contains a few pieces of information and all portfolio related method results all return this message object. The message object either has a single entity or a list of entites set along with a coupe of subtotals that require less code on the client.

First debugging step: Set a break point in the method and surprise, surprise the method actually completes properly. The code in the service fires to the server, but the the response still bombs with no result data. I checked the msg in the debugger and it’s fine no issues there.

So the problem most likely has to do with serialization. First to verify that the method is properly routed and working I returned null and that made it correctly all the way back to the client. No issue there. I then changed the methods WCF attributes to try and access it through a plain HttpGet:

[OperationContract]       
[WebInvoke(Method="Get")] public PortfolioMessage GetPortfolioItems(string userToken)

which should allow me to access the request directly in the browser with a url like

http://localhost/jquery/stockportfolio/StockService.svc/GetPorfolioItems?userToken=2322121321

Here’s the unfortunate result:

Connection Interrupted

The result is an incomplete page – or to be exact a page that didn’t return any output. It seems browsers handle this inconsistently. In FireFox I saw the above page as well as a browser based “Resource Could not be Found” error. Regardless, the bummer on this is that you get nothing back. No error, no message of failure – just no response at all.

In experimenting around with the problem method it seemed clear that the problem is with serialization. The question is just what. Next step for me was to enable WCF tracing and tracking errors. To enable tracing you can use something like the following:


<system.serviceModel>
  <diagnostics>
     <messageLogging logEntireMessage="true" logMalformedMessages="true"
       logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true"
       maxMessagesToLog="3000" maxSizeOfMessageToLog="10000" />
  </diagnostics>   
</system.serviceModel>
<system.diagnostics>
  <sources>
    <source name="System.ServiceModel" switchValue="Error,ActivityTracing"
     propagateActivity="true">
      <listeners>
        <add type="System.Diagnostics.DefaultTraceListener" name="Default">
          <filter type="" />
        </add>
        <add initializeData="c:\projects2008\articles\jquery\traces.xml"
         type="System.Diagnostics.XmlWriterTraceListener" name="messages">
          <filter type="" />
        </add>
      </listeners>
    </source>
  </sources>
</system.diagnostics>

You can also use the WCF Configuration Tool which makes this process a little easier at least once you’ve set up the basic diagnostics settings. You can find this tool in Visual Studio off  Tools | WCF Configuration and then specifying the .config file.

WcfConfiguration

You’ll probably want to just log errors which is by setting the switchValue to log just errors – otherwise the log will become very verbose with entries that’s difficult to read.

Looking at the logs turned out to be not very helpful other than confirming what I already knew: WCF was unable to serialize my message structure. I got a full stack trace of the error on the server, but no indication of what actually went wrong. Also there’s no indication on why there’s no error response to the client. It looks like WCF just quit processing the message after the serialization failure and doing an immediate output return.

Not very helpful.

At the beginning of this post I mentioned that the problem was operator error. I played around with different results from my message structure. Returning null, returning an empty message structure all of that worked. But as soon as I returned any entity data from my Linq To SQL model the failure would kick back in. It turns out when I copied the model somehow I failed to set the serialization options on the Linq to Sql Model:

L2SSerialization

Somewhere in the copy process or maybe when mucking around with the model I failed to set the serialization options for the generated entities. Setting the switch to Unidirectional turns on the [DataContract] and [DataMember] attributes on the generated properties of the generated model:

    [Table(Name="dbo.PortfolioItems")]
    [DataContract()]
    public partial class PortfolioItem : INotifyPropertyChanging, INotifyPropertyChanged
    {
 
        private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
 
        private int _Pk;
 
 
        public PortfolioItem()
        {
            this.Initialize();
        }
 
        [Column(Storage="_Pk", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true, UpdateCheck=UpdateCheck.Never)]
        [DataMember(Order=1)]
        public int Pk
        {
            get
            {
                return this._Pk;
            }
            set
            {
                if ((this._Pk != value))
                {
                    this.OnPkChanging(value);
                    this.SendPropertyChanging();
                    this._Pk = value;
                    this.SendPropertyChanged("Pk");
                    this.OnPkChanged();
                }
            }
        }
   }

Without this option the entities are not serializable. This makes perfect sense. Flog the developer for the oversight :-}.

However, what doesn’t make perfect sense is why WCF is failing so gracelessly in this scenario. Other exceptions such as user thrown exceptions in the code or errors in plain code actually return a proper error response to the client, but the serialization error does not.

Posted in WCF  AJAX  

The Voices of Reason


 

Eyal Vardi
November 04, 2008

# re: Debugging a WCF REST/AJAX Serialization Problem

I like your posts :-)
Can you help me to promote the WCF Debug Visualizer.
http://www.codeplex.com/WCFVisualizer

Rick Strahl
November 04, 2008

# re: Debugging a WCF REST/AJAX Serialization Problem

@Eyal - You just did!

This looks great. Wish I would have had this yesterday as I was looking through those logs (even if they didn't help isolate the problem much).

KierenH
January 14, 2009

# re: Debugging a WCF REST/AJAX Serialization Problem

Did you try adding System.Runtime.Serialization as a trace source :)

Kevin Babcock
February 12, 2009

# re: Debugging a WCF REST/AJAX Serialization Problem

Wow, totally saved me. I was banging my head for the past two hours trying to figure out why my service was failing. Thanks!

Dave
April 16, 2009

# re: Debugging a WCF REST/AJAX Serialization Problem

Once again, you're my hero.

Abhijeet
February 06, 2011

# re: Debugging a WCF REST/AJAX Serialization Problem

I want to write client code for a wcf rest service. I have code for this rest service. While debugging a call to one of the operation using ASP.Net Web server, The operation executes well. But after operation has executed and focus has shifted to Web page, I am been asked to enter a password. I don't know which password to enter. I have tried my admin username password, but to no use. I have set security mode to "None"

<bindings>.<webHttpBinding>. <binding>.<security mode="None">

but still web page keeps asking username & password.

Any clues on how to disable ASP.Net Web Server from asking Username & password.

Andras
September 17, 2011

# re: Debugging a WCF REST/AJAX Serialization Problem

After 2 hours of wasted time I finally found the solution in your post. Thanks!

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024