Silverlight TV: RIA Services Q & A

John and I went through four questions we see frequently on the WCF RIA Services forum. Here’s our episode and some notes to go along with it.

Silverlight TV: Episode 52

How do I investigate exceptions thrown from my DomainContext?

If you’ve been using RIA, you’ve undoubtedly seen this exception before.

Load operation failed for query 'GetEmployees'. Exception of type 'System.ServiceModel.DomainServices.Client.DomainOperationException' was thrown.
at System.ServiceModel.DomainServices.Client.WebDomainClient`1.EndQueryCore(IAsyncResult asyncResult)
at System.ServiceModel.DomainServices.Client.DomainClient.EndQuery(IAsyncResult asyncResult)
at System.ServiceModel.DomainServices.Client.DomainContext.CompleteLoad(IAsyncResult asyncResult)

A rough translation is “An exception was thrown in your DomainService while loading data. ” The problem is this exception is opaque and masks the real failure. What we need is some way to get the details about what is actually occurring.

Option 1: Temporarily set the customErrors mode to “Off”

In your web.config file, you can update the customErrors element.

   <customErrors mode="Off"/>

Option 2: Use fiddler to look at the response from the server

There’s a lot to know about using fiddler, but I’ll keep this section sparse. I showed a little in the video and there are plenty of other examples.

Download Fiddler

Tips for using Fiddler on localhost

Option 3: Override DomainService.OnError to inspect the error on the server

There are a number of reasons to override OnError (logging, etc.) in your DomainServices. One of the ways it can be useful is to give you a place to inspect errors before they’re sent back to the client.

Using any of these method, we can get more useful information from the error.

Load operation failed for query 'GetEmployees'. Object reference not set to an instance of an object.
at SampleBusinessApplication.Web.EmployeeDomainService.GetEmployees() in …\EmployeeDomainService.cs:line 22 at GetEmployees(DomainService , Object[] ) at System.ServiceModel.DomainServices.Server.ReflectionDomainServiceDescriptionProvider.ReflectionDomainOperationEntry.Invoke(DomainService domainService, Object[] parameters) at System.ServiceModel.DomainServices.Server.DomainOperationEntry.Invoke(DomainService domainService, Object[] parameters, Int32& totalCount) at System.ServiceModel.DomainServices.Server.DomainService.Query(QueryDescription queryDescription, IEnumerable`1& validationErrors, Int32& totalCount) at System.ServiceModel.DomainServices.Hosting.QueryProcessor.Process[TEntity](DomainService domainService, DomainOperationEntry queryOperation, Object[] parameters, ServiceQuery serviceQuery, IEnumerable`1& validationErrors, Int32& totalCount) at System.ServiceModel.DomainServices.Hosting.QueryOperationBehavior`1.QueryOperationInvoker.InvokeCore(Object instance, Object[] inputs, Object[]& outputs)

How do I add a ComboBox to a DataGrid or DataForm?

I have a couple posts that cover these topics.

Silverlight ComboBox Frequently Asked Questions

Silverlight ComboBox Sample for RIA Services

How do I change the default metadata added to an Entity when using the LinqToEntitiesDomainService?

It’s worth taking a second to provide context for this question. When you use the LinqToEntitiesDomainService, RIA Services codegen will add some default metadata to your entity types. For instance, if we look at the generated code for our Employee type, we can see the metadata on the FirstName property.

   [DataMember()]
  [Required()]
  [StringLength(10)]
  public string FirstName

It’s worth asking “Where do these value come from?” In short, the code generator is looking at the constraints you specified in your database and converting them into attributes. This helps reduce the number of exceptions you encounter when submitting your changes to the database.

If you want to use something other than the default metadata you only need to specify it yourself. All the metadata you specify will override the codegen defaults. For instance, I can add some metadata to the Employee type.

   // The MetadataTypeAttribute identifies EmployeeMetadata as the class
  // that carries additional metadata for the Employee class.
  [MetadataTypeAttribute(typeof(Employee.EmployeeMetadata))]
  public partial class Employee
  {
    internal sealed class EmployeeMetadata
    {
      [Required(AllowEmptyStrings = true,
                ErrorMessage = "First name cannot be null.")]
      public string FirstName { get; set; }
    }
  }

When I do this, I can see the attribute I specified for the FirstName property get generated in place of the default attribute.

   [DataMember()]
  [Required(AllowEmptyStrings=true,
            ErrorMessage="First name cannot be null.")]
  [StringLength(10)]
  public string FirstName

How do I add cross-field validation to an Entity?

Jeff has some great posts on validation. Here are the two that cover cross-field validation.

Cross-Field Validation

Entity-Level Validation 

Do you have the sample code?

Yep. Here it is.