Sunday, October 28, 2012

Entity Framework 5 Code First and WCF Ria Services

Starting from a question on stackoverflow site, I thought it could be useful to publish a working sample of Entity Framework 5 and WCF ria Services tight together.
Everything it’s pretty simple but there are some not obvious pitfalls that can lead to tedious waste of time.
First thing to do, create a new Silverlight Application and don’t forget to put a mark on “Enable WCF RIA Services” as in the image below
image
then, server side, on the project that will host our silverlight application (here named EFCodeFirst _WCFRiaDemo.Web) right click the project, then select “Manage Nuget Packages”; look for entity framework then click on install as in the image below
image
In my demo I’ll use the domain model classes from another assembly, as an usual path with POCO domain model, so let’s reference in the EFCodeFirst _WCFRiaDemo.Web project the assembly that contains our classes.
I’ll use a very basic one
image
Please note the BlogId field in the Post class. It really looks like the db that is leaking into the model, and indeed it is, but… that’s the way WCF Ria Services work with relations. Just pretend not to see this field Sorriso
Then create the DbContext including the related mapping, as in the snip below
public class BlogContext : DbContext
    {
        public BlogContext() : 
            base("BlogContext")
        {

        }
        public DbSet<Blog> Blogs { get; protected set; }

        public DbSet<Post> Posts { get; protected set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //Here goes our custom mapping
            //we can comment out the row below and completely customize the entities mapping
            //base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<Post>()
                .HasRequired(x => x.Blog)
                .WithMany(x => x.Posts)
                .HasForeignKey(x => x.BlogId);


        }
    }


and in the web.config add the connection strings section and relevant info

<connectionStrings>
    <add name="BlogContext" connectionString="Data Source=.\SQLEXPRESS; AttachDBFilename=|DataDirectory|\WcfRiaDemo.mdf;Integrated Security=SSPI; MultipleActiveResultSets=True;User Instance=true" providerName="System.Data.SqlClient" />
</connectionStrings>


I’ve leveraged Package Manager Console to create my database running in it Enable-Migrations –EnableAutomaticMigrations

Now, our DbContext should be up and running, let’s add out DomainService class. I’m not a fan of shining wizard, so I’ll not leverage automatic DomainServices creation, taking into account that it needs some tricks in order to work with EF Code First. I’ll rather add a DbDomainService manually. Consider also, that this is the way you’ll normally deal with when adding classes and methods to your model.

In order to work with EntityFramework and take advantages of mapping info defined into the DbContext, we need to derive our DomainContext from the DbDomainService class. This is a class defined in the WCF Ria Services tookit, available here.

Then, “expose” our classes to the client, adding methods these

    [EnableClientAccess()]
    public class WCFRiaDemoDomainService : DbDomainService<BlogContext>
    {
        [Query]
        public IQueryable<Blog> GetBlogs()
        {
            return this.DbContext.Blogs;
        }

        [Query]
        public IQueryable<Post> GetPosts()
        {
            return this.DbContext.Posts;
        }
    }

The QueryAttribute  it’s not strictly needed as it will be picked from convention (the method returns an IQueryable<T>) however, I like to mark those methods.

Please note that I’m not exposing the related Insert/Delete/Update methods, so my entity will be generated as read-only.


Now come the tricky part: if we try to build the client it will NOT generate our DomainContext, but rather just the WebContext and no Classes.

This come from a version compatibility issue between the code generator and entitiy framework. The Code generator will look for EntityFramework v4.2, will of course not found it, and will not generate our classes and unfortunately will not notify us of such problem.

The solution I usually use rely on, is assembly binding redirect. Putting the lines below into our web.config will trick the code generator that finally will generate our proxy

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>



A final note: Consider that the proxy generator come in two flavours: the CodeDom generator (the one that we are using here) and the T4 based code generator. You can learn how to use and leverage it from the (no long updated) blog of varun puranik

That’s it for now. I’ve attached the solution for everyone to download and take a look.