OData Programming Cookbook for .NET Developers
上QQ阅读APP看书,第一时间看更新

Using custom data objects as the data source of WCF Data Service

So far we've explored several examples, which use relational database objects as the data provider (through Entity Framework, LINQ to SQL, or custom operations). However, we're definitely not limited to these data sources; WCF Data Service provides the flexibility for developers to use custom CLR objects as data sources.

In this recipe, we will see how to use custom data objects as a WCF Data Service data source and expose OData entitiy sets based on the data members of the custom data objects.

Getting ready

In this recipe, we will create a WCF Data Service for exposing some books and book categories information to clients. Instead of using ADO.NET Entity Framework or LINQ to SQL, we will define some custom CLR types to represent the data model of the sample service.

The source code for this recipe can be found in the \ch01\CLRObjDataServiceSln\ directory.

How to do it...

  1. Create a new ASP.NET Empty Web Application.
  2. Create custom CLR types to represent the book and book category items.

    The following code snippet shows the definition of the sample CLR types:

    namespace CLRObjDataService
    {
    [DataServiceKey("ISBN")]
    [DataServiceEntity]
    public class BookInfo
    {
    public string ISBN { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public DateTime PubDate { get; set; }
    public BookCategory Category { get; set; }
    }
    [DataServiceKey("Name")]
    [DataServiceEntity]
    public class BookCategory
    {
    public string Name { get; set; }
    public List<BookInfo> Books { get; set; }
    }
    }
    
  3. Create a data context type that acts as a container for entity sets based on the custom CLR types (defined in the previous step).

    The following is the code of the sample data context type (see the following BookServiceContext class), which exposes two entity sets based on the BookInfo and BookCategoryx classes:

    public class BookServiceContext
    {
    static IList<BookCategory> _categories = null;
    static IList<BookInfo> _books = null;
    public IQueryable<BookCategory> BookCategories
    {
    get
    {
    return _categories.AsQueryable();
    }
    }
    public IQueryable<BookInfo> Books
    {
    get
    {
    return _books.AsQueryable();
    }
    }
    }
    

    For demonstration, we have also defined a static constructor for generating some test data (see the following code snippet).

    static BookServiceContext()
    {
    _books = new List<BookInfo>();
    _categories = new List<BookCategory>();
    for(int i=1;i<=3;++ i)
    {
    var cate = new BookCategory() { Name = "Category_" + i.ToString() };
    cate.Books = new List<BookInfo>();
    for (int j = 1; j <= 3; ++j)
    {
    int bid = (i*10+j);
    var book = new BookInfo()
    {
    ISBN = "ISBN" + bid.ToString(),
    Title = "Book Title " + bid.ToString(),
    Author = "Author",
    PubDate = DateTime.Now,
    Category = cate
    };
    _books.Add(book);
    cate.Books.Add(book);
    }
    _categories.Add(cate);
    }
    }
    
  4. Create a new WCF Data Service and use the custom data context type as its data source.

    The following code snippet shows the sample BookDataService class, which uses the BookServiceContext class (created in previous step) as the data source parameter:

    public class BookDataService : DataService< BookServiceContext >
    {
    public static void InitializeService (DataServiceConfiguration config)
    {
    config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
    config.SetEntitySetAccessRule("*", EntitySetRights.All);
    }
    }
    

    Like the ADO.NET Entity Framework-based WCF Data Service, we also need to set the proper entity set access rules in the initialization function.

  5. Launch the service and view the custom data entity sets in the web browser.

    For the sample service, we can access the exposed entity sets at the following locations:

    • Book category entity set (http://[server]:[port]/BookDataService.svc/BookCategories)
    • Book entity set (http://[server]:[port]/BookDataService.svc/Books)

    We can also use the following URL to retrieve book entities that belong to a certain category entity:

    http://[server]:[port]/BookDataService.svc/BookCategories('Category_1')/Books

    The following screenshot shows the book entities that belong to the first category entity:

How to do it...

How it works...

Now, let's take a look at what makes these things work. As we can see, each entity set we expose in the sample service is coming from its corresponding member property defined in the data context type. Such member properties should be declared as IQueryable<Entity Type> type so that the WCF Data Service runtime can correctly locate them and expose them as entity sets in the service.

Tip

For a given entity type T, we can only define one member property (on the data context class), which returns IQueryable<T>. In other words, we cannot expose multiple entity sets using the same entity type.

For each custom entity type, we must specify a key property by using the DataServiceKeyAttribute attribute. This key property is used for identifying entity instances in a given entity set (just like the primary key for the relational table).

The BookCategory entity type has a Books property of the List<BookInfo> type. Such kind of entity collection properties will be automatically treated as Navigation properties on the target entity type. For OData clients, they can use these Navigation properties (by using relative URI address) to retrieve the associated subentities from the primary entity instance (see the previous sample code).

There's more...

We have discussed LINQ to SQL based data sources in the previous recipe. Actually, LINQ to SQL is a special case of a custom data object based data source, since the LINQ to SQL data model has already done most of the work for us. If you are interested in finding out more about building WCF Data Service data source with a custom CLR type, you can refer to the following MSDN reference:

Reflection Provider (WCF Data Services) available at http://msdn.microsoft.com/en-us/library/dd723653.aspx

See also

  • Adding custom operations on OData service recipe
  • Building an OData service with WCF Data Service and LINQ to SQL recipe