"
ASP.NET (snapshot 2017) Microsoft documentation and samples

Create a Singleton in OData v4 Using Web API 2.2

by Zoe Luo

Traditionally, an entity could only be accessed if it were encapsulated inside an entity set. But OData v4 provides two additional options, Singleton and Containment, both of which WebAPI 2.2 supports.

This article shows how to define a singleton in an OData endpoint in Web API 2.2. For information on what a singleton is and how you can benefit from using it, see Using a singleton to define your special entity. To create an OData V4 endpoint in Web API, see Create an OData v4 Endpoint Using ASP.NET Web API 2.2.

We’ll create a singleton in your Web API project using the following data model:

Data Model
Data Model

A singleton named Umbrella will be defined based on type Company, and an entity set named Employees will be defined based on type Employee.

The solution used in this tutorial can be downloaded from CodePlex.

Define the data model

  1. Define the CLR types.

    [!code-csharpMain]
       1:  /// <summary> 
       2:  /// Present the EntityType "Employee" 
       3:  /// </summary> 
       4:  public class Employee 
       5:  {     
       6:      public int ID { get; set; }     
       7:      public string Name { get; set; }  
       8:     
       9:      [Singleton]     
      10:      public Company Company { get; set; } 
      11:  } 
      12:  /// <summary> 
      13:  /// Present company category, which is an enum type 
      14:  /// </summary> 
      15:  public enum CompanyCategory 
      16:  { 
      17:      IT = 0,     
      18:      Communication = 1,     
      19:      Electronics = 2,     
      20:      Others = 3 
      21:  } 
      22:  /// <summary> 
      23:  /// Present the EntityType "Company" 
      24:  /// </summary> 
      25:  public class Company 
      26:  {
      27:       public int ID { get; set; }
      28:       public string Name { get; set; }
      29:       public Int64 Revenue { get; set; }
      30:       public CompanyCategory Category { get; set; }
      31:       public List<Employee> Employees { get; set; } 
      32:  }
  2. Generate the EDM model based on the CLR types.

    [!code-csharpMain]

       1:  public static IEdmModel GetEdmModel() 
       2:  { 
       3:      ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
       4:      builder.EntitySet<Employee>("Employees"); builder.Singleton<Company>("Umbrella");
       5:      builder.Namespace = typeof(Company).Namespace;
       6:      return builder.GetEdmModel(); 
       7:  }

    Here, builder.Singleton<Company>("Umbrella") tells the model builder to create a singleton named Umbrella in the EDM model.

    The generated metadata will look like the following:

    [!code-xmlMain]

       1:  <EntityContainer Name="Container"> 
       2:    <EntitySet Name="Employees" EntityType="ODataSingletonSample.Employee"> 
       3:      <NavigationPropertyBinding Path="Company" Target="Umbrella"/> 
       4:    </EntitySet> 
       5:    <Singleton Name="Umbrella" Type="ODataSingletonSample.Company"> 
       6:      <NavigationPropertyBinding Path="Employees" Target="Employees"/> 
       7:    </Singleton> 
       8:  </EntityContainer>

    From the metadata we can see that the navigation property Company in the Employees entity set is bound to the singleton Umbrella. The binding is done automatically by ODataConventionModelBuilder, since only Umbrella has the Company type. If there is any ambiguity in the model, you can use HasSingletonBinding to explicitly bind a navigation property to a singleton; HasSingletonBinding has the same effect as using the Singleton attribute in the CLR type definition:

    [!code-csharpMain]

       1:  EntitySetConfiguration<Employee> employeesConfiguration = 
       2:      builder.EntitySet<Employee>("Employees"); 
       3:  employeesConfiguration.HasSingletonBinding(c => c.Company, "Umbrella");

Define the singleton controller

Like the EntitySet controller, the singleton controller inherits from ODataController, and the singleton controller name should be [singletonName]Controller.

[!code-csharpMain]

   1:  public class UmbrellaController : ODataController 
   2:  {
   3:      public static Company Umbrella;
   4:      static UmbrellaController()
   5:      {
   6:          InitData();
   7:      }
   8:      private static void InitData()
   9:      {
  10:          Umbrella = new Company()
  11:          {
  12:              ID = 1,
  13:              Name = "Umbrella",
  14:              Revenue = 1000,
  15:              Category = CompanyCategory.Communication,
  16:              Employees = new List<Employee>()
  17:          };
  18:      } 
  19:  }

In order to handle different kinds of requests, actions are required to be pre-defined in the controller. Attribute routing is enabled by default in WebApi 2.2. For example, to define an action to handle querying Revenue from Company using attribute routing, use the following:

[!code-csharpMain]

   1:  [ODataRoute("Umbrella/Revenue")] 
   2:  public IHttpActionResult GetCompanyRevenue() 
   3:  {
   4:       return Ok(Umbrella.Revenue); 
   5:  }

If you are not willing to define attributes for each action, just define your actions following OData Routing Conventions. Since a key is not required for querying a singleton, the actions defined in the singleton controller are slightly different from actions defined in the entityset controller.

For reference, method signatures for every action definition in the singleton controller are listed below.

[!code-csharpMain]

   1:  // Get Singleton 
   2:  // ~/singleton 
   3:  public IHttpActionResult Get() 
   4:  public IHttpActionResult GetUmbrella() 
   5:   
   6:  // Get Singleton 
   7:  // ~/singleton/cast 
   8:  public IHttpActionResult GetFromSubCompany() 
   9:  public IHttpActionResult GetUmbrellaFromSubCompany() 
  10:   
  11:  // Get Singleton Property 
  12:  // ~/singleton/property  
  13:  public IHttpActionResult GetName() 
  14:  public IHttpActionResult GetNameFromCompany() 
  15:   
  16:  // Get Singleton Navigation Property 
  17:  // ~/singleton/navigation  
  18:  public IHttpActionResult GetEmployees() 
  19:  public IHttpActionResult GetEmployeesFromCompany() 
  20:   
  21:  // Update singleton by PUT 
  22:  // PUT ~/singleton 
  23:  public IHttpActionResult Put(Company newCompany) 
  24:  public IHttpActionResult PutUmbrella(Company newCompany) 
  25:   
  26:  // Update singleton by Patch 
  27:  // PATCH ~/singleton 
  28:  public IHttpActionResult Patch(Delta<Company> item) 
  29:  public IHttpActionResult PatchUmbrella(Delta<Company> item) 
  30:   
  31:  // Add navigation link to singleton 
  32:  // POST ~/singleton/navigation/$ref 
  33:  public IHttpActionResult CreateRef(string navigationProperty, [FromBody] Uri link) 
  34:   
  35:  // Delete navigation link from singleton 
  36:  // DELETE ~/singleton/navigation/$ref?$id=~/relatedKey 
  37:  public IHttpActionResult DeleteRef(string relatedKey, string navigationProperty) 
  38:   
  39:  // Add a new entity to singleton navigation property 
  40:  // POST ~/singleton/navigation 
  41:  public IHttpActionResult PostToEmployees([FromBody] Employee employee) 
  42:   
  43:  // Call function bounded to singleton 
  44:  // GET ~/singleton/function() 
  45:  public IHttpActionResult GetEmployeesCount()

Basically, this is all you need to do on the service side. The sample project contains all of the code for the solution and the OData client that shows how to use the singleton. The client is built by following the steps in Create an OData v4 Client App.

.

Thanks to Leo Hu for the original content of this article.



Comments ( )
Link to this page: //www.vb-net.com/AspNet-DocAndSamples-2017/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/using-a-singleton-in-an-odata-endpoint-in-web-api-22.htm
< THANKS ME>