Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Introducing the Composite Data Service Framework

5.00/5 (4 votes)
27 Nov 2011CPOL5 min read 31.6K   509  
Use a single Data Service to expose data from many sources with the Composite Data Service Framework!

CDSF-Logo.png

Introduction

Welcome! In this series of articles, I am going to show you how to perform some advanced OData/WCF Data Service tasks, such as creating a custom data service provider, customizing the generation of service references, and more. First, I will describe some of the limitations of WCF Data Services and then how we will address them.

Limitations of WCF Data Services

WCF Data Services are great, but currently have a few key limitations:

  • It is difficult to aggregate many data sources into a single data service.
  • It is very hard to augment WCF Data Services with standard WCF Services.
  • No client-side proxies are generated for service operations.

There are some more subtle limitations that we'll see later.

Running the Example Service

Here's how to get started with the sample service:

  1. Open the CompositeDataServiceFramework Solution.
  2. Double click on the file Samples > Composite Data Service Sample > CreateDatabases.sql.
  3. Run this script (SQL Server Express Edition is fine as a database platform if you do not have the full MS SQL Server installed).
  4. Run the CompositeDataServiceSample project.
  5. Browse to http://localhost:65110/CompositeDataServiceSample.svc/$metadata and we can see that the CompositeDataService has composed a single data service from our Orders and Users Data services - and that the service is fully functional.

The Composite Data Service Framework

With these limitations in mind, I have created a project called the Composite Data Service Framework. The main aim of this project is to allow many data sources to be aggregated together to create a single composite WCF Data Service, highlighted by the diagram below.

CSDF_Diagram.png

Creating a Composite Data Service

Creating a composite data service is very simple. First, add a WCF Data Service class for each model you want to expose - in the example solution provided, I have two Models - an OrdersDataModel and a UsersDataModel. These models are Entity Framework Data Models. Now create another WCF Data Service, named something like 'CompositeDataService'. All you now need to do is derive from CompositeDataService and add each distinct WCF Data Service as a CompositeDataSource.

Here's how we do it step-by-step.

First, create the Composite Data Service, by adding a WCF Data Service to your application:

C#
/// <summary>
/// This is an example of a composite data service.
/// </summary>
public class CompositeDataServiceSample : 
       CompositeDataServiceFramework.Server.CompositeDataService
{
    /// <summary>
    /// A WcfDataServiceDataSource for the Orders Data Service.
    /// </summary>
    private WcfDataServiceDataSource<OrdersModelContainer> ordersDataService;

    /// <summary>
    /// A WcfDataServiceDataSource for the Users Data Service.
    /// </summary>
    private WcfDataServiceDataSource<UsersDataModelContainer> usersDataService;

What we have done here is create a composite data service that has two data source members - one for our users model and one for our orders model. Next we initialise our service just as we would any normal WCF Data Service - specifying access for each object and operation.

C#
/// <summary>
/// Initializes the service.
/// </summary>
/// <param name="config">The config.</param>
public static void InitializeService(DataServiceConfiguration config)
{
    //  Allow full access to all entity sets and all service operations.
    config.SetEntitySetAccessRule("*", EntitySetRights.All);
    config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
    config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}

Finally, in the constructor, we build the two data sources and add them to the composite data service and then initialise it.

C#
/// <summary>
/// Initializes a new instance of the <see cref="CompositeDataServiceSample"/> class.
/// </summary>
public CompositeDataServiceSample()
{
    //  Create the orders data source, by providing
    //  an Orders Data Service, Orders Model Container
    //  and the Url to the data service.
    ordersDataSource = new WcfDataServiceDataSource<OrdersModelContainer>(
        new OrdersDataService(),
        new OrdersModelContainer(),
        new Uri("http://localhost:65110/OrdersDataService.svc"));

    //  Create the users data source, by providing
    //  a Users Data Service, Users Model Container
    //  and the Url to the data service.
    usersDataSource = new WcfDataServiceDataSource<UsersDataModelContainer>(
        new UsersDataService(),
        new UsersDataModelContainer(),
        new Uri("http://localhost:65110/UsersDataService.svc"));
    
    //  Add each data source.
    AddDataSource(ordersDataSource);
    AddDataSource(usersDataSource);

    //  Initialise the data service.
    Initialise();
}

Now you can run up the data service and put /$metadata at the end of the URL - this single data service aggregates the two other data services into one!

Now when you add a reference to the composite data service in a client project, you have access to entities from both services; from the client's point of view, it doesn't matter where they come from, they are presented as part of the same service.

How Does It Work?

There is a lot of code in this project already, and there's going to be more as I build up the full set of features. So rather than going through the code line-by-line as I do in most of my articles, I'm going to describe the code in a more high level way.

Creating a Custom Data Service

The first thing to do is to derive a class from Data Service. This will be the the main object that represents the Composite Data Service. This object must also implement the IServiceProvider interface, to allow instances of supporting interfaces to be instantiated.

The following interfaces must now be supported (in this framework, each is in its own class).

IDataServiceMetadataProvider

The IDataServiceMetadataProvider interface exposes information about the service itself - what collections it exposes, the object types it exposes, its service operations, and relationships between objects.

IDataServiceQueryProvider

The IDataServiceQueryProvider interface allows actual querying of the data in a data service. The most important function of the lot is GetQueryRootForResourceSet, which must return an IQueryable for a specific resource set.

IDataServiceUpdateProvider

The IDataServiceUpdateProvider interface exposes functions to enable manipulation of the data we have defined in the Metadata Provider and exposed in the Query Provider. It allows data to be updated, deleted, etc.

Keeping Up To Date

The Composite Data Service Framework is hosted on CodePlex at: http://cdsf.codeplex.com/. The roadmap for the project is on the main page. I would welcome any suggestions or ideas! As this project develops, we will be completing the following tasks:

  • Allow an Entity Framework Model to be used as a Composite Data Source - without the need for a WCF Data Service to expose it first.
  • Allow collections of standard CLR objects to be used as a Composite Data Source.
  • Demonstrate customization of creating of the client-side Service Reference by showing how to create a special attribute used client side to mark a property as client-side only.
  • Demonstrate how Service Operation proxies can be generated automatically when adding the service reference.
  • Show how to extend Visual Studio with custom templates for items, projects, and show how to use Wizards to customize the generation of these items.

Further Reading

There is a great set of posts on Alex D James' blog 'Meta-Me' describing how to create custom data services - the first post is here: http://blogs.msdn.com/b/alexj/archive/2010/01/07/data-service-providers-getting-started.aspx.

The Composite Data Service Framework is hosted on CodePlex at: http://cdsf.codeplex.com/.

I post various articles about the ongoing development of my projects on my blog: http://www.dwmkerr.com.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)