Friday, August 01, 2008

ADO.NET Data Services: Creating a custom Data Context #1

Yesterday I wrote a quick overview of ADO.NET Data Services. We saw how it exposes a RESTfull API on top of any IQueryable<T> data source. The IQueryable<T> interface is of course at the core of any LINQ enabled data service. It's very easy to write your own custom Data Context if you already have a data source that supports IQueryable<T>. It's worth remembering that anything that provides IEnumerable<T> can be converted to IQueryable<T> by the AsQueryable() extension method, which means we can simply export an in-memory object graph in a RESTfull fashion with ADO.NET Data Services. That's what I'm going to show how to do today.

I got these techniques from an excellent MSDN Magazine article by Elisa Flasko and Mike Flasko, Expose And Consume Data in A Web Services World.

The first thing we need to do is provide a Domain Model to export. Here is an extremely simple example, two classes: Teacher and Course. Note that each entity must have an ID property that the Data Service can recognize as its primary key.

ado_net_im_model

For a read-only service (I'll show insert, update and delete in part 2) you simply need a data context that exports the entities of the domain model as IQueryable<T> properties:

using System.Linq;
using Mike.DataServices.Model;

namespace Mike.DataServices
{
   public class SchoolDataContext
   {
       private static Teacher[] teachers;
       private static Course[] courses;

       public SchoolDataContext()
       {
           var johnSmith = new Teacher
                                   {
                                       ID = 1,
                                       Name = "John Smith"
                                   };
           var fredJones = new Teacher
                                   {
                                       ID = 2,
                                       Name = "Fred Jones"
                                   };

           var programming101 = new Course
                                    {
                                        ID = 1,
                                        Name = "programming 101",
                                        Teacher = johnSmith
                                    };
           var howToMakeAnything = new Course
                                       {
                                           ID = 2,
                                           Name = "How to make anything",
                                           Teacher = johnSmith
                                       };
           johnSmith.Courses = new[] {programming101, howToMakeAnything};

           var yourInnerFish = new Course
                                   {
                                       ID = 3,
                                       Name = "Your inner fish",
                                       Teacher = fredJones
                                   };
           fredJones.Courses = new[] {yourInnerFish};

           teachers = new[] {johnSmith, fredJones};
           courses = new[] {programming101, howToMakeAnything, yourInnerFish};
       }

       public IQueryable<Teacher> Teachers
       {
           get { return teachers.AsQueryable(); }
       }

       public IQueryable<Course> Courses
       {
           get { return courses.AsQueryable(); }
       }
   }
}

Note that we're building our object graph in the constructor in this demo. In a realistic implementation you'd probably have your application create its model somewhere else.

Now we simply have to set the type parameter of the DataService to our data context (DataService<SchoolDataContext>):

using System.Data.Services;

namespace Mike.DataServices
{
   [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
   public class SchoolService : DataService<SchoolDataContext>
   {
       public static void InitializeService(IDataServiceConfiguration config)
       {
           config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
       }
   }
}

And we can query our model via our RESTfull API:

ado_net_im_ie_root

And here's all the courses that the first teacher teaches:

ado_net_im_ie_teachers_courses

Code is here:

http://static.mikehadlow.com/Mike.DataServices.InMemory.zip

No comments: