Welcome to EMC Consulting Blogs Sign in | Join | Help

Simon Evans' Blog

My blog covers the technology areas I focus on here at EMC Consulting, namely Architecture using the .NET Framework, ASP.NET, WCF, WCF Data Services and Windows Azure Follow me on twitter @simonevans

ADO.NET Data Services : Diagnosing problems with your data service

ADO.NET Data Services is elegant technology that feels very easy to work with. The majority of current scenarios for using ADO.NET Data Services involve exposing an Entity Data Model (EDM) implemented using the ADO.NET Entity Framework.  Most of the time, this just works, but it can throw you when you do face problems; how exactly do you diagnose issues in data services, either at design time or in production?

In this blog post I will cover a common check list that should be followed when things haven’t gone to plan; either the service has never successfully run, or has stopped working in production. I will cover the techniques available to you to diagnose problems with your service.

Common Issues

Below is a checklist of issues that are common causes of data services not functioning properly.

Issue 1 : No database connectivity

It sounds obvious, but many data services appear not to be working due to an incorrect database connection string.

Start by checking the connection string that is being used by the Entity Framework. The connection string should be in the <connectionStrings /> section of your service host’s web.config file. Use the server explorer to test the connection credentials. Ensure that the CSDL / MSL / SSDL resources are set to be embedded in the EDMX designer.

Issue 2 : Your EDM is using features not supported by ADO.NET Data Services

Not everything that you can do in the Entity Data Model is supported by ADO.NET Data Services.

The first and most common issue here is the use of EDM types that are not supported by data services. A complete list of EDM types supported by ADO.NET Data Services can be found here.

The second issue you may have when surfacing your EDM is that you have used a form of inheritance not supported by data services. The Entity Framework supports table based inheritance, where the conceptual type must be mapped to a table that represents the sub class. This will only work in the data service if the sub class contains additional properties that are contained in the underlying table.

Issue 3 : The database user account does not have access to the required database objects

Check that all your database objects (tables, view etc) can be accessed using CRUD based SQL with the account that your are using in your database connection string.

Issue 4 : Check you have granted appropriate access to the required entities

By default, no entities from an EDM are surfaced by ADO.NET Data Services unless you specifically grant access to the entities. Check your data service’s Initialize method to ensure that you have granted the appropriate access. Conversely, ensure that there is no code grant access to entities or service operations that do not exist in your service.

Issue 5 : Invalid custom service operation or query interceptor

Custom service operations require the WebGetAttribute to be applied to the method.

If you have stubbed out your service operation, you must ensure that the operation returns a valid IQueryable object (don’t just return null!).

For more information on service operations, look at the MSDN documentation here.

How exceptions are thrown and handled by ADO.NET Data Services

ADO.NET Data Services are build on top of a WCF WebHttpBinding channel stack and use the complete WCF infrastructure to expose a service endpoint. Therefore, any unhandled exceptions from the data service will cause WCF to use its standard fault mechanism to return a response to the client. These faults need to diagnosed using the standard approaches to WCF faults as described later on in this post.

Exceptions handled by a data service implementation causes an HTTP 404 error response. This is because ADO.NET Data Services is a good RESTful citizen. If you see this behaviour, you know that an exception has occurred within the data services runtime.

Diagnosing exceptions handled by the data service at runtime

As mentioned above, ADO.NET Data Services return a standard HTTP 404 message when the service encounters an exception of any kind. To understand what is going wrong in your service, you need to switch on verbose errors in the service’s initialization. However, this should not be used by a service running in production, because it will stop the service returning a standard HTTP 404 error code. This following service initialization code will switch on verbose errors:

    /// <summary>
    /// Initializes the service.
    /// </summary>
    /// <param name="config">The config.</param>
    /// <remarks>This method is called only once to initialize service-wide policies.</remarks>
    public static void InitializeService(IDataServiceConfiguration config)
    {
    // other config settings go here...
        config.UseVerboseErrors = false;
    }

Unfortunately out of the box, ADO.NET Data Services does not provide a standard configuration section to manage these settings at runtime. Therefore, I have attached (at the very bottom of this post) a custom configuration section that can be used within the InitializeService method to drive these settings through configuration.

The configuration section will require an entry in your host’s web.config file like the sample below:

