WCF RIA Services - “Not Found” Error Message

The dreaded “The remote server returned an error: NotFound” error message in RIA Services can be frustrating if you are not aware of what it really means, and more importantly how to diagnose it.

This generic error message is due to network stack limitation in your browser, basically the browser is intercepting the error and not giving it all to Silverlight.  That does not mean there isn’t good information to be found.  Your friend here is Fiddler and/or WCF Service Tracing. 

NotFound vs OnError:  A NotFound generally means that something in the WCF side blew up, OnError will handle errors in your model (or custom code in your DomainService).  So when you see NotFound, overriding OnError will not be much help, break points placed inside of it will most likely not be reached during debugging, but its an easy place to start.

The first tool we are going to us is Fiddler, a web debugging proxy with a WCF Binary Inspector. This will show you all the requests are being made and will show you what error code, and possibly what error is being returned by your service. (Using Fiddler with ASP.Net Development Server / Casini)

Fiddler

If there is no good information in Fiddler then the next step is to hit your service url, which you can find in Fiddler.   In the picture above you can see that my service is at /ClientBin/HockeyStatsService-Web-HockeyStatsDomainService.svc (ProjectName-Web-DomainServiceName.svc).  Remember that RIA Services does not actually generate a .svc file for you, it is handled dynamically by the DomainServiceHttpModule, so don’t go looking for a physical file.

Actual 404:  If you hit your service in the browser and you still get a 404, then something is wrong with your deployment. 

Actual404

Check out Saurabh Pant’s Blog or Tim Heuer for good articles on deploying WCF Ria Services to IIS.

If you are using Casini (ASP.NET development server) then make sure your web.config is correct (Has proper references to DomainServiceHttpModule), and that you have a reference in your ASP.NET project to your service library (if you are using RIA Class Libraries, otherwise you should be fine on this point).

Now if you can hit your service url without a 404, but still get a NotFound, and the Fiddler response tab didn’t give you anymore insight we will move on to some other steps.

SvcTraceViewer: Visual Studio has a tool to help you configure WCF, it can be found under TOOLS | WCF Service Configuration Editor.  Use this tool to open your Web.Config and then on the ‘Diagnostics’ folder, turn on Message Logging and Tracing.  On the ‘Message Logging’ node, LogMessagesAtServiceLevel=true and LogMessagesAtTransportLevel=false.

WCFtraceConfig2

You can view the generated svclog files with C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe

In my example DomainService I am loading a large amount of hockey stats data.  When I open my svclog file and find the error generated I can see that the actual exception being thrown by my service says:

'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota. '.

WCFTraceViewer

Your message obviously might be different, but with that information you should be able to find a solution or at least provide the right information to the WCF RIA Services Forums so they can help find a solution

Another good debugging tip is to turn off custom errors in your Web.Config.  <customErrors mode="Off"/>  This will provide more informative exceptions to silverlight, however it also exposes information to the user that you may not intend, so do not leave this set to ‘off’ on a publicly available site.

If your error is the same as mine, take a look at Fixing the MaxItemsInObjectGraph.

MaxItemsInObjectGraph – WCF RIA Services Exception

 

The MaxItemsInObjectGraph error message comes up fairly often in the WCF RIA Services forums and I just ran into it on a personal project so I thought I’d write a quick blog on how to fix this error.

The exact error message from WCF Trace is:

'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota. '.

You need to add the following code to your web.config, and replace the following:

HockeyStatsService-Web-HockeyStatsDomainService with YourRiaProjectName-Web-YourDomainServiceName

HockeyStatsService.Web.HockeyStatsDomainService with YourRiaProjectName.Web.YourDomainServiceName

<services>
  <service name="HockeyStatsService.Web.HockeyStatsDomainService"
          behaviorConfiguration="HockeyStatsService-Web-HockeyStatsDomainService">
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="HockeyStatsService-Web-HockeyStatsDomainService">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
      <dataContractSerializer maxItemsInObjectGraph="655360"/>
    </behavior>
  </serviceBehaviors>
</behaviors>

WCF Ria Services vs Entity Framework

