Skip to content

Commit

Permalink
Fix AutoExpand Issues with Capitalized $Expand System Query Options (#…
Browse files Browse the repository at this point in the history
…1292)

* Fix AutoExpand Issues with Capitalized $Expand System Query Options (#1292)
  • Loading branch information
WanjohiSammy authored Sep 6, 2024
1 parent 7bc661d commit a77ed76
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/Microsoft.AspNetCore.OData/Query/ODataQueryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ internal void AddAutoSelectExpandProperties()

private IDictionary<string, string> GetODataQueryParameters()
{
Dictionary<string, string> result = new Dictionary<string, string>();
Dictionary<string, string> result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

foreach (var query in Request.Query)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,22 @@ public IActionResult Put(int key, [FromBody] Customer customer)
public class PeopleController : ODataController
{
[EnableQuery(MaxExpansionDepth = 4)]
public IQueryable<People> Get()
public IQueryable<Person> Get()
{
return AutoExpandDataSource.People.AsQueryable();
}

[EnableQuery]
public IActionResult Get(int key)
{
Person person = AutoExpandDataSource.People.FirstOrDefault(c => c.Id == key);
if (person == null)
{
return NotFound($"Cannot find person with key = {key}");
}

return Ok(person);
}
}

public class NormalOrdersController : ODataController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ public class ZipCodeInfo
public string Code { get; set; }
}

public class People
public class Person
{
public int Id { get; set; }

[AutoExpand]
public Order Order { get; set; }

public People Friend { get; set; }
public Person Friend { get; set; }
}

public class Order
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.OData.E2E.Tests.AutoExpand
public class AutoExpandDataSource
{
private static IList<Customer> _customers;
private static IList<People> _people;
private static IList<Person> _people;
private static IList<NormalOrder> _normalOrders;

static AutoExpandDataSource()
Expand All @@ -26,7 +26,7 @@ static AutoExpandDataSource()

public static IList<Customer> Customers => _customers;

public static IList<People> People => _people;
public static IList<Person> People => _people;

public static IList<NormalOrder> NormalOrders => _normalOrders;

Expand Down Expand Up @@ -129,12 +129,12 @@ private static void GenerateCustomers()

public static void GeneratePeople()
{
_people = new List<People>();
_people = new List<Person>();

People previousPeople = null;
Person previousPerson = null;
for (int i = 1; i < 10; i++)
{
var people = new People
var person = new Person
{
Id = i,
Order = new Order
Expand All @@ -150,11 +150,11 @@ public static void GeneratePeople()

if (i > 1)
{
people.Friend = previousPeople;
person.Friend = previousPerson;
}

_people.Add(people);
previousPeople = people;
_people.Add(person);
previousPerson = person;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static IEdmModel GetEdmModel()
builder.EntityType<DerivedOrder>();
builder.EntityType<DerivedOrder2>();
builder.EntitySet<OrderDetail>("OrderDetails");
builder.EntitySet<People>("People");
builder.EntitySet<Person>("People");
builder.EntitySet<Menu>("EnableQueryMenus");
builder.EntitySet<Menu>("QueryOptionsOfTMenus");
builder.EntitySet<Tab>("Tabs");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Net;
using System.Net.Http;
Expand Down Expand Up @@ -69,7 +70,7 @@ public async Task QueryForAnResource_Includes_AutoExpandNavigationProperty(strin
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);

var customer = await response.Content.ReadAsObject<JObject>();
var customer = await response.Content.ReadAsObject<JObject>().ConfigureAwait(false);
this.output.WriteLine(customer.ToString());
Assert.Equal(customer.Properties().Count(), propCount);
VerifyOrderAndChoiceOrder(customer);
Expand All @@ -86,6 +87,150 @@ public async Task QueryForAnResource_Includes_AutoExpandNavigationProperty(strin
Assert.Null(friend["Order"]);
}

[Theory]
[InlineData("$select=Order", 1)]
[InlineData("$Select=Order", 1)]
[InlineData("$SELECT=Order", 1)]
[InlineData("select=Order", 1)]
public async Task QueryForResources_WithSelectQueryParam_SelectAutoExpandProperty(string queryParams, int propCount)
{
// Arrange
string queryUrl = $"autoexpand/People(1)?{queryParams}";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, queryUrl);
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json;odata.metadata=none"));
HttpClient client = CreateClient();

// Act
HttpResponseMessage response = await client.SendAsync(request);

// Assert
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);

var person = await response.Content.ReadAsObject<JObject>().ConfigureAwait(false);
Assert.Equal(person.Properties().Count(), propCount); // Only Order is selected
Assert.NotNull(person["Order"]);

VerifyOrderAndChoiceOrder(person);
}

[Theory]
[InlineData("$select=Id", 2)]
[InlineData("$Select=Id", 2)]
[InlineData("$SELECT=Id", 2)]
[InlineData("select=Id", 2)]
public async Task QueryForResources_WithSelectQueryParam_IncludesAutoSelectProperty(string queryParams, int propCount)
{
// Arrange
string queryUrl = $"autoexpand/People(1)?{queryParams}";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, queryUrl);
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json;odata.metadata=none"));
HttpClient client = CreateClient();

// Act
HttpResponseMessage response = await client.SendAsync(request);

// Assert
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);

var person = await response.Content.ReadAsObject<JObject>().ConfigureAwait(false);
Assert.Equal(person.Properties().Count(), propCount); // Id and Order are selected
Assert.NotNull(person["Order"]); // Order is auto-expanded
Assert.NotNull(person["Id"]);

VerifyOrderAndChoiceOrder(person);
}

[Theory]
[InlineData("$expand=Order", 2)]
[InlineData("$Expand=Order", 2)]
[InlineData("$EXPAND=Order", 2)]
[InlineData("expand=Order", 2)]
public async Task QueryForResources_WithExpandQueryParam_IncludesAutoExpandNavigationProperty(string queryParams, int propCount)
{
// Arrange
string queryUrl = $"autoexpand/People(1)?{queryParams}";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, queryUrl);
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json;odata.metadata=none"));
HttpClient client = CreateClient();

// Act
HttpResponseMessage response = await client.SendAsync(request);

// Assert
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);

