EF CTP4 Tips & Tricks: WCF Data Service on DbContext

This is the fourth in a series of posts about the recently released Entity Framework Feature CTP4, now affectionately known as “EF Magic Unicorn Edition”.

For this post I’m going to assume you are somewhat familiar with the Productivity Improvements for EF and WCF Data Services.

You can download the completed VS2010 project from this post.

Update: If you want to use DbContext with Dynamic Data then you can use a similar approach as described in this post by Stephen Naughton.

Existing ObjectContext Experience

If you’ve used WCF Data Services on top of Entity Framework before then you would have added a new Entity Data Model to your project, which in turn creates a derived ObjectContext class to allow you to query and persist data using the model. Then you would have added a WCF Data Service class that derives from a DataService of your derived ObjectContext, something like this:

using System.Data.Services;
using System.Data.Services.Common;

namespace PI.WCFDataService.Sample
{
    public class BlogService : DataService<BlogContext>
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("Blogs", EntitySetRights.All);
            config.SetEntitySetAccessRule("Posts", EntitySetRights.All);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    }
}

What About DbContext?

Now what if your BlogContext derives from DbContext instead of ObjectContext? In the current CTP4 you can’t just create a DataService of a derived DbContext, although you can expect this to work by the time there is an RTM release.

But there is some good news, DbContext uses ObjectContext under the covers and you can get to the underlying context via a protected member. So lets define our derived context so that it exposes the context for our service to use:

using System.Data.Entity;
using System.Data.Objects;

namespace Service
{
    public class BlogContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }

        public ObjectContext UnderlyingContext
        {
            get { return this.ObjectContext; }
        }
    }
}

 

Now all we need to do is create a DataService of ObjectContext and override the CreateDataSource method. In CreateDataSource we will construct a BlogContext and then return the underlying ObjectContext. Note that we also need to turn off proxy creation to allow WCF Data Services to function correctly.

using System.Data.Objects;
using System.Data.Services;
using System.Data.Services.Common;

namespace Service
{
    public class BlogService : DataService<ObjectContext>
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("BlogSet", EntitySetRights.All);
            config.SetEntitySetAccessRule("PostSet", EntitySetRights.All);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }

        protected override ObjectContext CreateDataSource()
        {
            var ctx = new BlogContext();
            ctx.UnderlyingContext.ContextOptions.ProxyCreationEnabled = false;
            return ctx.UnderlyingContext;
        }
    }
}

 

That’s it, now WCF Data Services just thinks it’s interacting with a standard ObjectContext and everything works.

Entity Set Naming

If you are using the Code First capabilities of DbContext then your entity set names will be <ClassName>Set. Obviously this isn’t brilliant and is something that will improve in future releases. The likely solution is to use the name of the DbSet property that you defined on the derived context.

Virtual SaveChanges

One thing to note with this approach is that WCF Data Services is going to call SaveChanges on the underlying ObjectContext and not your derived context. This is only an issue if you have overridden SaveChanges in your derived context to include business logic because this logic won’t get executed when the Data Service persists changes to the database. There isn’t a workaround for this at the moment but the issue will go away once there is native support for DbContext in WCF Data Services.

Summary

You can use DbContext with WCF Data Services, it’s not 100% natively supported just yet but will be in the future. The code to get it to work is pretty simple and makes use of the underlying ObjectContext from your derived DbContext.