Skip to content

Commit

Permalink
Fixes OData#1397: Conventional routing cannot identify the endpoint f…
Browse files Browse the repository at this point in the history
…or action to query property without the key
  • Loading branch information
xuzhg committed Jan 30, 2025
1 parent 0ceeb08 commit 5b87e2b
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ public static bool HasODataKeyParameter(this ActionModel action, IEdmEntityType

// TODO: shall we make sure the type is matching?
var keys = entityType.Key().ToArray();
if (keys.Length == 0)
{
return false;
}

if (keys.Length == 1)
{
// one key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,26 @@ public void NavigationRoutingConventionAddDollarCountAsExpectedBasedOnConfigurat
}
}

[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
public void NavigationRoutingConventionOnSingletonWithoutKeyDefinedOnEntityTypeAsExpectedBasedOnConfiguration(int paramerterCount)
{
// Arrange
ControllerModel controller = ControllerModelHelpers.BuildControllerModelWithAllActions<MainSupplierController>();
ActionModel action = controller.Actions.First(a => a.ActionName == "GetCustomers" && a.Parameters.Count == paramerterCount);

ODataControllerActionContext context = ODataControllerActionContextHelpers.BuildContext(string.Empty, EdmModel, controller);
context.Action = action;

// Act
bool returnValue = NavigationConvention.AppliesToAction(context);
Assert.True(returnValue);

Assert.Equal(["/MainSupplier/Customers", "/MainSupplier/Customers/$count"], action.Selectors.Select(s => s.AttributeRouteModel.Template));
}

[Theory]
[InlineData("PostToName")]
[InlineData("Get")]
Expand Down Expand Up @@ -285,6 +305,23 @@ private static IEdmModel GetEdmModel()
customers.AddNavigationTarget(subOrderNavProp, orders, new EdmPathExpression("NS.VipCustomer/SubOrder"));
me.AddNavigationTarget(subOrderNavProp, orders, new EdmPathExpression("NS.VipCustomer/SubOrder"));

// Let's build a singleton using an entity type without a key
// So 'Supplier' doesn't contain a key by design.
EdmEntityType supplier = new EdmEntityType("NS", "Supplier");
supplier.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String);
model.AddElement(supplier);

supplier.AddUnidirectionalNavigation(
new EdmNavigationPropertyInfo
{
Name = "Customers",
TargetMultiplicity = EdmMultiplicity.Many,
Target = customer,
ContainsTarget = true
});

container.AddSingleton("MainSupplier", supplier);

return model;
}

Expand Down Expand Up @@ -333,6 +370,18 @@ public void PatchToSubOrderFromVipCustomer(CancellationToken cancellation)
{ }
}

private class MainSupplierController
{
public void GetCustomers(int key, CancellationToken cancellation)
{ }

public void GetCustomers(int key)
{ }

public void GetCustomers()
{ }
}

private class UnknownController
{ }
}
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,25 @@ public void PropertyRoutingConventionAddDollarCountAsExpectedBasedOnConfiguratio
}
}

[Theory]
[InlineData(0)]
[InlineData(1)]
public void PropertyRoutingConventionOnSingletonWithoutKeyDefinedOnEntityTypeAsExpectedBasedOnConfiguration(int paramerterCount)
{
// Arrange
ControllerModel controller = ControllerModelHelpers.BuildControllerModelWithAllActions<MainSupplierController>();
ActionModel action = controller.Actions.First(a => a.ActionName == "GetName" && a.Parameters.Count == paramerterCount);

ODataControllerActionContext context = ODataControllerActionContextHelpers.BuildContext(string.Empty, EdmModel, controller);
context.Action = action;

// Act
bool returnValue = PropertyConvention.AppliesToAction(context);
Assert.True(returnValue);

Assert.Equal(["/MainSupplier/Name", "/MainSupplier/Name/$value"], action.Selectors.Select(s => s.AttributeRouteModel.Template));
}

[Theory]
[InlineData("PostToName")]
[InlineData("Get")]
Expand Down Expand Up @@ -294,6 +313,13 @@ private static IEdmModel GetEdmModel()
container.AddEntitySet("AnotherCustomers", customer);
container.AddSingleton("Me", customer);
model.AddElement(container);

// Let's build a singleton using an entity type without a key.
// So 'Supplier' doesn't contain a key by design.
EdmEntityType supplier = new EdmEntityType("NS", "Supplier");
supplier.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String);
model.AddElement(supplier);
container.AddSingleton("MainSupplier", supplier);
return model;
}

Expand Down Expand Up @@ -373,6 +399,18 @@ public void PostToSubLocationsOfUsAddressFromVipCustomer()
{ }
}

private class MainSupplierController
{
public void GetName()
{ }

public void GetName(int key)
{
// Be noted, the type of 'MainSupplier' doesn't contain a key.
// So, conventional routing doesn't care about the parameters.
}
}

private class AnotherCustomersController
{
public void PostToName(string keyLastName, string keyFirstName)
Expand Down

0 comments on commit 5b87e2b

Please sign in to comment.