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

Using Visual Studio to generate strong-typed OData client proxy

When we need to incorporate data from OData services in .NET Framework based applications, what would be the most straightforward and efficient means for consuming the services? The answer is using the strong-typed client proxy generated upon the WCF Data Service client library. And Visual Studio 2010 has provided GUI support on this through the Add Service Reference wizard.

Tip

Recipes in this book are using Visual Studio 2010 as the main development tool. However, generating OData client proxy via the Add Service Reference wizard has already been supported since Visual Studio 2008 SP1.

In this recipe, we will demonstrate how to generate a strong-typed OData client proxy in Visual Studio 2010 and use the generated proxy to consume the target OData service.

Getting ready

The sample OData service here is still built with WCF Data Service and uses the ADO.NET Entity Framework data model (Northwind database). And we will create a strong-typed client proxy in Visual Studio to consume the service. This proxy generation approach will be used many times over the entire book.

The source code for this recipe can be found in the \ch02\VSODataClientSln\ directory.

How to do it...

  1. Create a new ASP.NET web application, which contains the WCF Data Service based on the Northwind database (using ADO.NET Entity Framework data model).
  2. Create a new Console application as an OData client.
  3. Right-click on the project node in Visual Studio Solution Explorer and launch the proxy generation wizard by selecting the Add Service Reference... context menu (see the following screenshot).
    How to do it...
  4. Type the base address of the target OData service in the address bar of Add Service Reference dialog.

    In this sample, we will type the address of the local Northwind OData service (within the same solution) as follows:

    http://localhost:14944/NWDataService.svc/

    Optionally, you can click on the Go button to preview the entity sets exposed by the target OData service (see the following screenshot).

    How to do it...
  5. Click on the OK button (at the bottom of the dialog) to finish the proxy generation.
  6. Inspect the auto-generated proxy code by double-clicking on the service reference item in Visual Studio Class View or Object Browser.

    The following is the declaration of the classes within the auto-generated proxy code:

    public partial class NorthwindEntities : global::System.Data.Services.Client.DataServiceContext
    {
    ......
    }
    [global::System.Data.Services.Common.EntitySetAttribute("Categories")] [global::System.Data.Services.Common.DataServiceKeyAttribute("CategoryID")]
    public partial class Category : global::System.ComponentModel.INotifyPropertyChanged
    {
    ......
    }
    [global::System.Data.Services.Common.EntitySetAttribute("Products")] [global::System.Data.Services.Common.DataServiceKeyAttribute("ProductID")]
    public partial class Product : global::System.ComponentModel.INotifyPropertyChanged
    {
    ......
    }
    
  7. Use the generated proxy to query entity sets from the target service.

    The ListCategories function (see the following code snippet) creates an instance of the NorthwindEntities class and uses the Categories property to query all the Category entities.

    static void ListCategories()
    {
    var svcUri = new Uri("http://localhost:14944/NWDataService. svc/");
    var svc = new NWDataSvc.NorthwindEntities(svcUri);
    foreach (var cate in svc.Categories)
    {
    Console.WriteLine(
    "CategoryID:{0}, CategoryName:{1}",
    cate.CategoryID,
    cate.CategoryName
    );
    }
    }
    

    And we can use a similar method to retrieve all the Product entities (see the following ListProducts function).

    static void ListProducts()
    {
    var svcUri = new Uri("http://localhost:14944/NWDataService. svc/");
    var svc = new NWDataSvc.NorthwindEntities(svcUri);
    foreach (var prod in svc.Products)
    {
    // Load deferred property
    svc.LoadProperty(prod, "Category");
    Console.WriteLine(
    "ID:{0}, Name:{1},Category:{2}, UnitPrice:{3}, UnitsInStock:{4}",
    prod.ProductID,
    prod.ProductName,
    prod.Category.CategoryName,
    prod.UnitPrice,
    prod.UnitsInStock
    );
    }
    }
    
  8. Use the generated proxy to invoke service operations against the target OData service (see the following code snippet).
    static void ExecuteOperations()
    {
    var svcUri = new Uri("http://localhost:14944/NWDataService. svc/");
    var svc = new NWDataSvc.NorthwindEntities(svcUri);
    var operationUri =
    new Uri("GetProductCountByCategoryName?cateName= 'Beverages'", UriKind.Relative);
    var result = svc.Execute<int>(operationUri).First();
    Console.WriteLine("Result of 'GetProductCountByCategoryName' operation: {0}", result);
    }
    

How it works...

In this sample, the Visual Studio generated client proxy contains the following classes:

  • The NorthwindEntities class
  • The Category class
  • The Product class

The NorthwindEntities class derives from the DataServiceContext class under the System.Data.Services.Client namespace. This class represents the service data context at the client side and holds one or more entity collection properties (such as the Categories and Products properties in this case) corresponding to the entity sets exposed in the target OData service.

At runtime, we first construct an instance of the data context class (by supplying the URL address of the target OData service) and then use LINQ to Entity methods to query or change the required entity objects. The data context type instance will track all the changes that have been made against the entity objects held by it until the client submits the changes to the server side. This is quite similar to how we use the ADO.NET Entity Framework data model to access a database directly.

One thing worth noticing is that for those entity types which have navigation properties (such as the Products property on Category entity type), we need to load the navigation properties before using them. This is because the WCF Data Service client library uses the lazy loading pattern for entity collections associated through navigation properties. To load such properties, we need to call the LoadProperty method of the data context class (the NorthwindEntities class in this case) so as to make sure the data in the navigation properties is ready for using.

As we've discussed in Chapter 1, Building OData Services, an OData service can expose not only data entities, but also service operations, which can return either entities or custom data objects. With a Visual Studio generated client proxy, we can also easily invoke service operations against the target OData service. In this recipe, we've demonstrated how we can use the ExecuteOperations function (of the OData proxy class) to invoke the GetProductCountByCategoryName operation against the sample Northwind OData service.

When constructing the data context object, we have to pass in the base address of the OData service. The WCF Data Service client library uses this address to locate the target OData service and perform all the network communication with the target service under the hood. By using Fiddler or other HTTP sniffer tools, we can find out the underlying HTTP requests (send by the WCF Data Service client library) for querying the entity sets (see the following screenshot).

How it works...

And after the service sends the response back in either XML or JSON format (see the following screenshot), the client library will also help deserialize the response content into the proper entity objects or custom data objects.

How it works...

See also

  • Exploring an OData service through web browser recipe