Thursday, August 8, 2013

WCF Data Services with Entity Framework Provider

I wrote two posts about WCF Data Services sometimes back. First post was as Introduction to WCF Data Services and OData and the second one was WCF Data Services with Silverlight. This post will be a add-on to both these previous posts.

WCF Data Services supports multiple provider models for exposing data as an Open Data Protocol (OData) feed which are as follows. I am highlighting the main three of them.
  1. Entity Framework Provider
  2. Reflection Provider
  3. Custom Provider
  4. Streaming Provider
  5. Action Provider
Today let’s see how we can implement a WCF Data Service with Entity Framework Provider. If you have read my previous post on WCF Data Services with Silverlight, you might notice that I have used Entity Framework Provider there. But today let's cover up a more detailed post on WCF Data Services with Entity Framework Provider.

I have created a empty a ASP.NET web application. Now let’s start by adding a ADO.NET Entity Data Model to the project.

image
ADO.NET Entity Data Model
Now I am asked to create a model with existing database or to create a empty model. I am going with the Empty model, so we can learn all these from the scratch.

image
Empty Model
I am clicking finish and I am getting a empty model designer. Now let’s create some entities and add some associations.

I am right clicking on the designer and selecting Add New –> Entity called "Employee". I am creating a Key property which is “EmployeeId” and type I am leaving it as it is which is Int32.

image
Add Entity
image
Entity Added
Now I am right clicking on the Employee entity and adding some Scalar Properties which are “FirstName” and “LastName”. From the properties window of these Scalar Properties we can change the things like data type etc.

Same way I am creating two other entities which are “Department” and “JobRole”. Finally I am getting the following.

image
Entity Relationship Diagram without Associations
Now let’s create some associations. I am right clicking on the designer and selecting Add New->Association. I am creating a relationship between Employee and Department which is Employee can only belong to one Department and one Department can have many Employees.

image
Add Association
Same way I am creating a relationship between Employee and JobRole in which Employee can have many JobRoles and one JobRole can have many Employees.

image
Add Association
Once this is done I am getting the following model.

image
Entity Relationship Diagram with Associations
Now let’s right click on the designer and select “Generate Database from Model” to create a database from this model.

I have already created a blank database called “EFProviderDB” and let’s create a connection to this particular database.

image
Choose Data Source
image
Connection Properties
image
Generate Database Wizard
image
Generate Database Wizard
OK, Now what I have to do is run this query on the SQL Server Management Studio to create my tables and the relationships. After running the query I can see my tables got created and their relationships.

Now let’s add some data to expose via WCF Data Services.

image
Tables created in the database
Once the data is added to the tables, I am going to add new project item which is “WCF Data Service”.

image
WCF Data Service
The Visual Studio will create a service which is of WCF Data Service template.
public class WcfDataService1 : DataService< /* TODO: put your data source class name here */ >
{
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(DataServiceConfiguration config)
    {
        // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
        // Examples:
        // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
        // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
    }
}
In simple this is a service class which is derived from DataService of type T. It has a single static method which is InitializeService(…). What this class does is it will expose data in a particular context which is T.

Now I am going to modify this class. First I need to find out what the context is. For that I am opening the Model1.Context.cs and I am copying the the class name, in here it’s “Model1Container”. Now this is my data service type.

image
Exposing Context
Now I am modifying the InitializeService(…) method as follows. I am setting up a entity access rule for all the entities, so consumers can read all data.
public class WcfDataService1 : DataService<Model1Container>
{
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(DataServiceConfiguration config)
    {
        // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
        // Examples:
        config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
        // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
    }
}
I can even modify the method in the following way, so only two entities are exposed (“Employee” and “Department”) to outside.
public static void InitializeService(DataServiceConfiguration config)
{
    // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
    // Examples:
    config.SetEntitySetAccessRule("Employee", EntitySetRights.AllRead);
    config.SetEntitySetAccessRule("Department", EntitySetRights.AllRead);
    // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
    config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
You can set various rights here and it’s up to you to explore. For this demo I am exposing all the entities.

And that’s it.When I run the project I can see my WCF Data Service up and running.

image
Up and Running WCF Data Service
Now let’s see how we can consume this data service. I am creating a console application and adding a service reference to my created WCF Data Service.

Now I am writing the following code.
using ConsoleApplication1.svcWcfDataService;
using System;
using System.Linq; 

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Model1Container modelContext = new Model1Container(new Uri("http://localhost:51639/WcfDataService1.svc/"));
            var employees = from e in modelContext.Employees
                            select e;
            foreach (var e in employees)
            {
                Console.WriteLine("{0}, {1}", e.LastName, e.FirstName);
            }
            Console.ReadLine();
        }
    }
}

I am creating a object of my data context and then I have wrote a LINQ query to retrieve the data. Behind the scene what's happening is, the LINQ query get transformed into REST-like URI syntax and executes HTTP methods such as “GET”,“POST” etc based on my request.

I am attaching a sample project to my SkyDrive, so you can play around.


Appreciate your feedback.

Happy Coding.

Regards,
Jaliya

3 comments:

  1. i get this error on saving new entity and its a nighmare i dont understand what is the issue please help.

    please check:http://stackoverflow.com/questions/20313340/error-in-saving-using-wcf-data-sevices

    ReplyDelete
    Replies
    1. Hi,

      After this line, modelContext.AddToEmployees(NewEmp); Comment everything below and add modelContext.SaveChanges() and see.

      Delete
  2. this was very easy to follow - thank you for putting this together

    ReplyDelete