This is a quick tip for anyone using WCF RIA Services with Entity Framework.  The WCF RIA Services team has fixed what I consider a fairly annoying ‘bug’ with Entity Framework.  In Entity Framework the EntityCollection class does not implement INotifyCollectionChanged, however the client side EntityCollection class that RIA uses is part of the RIA framework and they have fixed this issue.  They have explicitly implemented the interface however so you will need to cast the EntityCollection to a INotifyCollectionChanged before you see the CollectionChanged event.

RIA Services XMLMetaDataProvider and Dynamic Assemblies

If you are using the XMLMetaDataProvider and have a dynamic assembly reference your service might fail with the following error:

           The invoked member is not supported in a dynamic assembly

There are two fixes for this problem, one is to use the full attribute names.  So ‘DisplayAttribute’ instead of just ‘Display’.  Second option is to fix the code in MetadataSet.cs.  The problem is with the TryGetType method around line 421.  You should be able to find the code below, the GetExportedTypes needs to be changed to GetTypes. 

   1: // TODO : the metadata file might need a way to specify the set
   2: // of source assemblies to load from - for now search all loaded assemblies
   3: foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
   4: {
   5:     foreach (Type t in assembly.GetTypes())
   6:     {
   7:         if (t.Name == typeName || t.FullName == typeName)
   8:         {
   9:             typeMap[typeName] = t;
  10:             return t;
  11:         }
  12:     }
  13: }

 

Thanks to Manfred Lange for the tip on the error message.

WCF RIA Services XMLMetaDataProvider Problem

The current RIA Services project I’m working on has been using the XMLMetaDataProvider due to the fact that our model and DomainService are in different projects.  This rules out defining your metadata in a partial class for each entity.   As the project got bigger we noticed that randomly our metadata was not being created at build time.  Turns out there is a race condition with loading the XML file and the requests for metadata.  Here is the new XmlMetadataProvider.cs file where we now load the dataset in the constructor, not the first time it is requested.  After all that, I think we’ll try using Nikhil Kothari’s fluent API style, I like the look of it over the mass amount of XML.

   1: internal class XmlMetadataProvider : TypeDescriptionProvider
   2:     {
   3:         private Type domainServiceType;
   4:         private MetadataSet metadataSet;
   5:  
   6:         /// <summary>
   7:         /// Constructor that accepts a metadata context to use when generating custom type descriptors
   8:         /// </summary>
   9:         /// <param name="existingProvider">The parent TDP instance</param>
  10:         /// <param name="domainServiceType">The DomainService Type exposing the entity Types this provider will be registered for</param>
  11:         public XmlMetadataProvider(TypeDescriptionProvider existingProvider, Type domainServiceType)
  12:             : base(existingProvider)
  13:         {
  14:             this.domainServiceType = domainServiceType;
  15:             LoadMetadataSet();
  16:         }
  17:  
  18:         public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
  19:         {
  20:             return new XmlMetadataTypeDescriptor(this.MetadataSet, objectType, base.GetTypeDescriptor(objectType, instance));
  21:         }
  22:  
  23:         private MetadataSet MetadataSet
  24:         {
  25:             get
  26:             {
  27:                 if (metadataSet == null)
  28:                 {
  29:                     LoadMetadataSet();
  30:                 }
  31:                 return metadataSet;
  32:             }
  33:         }
  34:  
  35:         private void LoadMetadataSet()
  36:         {
  37:             metadataSet = new MetadataSet();
  38:  
  39:             // load all the metadata files found
  40:             IEnumerable<string> metadataFiles = domainServiceType.Assembly.GetManifestResourceNames().Where(p => p.EndsWith(".metadata.xml", StringComparison.OrdinalIgnoreCase));
  41:             foreach (string metadataFile in metadataFiles)
  42:             {
  43:                 Stream stream = domainServiceType.Assembly.GetManifestResourceStream(metadataFile);
  44:                 StreamReader streamReader = new StreamReader(stream);
  45:                 String metadata = streamReader.ReadToEnd();
  46:  
  47:                 try
  48:                 {
  49:                     metadataSet.Load(metadata);
  50:                 }
  51:                 catch (Exception e)
  52:                 {
  53:                     string msg = string.Format(CultureInfo.CurrentCulture, Resource.MetadataLoadError, metadataFile) + " : " + e.Message;
  54:                     throw new InvalidOperationException(msg, e);
  55:                 }
  56:  
  57:             }
  58:         }
  59:     }
  60: }