<?xml version="1.0"?>
<configuration>
    <configSections>
        <sectionGroup name="emc.common">
                  <section name="dataService" type="EMC.Data.Services.Configuration.DataServiceSection, EMC.Data.Services.Configuration"/>
        </sectionGroup>
    </configSections>
    <emc.common>
        <dataService>
            <serviceSettings useVerboseErrors="false" maxExpandDepth="3" maxExpandCount="10" maxResultsPerCollection="1000" />
            <entitySetAccessRules>
                <add name="*" entitySetRights="All" />
            </entitySetAccessRules>
            <serviceOperationAccessRules>
                <add name="*" serviceOperationRights="All" />
            </serviceOperationAccessRules>
        </dataService>
    </emc.common>
</configuration>

The code below illustrates how to wire up the configuration section to the InitializeService method:

using EMC.Data.Services.Configuration;

public class MyDataService: DataService<MyEntities>
{

/// <summary>
/// Initializes the service.
/// </summary>
/// <param name="config">The config.</param>
/// <remarks>This method is called only once to initialize service-wide policies.</remarks>
public static void InitializeService(IDataServiceConfiguration config)
{
    DataServiceSection dataServiceSection = ConfigurationManager.GetSection("emc.common/dataService") as DataServiceSection;

    if (dataServiceSection != null)
    {
        if (dataServiceSection.ServiceSettings != null)
        {
            ServiceSettingsElement serviceSettings = dataServiceSection.ServiceSettings;

            config.MaxExpandDepth = serviceSettings.MaxExpandDepth;
            config.UseVerboseErrors = serviceSettings.UseVerboseErrors;
            config.MaxExpandCount = serviceSettings.MaxExpandCount;
            config.MaxResultsPerCollection = serviceSettings.MaxResultsPerCollection;
        }

        if (dataServiceSection.EntitySetAccessRules != null)
        {
            foreach (EntitySetAccessRulesElement element in dataServiceSection.EntitySetAccessRules)
            {
                config.SetEntitySetAccessRule(element.Name, element.EntitySetRights);
            }
        }

        if (dataServiceSection.ServiceOperationAccessRules != null)
        {
            foreach (ServiceOperationAccessRulesElement element in dataServiceSection.ServiceOperationAccessRules)
            {
                config.SetServiceOperationAccessRule(element.Name, element.ServiceOperationRights);
            }
        }
    }

}

Diagnosing WCF faults

If an handled exception is encountered by the WCF channel stack, it will use the standard fault mechanism to respond to the client. By default, the details of the exception will be hidden from the client (again this is how your service should be configured during normal running). This is how it looks in your browser by default when you have a WCF fault in your data service:

WCFError

In order to see the details of the exception in the response from the service, you need to attach a ServiceBehavior to the data service. This can be done in code by applying a service behaviour attribute to the data service implementation, but again this is hard coded and not what you would want for general good running of your service.

Unlike ADO.NET Data Services, WCF does provide a standard way of configuring this behaviour at runtime through the web config file. The configuration code below illustrates how you can drive this behaviour through configuration:

<system.serviceModel>
    <services>
      <service name="Schedule" behaviorConfiguration="DataServiceBehavior">
        <endpoint binding="webHttpBinding" contract="System.Data.Services.IRequestHandler"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DataServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>

ADO.NET Data Services implements a service contract called IRequestHandler. The name of the service needs to be the fully qualified name of your data service implementation.

Using standard WCF messaging diagnostics

ADO.NET Data Services also benefit from the excellent support that WCF has for standard trace diagnostics. The following configuration entry illustrates how you can log out WCF’s tracing to a flat file. Again this would only be used when you have problems with your service at runtime:

<system.diagnostics>
  <sources>
    <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing" >
      <listeners>
        <add name="ServiceModelTraceListener"/>
      </listeners>
    </source>

    <source name="System.ServiceModel" switchValue="Verbose,ActivityTracing"                >
      <listeners>
        <add name="ServiceModelTraceListener"/>
      </listeners>
    </source>
    <source name="System.Runtime.Serialization" switchValue="Verbose,ActivityTracing">
      <listeners>
        <add name="ServiceModelTraceListener"/>
      </listeners>
    </source>
  </sources>
  <sharedListeners>
    <add initializeData="App_tracelog.svclog"
                                    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                                    name="ServiceModelTraceListener" traceOutputOptions="Timestamp"/>
  </sharedListeners>
</system.diagnostics>

Published 17 March 2009 17:37 by simon.evans
Attachment(s): EMC.Data.Services.zip

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit

About simon.evans

Simon is a Managing Consultant for Conchango in the UK, part of EMC Consulting Services. He is an expert in .NET development, and more specifically in WCF and ASP.NET, having participated in several Microsoft early adoption programs. Simon believes deeply that a broad understanding of key technology concepts is an essential foundation to being a gifted designer and builder of solutions.
Powered by Community Server (Personal Edition), by Telligent Systems