diff --git a/src/Core/Parsers/RequestParser.cs b/src/Core/Parsers/RequestParser.cs
index 081018e820..223cb3a38f 100644
--- a/src/Core/Parsers/RequestParser.cs
+++ b/src/Core/Parsers/RequestParser.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.Net;
+using System.Web;
using Azure.DataApiBuilder.Core.Models;
using Azure.DataApiBuilder.Core.Services;
using Azure.DataApiBuilder.Service.Exceptions;
@@ -321,6 +322,12 @@ private static bool IsNull(string value)
return null;
}
+ // Encode the parameterName to ensure it matches the encoding in the query string if the $ sign is URL encoded.
+ if (!queryString.Contains(parameterName, StringComparison.OrdinalIgnoreCase))
+ {
+ parameterName = HttpUtility.UrlEncode(parameterName);
+ }
+
// Split on '&' which are parameter separators in properly URL-encoded query strings.
// Any '&' characters within parameter values will be encoded as %26.
foreach (string param in queryString.TrimStart('?').Split('&'))
diff --git a/src/Service.Tests/Configuration/ConfigurationTests.cs b/src/Service.Tests/Configuration/ConfigurationTests.cs
index 203de98aef..71ef6ed6cf 100644
--- a/src/Service.Tests/Configuration/ConfigurationTests.cs
+++ b/src/Service.Tests/Configuration/ConfigurationTests.cs
@@ -4224,6 +4224,47 @@ public async Task OpenApi_InteractiveSwaggerUI(
}
}
+ ///
+ /// End to end test that validates that REST requests with OData query
+ /// options $filter and $orderby succeed to ensure no regression can occur.
+ ///
+ [DataTestMethod]
+ [DataRow("/api/Book?$orderby=id desc&$filter=publisher_id eq 1234", DisplayName = "REST URL without encoded characters")]
+ [DataRow("/api/Book?%24orderby=id%20desc&%24filter=publisher_id%20eq%201234", DisplayName = "REST URL with encoded characters")]
+ [TestCategory(TestCategory.MSSQL)]
+ public async Task TestForRestRequestsWithFilterAndOrderbyParameters(string restUri)
+ {
+ // The configuration file is constructed by merging hard-coded JSON strings to simulate the scenario where users manually edit the
+ // configuration file (instead of using CLI).
+ string configJson = TestHelper.AddPropertiesToJson(TestHelper.BASE_CONFIG, BOOK_ENTITY_JSON);
+ Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(
+ configJson,
+ out RuntimeConfig deserializedConfig,
+ replacementSettings: new(),
+ connectionString: GetConnectionStringFromEnvironmentConfig(environment: TestCategory.MSSQL)));
+ string configFileName = "custom-config.json";
+ File.WriteAllText(configFileName, deserializedConfig.ToJson());
+ string[] args = new[]
+ {
+ $"--ConfigFileName={configFileName}"
+ };
+
+ using (TestServer server = new(Program.CreateWebHostBuilder(args)))
+ using (HttpClient client = server.CreateClient())
+ {
+ // Act
+ using HttpRequestMessage restRequest = new(HttpMethod.Get, restUri);
+ using HttpResponseMessage restResponse = await client.SendAsync(restRequest);
+
+ // Assert - Verify REST response
+ Assert.AreEqual(HttpStatusCode.OK, restResponse.StatusCode, "REST request to auto-generated entity should succeed");
+
+ string restResponseBody = await restResponse.Content.ReadAsStringAsync();
+ Assert.IsTrue(!string.IsNullOrEmpty(restResponseBody), "REST response should contain data");
+ Assert.IsTrue(restResponseBody.Contains("\"publisher_id\":1234"));
+ }
+ }
+
///
/// Test different loglevel values that are avaliable by deserializing RuntimeConfig with specified LogLevel
/// and checks if value exists properly inside the deserialized RuntimeConfig.