var person = await response.Content.ReadAsObject<JObject>().ConfigureAwait(false);
Assert.Equal(person.Properties().Count(), propCount); // Id and Order are selected
Assert.NotNull(person["Order"]); // Order is auto-expanded
Assert.NotNull(person["Id"]);

VerifyOrderAndChoiceOrder(person);
}

[Theory]
[InlineData("$expand=Friend", 3)]
[InlineData("$Expand=Friend", 3)]
[InlineData("$EXPAND=Friend", 3)]
[InlineData("expand=Friend", 3)]
public async Task QueryForResources_WithExpandQueryParam_IncludesNonAutoExpandNavigationProperty(string queryParams, int propCount)
{
// Arrange
string queryUrl = $"autoexpand/People(1)?{queryParams}";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, queryUrl);
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json;odata.metadata=none"));
HttpClient client = CreateClient();

// Act
HttpResponseMessage response = await client.SendAsync(request);

// Assert
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);

var person = await response.Content.ReadAsObject<JObject>().ConfigureAwait(false);
Assert.Equal(person.Properties().Count(), propCount); // Id and Order are selected
Assert.NotNull(person["Order"]); // Order is auto-expanded
Assert.NotNull($"{person["Friend"]}"); // Friend is expanded
Assert.NotNull(person["Id"]);

VerifyOrderAndChoiceOrder(person);
}

[Theory]
[InlineData("$Expand=Order&Select=Friend", 3)]
[InlineData("Expand=Order&$Select=Order", 3)]
[InlineData("$Expand=Order,HomeAddress/CountryOrRegion($Select=Name)", 4)]
[InlineData("$Expand=HomeAddress/CountryOrRegion,HomeAddress/Microsoft.AspNetCore.OData.E2E.Tests.AutoExpand.UsAddress/ZipCode,Order($Expand=Choice)", 4)]
[InlineData("Expand=HomeAddress/Microsoft.AspNetCore.OData.E2E.Tests.AutoExpand.UsAddress/ZipCode", 4)]
[InlineData("Expand=Friend(Select=Order)&$Select=Order", 3)]
[InlineData("Select=Order&Expand=Order(Expand=Choice(Select=Amount))", 3)]
public async Task QueryForResources_WithExpandSelectQueryParamsCapitalized_IncludesAutoExpandNavigationProperty(string queryParams, int propCount)
{
// Arrange
string queryUrl = $"autoexpand/Customers(5)?{queryParams}";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, queryUrl);
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json;odata.metadata=none"));
HttpClient client = CreateClient();

// Act
HttpResponseMessage response = await client.SendAsync(request);

// Assert
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);

var customer = await response.Content.ReadAsObject<JObject>().ConfigureAwait(false);
VerifyNavigationProperties(customer, propCount);
}

private static void VerifyHomeAddress(JObject customer)
{
JObject homeAddress = customer["HomeAddress"] as JObject;
Expand Down Expand Up @@ -488,5 +633,22 @@ public async Task PutCustomer_AutoExpandNavigationProperties()
}
}
}

private void VerifyNavigationProperties(JObject responseContent, int propCount)
{
Assert.Equal(responseContent.Properties().Count(), propCount);
VerifyOrderAndChoiceOrder(responseContent);
VerifyHomeAddress(responseContent);

// level one
JObject friend = responseContent["Friend"] as JObject;
JObject order = friend["Order"] as JObject;
Assert.NotNull(order);
Assert.Null(order["Choice"]);

// level two
friend = friend["Friend"] as JObject;
Assert.Null(friend["Order"]);
}
}
}

0 comments on commit a77ed76

Please sign in to comment.