AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

Dynamically fetching property of a singleton entity in odata 8.0.11

Open stealth-17 opened this issue 3 years ago • 3 comments

Assemblies affected ASP.NET Core OData 8.0.11

Describe the bug When trying to fetch property of a singleton object, it fails with a 404. Is it possible to implement a single controller method which could fetch any property of a singleton/entity using reflection?

Reproduce steps

Program.cs

builder.Services.AddControllers()
    .AddOData(opt =>
    {
        var builder = new ODataConventionModelBuilder
        {
            Namespace = "MyOdataApp",
            ContainerName = "ODataAppContainer",
        };
        opt.EnableQueryFeatures();
        builder.Singleton<Warehouse>("warehouse");
        opt.AddRouteComponents("v1.0", builder.GetEdmModel());
    });

Controller

  [Route("v1.0/warehouse")]
  [ApiController]
  public class WarehouseController : ODataController
  {
      private readonly Warehouse warehouse = new Warehouse
      {
          Id = "w1",
          Name = "MyWarehouse",
          Products = new List<Product>
          {
              new Product
              {
                  Id = "1",
                  Name = "NoteBook",
                  Price = 25
              },
              new Product
              {
                  Id = "2",
                  Name = "Pen",
                  Price = 10
              },
              new Product
              {
                  Id = "3",
                  Name = "Pencil",
                  Price = 8
              },
              new Product
              {
                  Id = "4",
                  Name = "Bag",
                  Price = 250
              }
          }
      };
  
      [HttpGet]
      [EnableQuery]
      public IActionResult Get()
      {
          return Ok(warehouse);
      }
  
      [HttpGet("{propertyName}")]
      [EnableQuery]
      public IActionResult GetProperty(string propertyName)
      {
          var property = warehouse.GetType().GetProperty(propertyName);
          if (property != null)
          {
              return Ok(property.GetValue(warehouse));
          }
          return this.NotFound();
      }
  }

Data Model

public class Warehouse
{
    public string Id { get; set; }
    public string Name { get; set; }
    public List<Product> Products { get; set; }
}

public class Product
{
    public string Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set; }
}

EDM (CSDL) Model Please share your Edm model, for example, CSDL file.

<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
  <edmx:DataServices>
    <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="MyOdataApp">
        <EntityType Name="Warehouse">
          <Key>
          <PropertyRef Name="Id"/>
          </Key>
          <Property Name="Id" Type="Edm.String" Nullable="false"/>
          <Property Name="Name" Type="Edm.String" Nullable="false"/>
          <NavigationProperty Name="Products" Type="Collection(MyOdataApp.Product)"/>
        </EntityType>
      <EntityType Name="Product">
        <Key>
        <PropertyRef Name="Id"/>
        </Key>
        <Property Name="Id" Type="Edm.String" Nullable="false"/>
        <Property Name="Name" Type="Edm.String" Nullable="false"/>
        <Property Name="Price" Type="Edm.Decimal" Nullable="false" Scale="Variable"/>
      </EntityType>
      <EntityContainer Name="ODataAppContainer">
        <Singleton Name="warehouse" Type="MyOdataApp.Warehouse"/>
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

Request/Response Request GET https://localhost:7152/v1.0/warehouse/Products

Response Error: response status is 404

Expected behavior Should ideally return the products in the warehouse

stealth-17 avatar Sep 05 '22 09:09 stealth-17

  • https://github.com/OData/AspNetCoreOData/issues/440

julealgon avatar Sep 05 '22 12:09 julealgon

Any workaround to get this working?

stealth-17 avatar Sep 05 '22 13:09 stealth-17

Any workaround to get this working?

Not that I'm aware of. You'd have to implement it from scratch. I personally don't quite know how I'd do that too, maybe someone else can help, or you could look into the v7 codebase as a starting point.

I'd also suggest potentially broadening the scope of your issue here (as this is not exclusive to singletons, but applies to any entity), and using it to keep track of this as a v8 feature.

@xuzhg / @habbes any chance we can add NestedPaths support as a v8/vNext feature on the backlog? This would probably be a nice use-case for source generation in OData as well, avoiding the reflection costs altogether.

julealgon avatar Sep 05 '22 15:09 julealgon

@corranrogue9 Any updates on this issue? Currently I'm enumerating all properties of the singleton because lack of NestedPath support.

stealth-17 avatar Oct 18 '22 07:10 stealth-17