From 08f741c41ddae4d6ca0ad8e849cb5b727554d1f2 Mon Sep 17 00:00:00 2001 From: KobeLenjou Date: Fri, 16 Aug 2024 11:41:11 +0200 Subject: [PATCH 1/9] pp --- Dockerfile | 6 ++-- src/Auth/Azure.DataApiBuilder.Auth.csproj | 2 +- src/Cli.Tests/Cli.Tests.csproj | 2 +- src/Cli/Cli.csproj | 2 +- src/Config/Azure.DataApiBuilder.Config.csproj | 2 +- src/Core/Azure.DataApiBuilder.Core.csproj | 2 +- src/Directory.Packages.props | 4 +-- .../Azure.DataApiBuilder.Product.csproj | 2 +- ...taApiBuilder.Service.GraphQLBuilder.csproj | 2 +- .../Azure.DataApiBuilder.Service.Tests.csproj | 2 +- src/Service/.config/dotnet-tools.json | 5 ++++ .../Azure.DataApiBuilder.Service.csproj | 7 +++-- .../PublishProfiles/crweudev01.pubxml | 30 +++++++++++++++++++ 13 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 src/Service/.config/dotnet-tools.json create mode 100644 src/Service/Properties/PublishProfiles/crweudev01.pubxml diff --git a/Dockerfile b/Dockerfile index 5dbaa35a17..537ea4c78c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ # Version values referenced from https://hub.docker.com/_/microsoft-dotnet-aspnet -FROM mcr.microsoft.com/dotnet/sdk:6.0-cbl-mariner2.0. AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY [".", "./"] -RUN dotnet build "./src/Service/Azure.DataApiBuilder.Service.csproj" -c Docker -o /out -r linux-x64 +RUN dotnet build "./src/Service/Azure.DataApiBuilder.Service.csproj" -f net8.0 -o /out -r linux-x64 --self-contained -FROM mcr.microsoft.com/dotnet/aspnet:6.0-cbl-mariner2.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime COPY --from=build /out /App WORKDIR /App diff --git a/src/Auth/Azure.DataApiBuilder.Auth.csproj b/src/Auth/Azure.DataApiBuilder.Auth.csproj index 9f63cd3ed6..1ee2df57b8 100644 --- a/src/Auth/Azure.DataApiBuilder.Auth.csproj +++ b/src/Auth/Azure.DataApiBuilder.Auth.csproj @@ -1,7 +1,7 @@ - net8.0;net6.0 + net8.0 enable enable $(BaseOutputPath)\engine diff --git a/src/Cli.Tests/Cli.Tests.csproj b/src/Cli.Tests/Cli.Tests.csproj index 46192e3802..a8081f5250 100644 --- a/src/Cli.Tests/Cli.Tests.csproj +++ b/src/Cli.Tests/Cli.Tests.csproj @@ -1,7 +1,7 @@ - net8.0;net6.0 + net8.0 enable enable false diff --git a/src/Cli/Cli.csproj b/src/Cli/Cli.csproj index fec0cc9786..5321f52356 100644 --- a/src/Cli/Cli.csproj +++ b/src/Cli/Cli.csproj @@ -2,7 +2,7 @@ Exe - net8.0;net6.0 + net8.0 Cli enable enable diff --git a/src/Config/Azure.DataApiBuilder.Config.csproj b/src/Config/Azure.DataApiBuilder.Config.csproj index 501f10bc22..cf739f24ec 100644 --- a/src/Config/Azure.DataApiBuilder.Config.csproj +++ b/src/Config/Azure.DataApiBuilder.Config.csproj @@ -1,7 +1,7 @@ - net8.0;net6.0 + net8.0 enable enable $(BaseOutputPath)\engine diff --git a/src/Core/Azure.DataApiBuilder.Core.csproj b/src/Core/Azure.DataApiBuilder.Core.csproj index d8e314d78d..e2cc111979 100644 --- a/src/Core/Azure.DataApiBuilder.Core.csproj +++ b/src/Core/Azure.DataApiBuilder.Core.csproj @@ -1,7 +1,7 @@ - net8.0;net6.0 + net8.0 enable enable true diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index b33dd9cc9e..ef2add3302 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -20,7 +20,7 @@ - + @@ -66,4 +66,4 @@ - + \ No newline at end of file diff --git a/src/Product/Azure.DataApiBuilder.Product.csproj b/src/Product/Azure.DataApiBuilder.Product.csproj index f0d0e70927..6045200487 100644 --- a/src/Product/Azure.DataApiBuilder.Product.csproj +++ b/src/Product/Azure.DataApiBuilder.Product.csproj @@ -1,7 +1,7 @@ - net8.0;net6.0 + net8.0 enable enable $(BaseOutputPath)\engine diff --git a/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj b/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj index 649e46c550..87eab3c75b 100644 --- a/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj +++ b/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj @@ -1,7 +1,7 @@ - net8.0;net6.0 + net8.0 enable enable $(BaseOutputPath)\engine diff --git a/src/Service.Tests/Azure.DataApiBuilder.Service.Tests.csproj b/src/Service.Tests/Azure.DataApiBuilder.Service.Tests.csproj index 112cb64714..26a2204725 100644 --- a/src/Service.Tests/Azure.DataApiBuilder.Service.Tests.csproj +++ b/src/Service.Tests/Azure.DataApiBuilder.Service.Tests.csproj @@ -1,7 +1,7 @@ - net8.0;net6.0 + net8.0 false disable $(BaseOutputPath)\tests diff --git a/src/Service/.config/dotnet-tools.json b/src/Service/.config/dotnet-tools.json new file mode 100644 index 0000000000..b0e38abdac --- /dev/null +++ b/src/Service/.config/dotnet-tools.json @@ -0,0 +1,5 @@ +{ + "version": 1, + "isRoot": true, + "tools": {} +} \ No newline at end of file diff --git a/src/Service/Azure.DataApiBuilder.Service.csproj b/src/Service/Azure.DataApiBuilder.Service.csproj index 710048b9fa..4d32c53912 100644 --- a/src/Service/Azure.DataApiBuilder.Service.csproj +++ b/src/Service/Azure.DataApiBuilder.Service.csproj @@ -1,7 +1,7 @@ - net8.0;net6.0 + net8.0 Debug;Release;Docker $(BaseOutputPath)\engine win-x64;linux-x64;osx-x64 @@ -36,6 +36,10 @@ True + + True + + $(CopyToOutputDirectoryAction) @@ -45,7 +49,6 @@ - diff --git a/src/Service/Properties/PublishProfiles/crweudev01.pubxml b/src/Service/Properties/PublishProfiles/crweudev01.pubxml new file mode 100644 index 0000000000..a785ab2cac --- /dev/null +++ b/src/Service/Properties/PublishProfiles/crweudev01.pubxml @@ -0,0 +1,30 @@ + + + + + Container + NetSdk + /subscriptions/d81425a2-a8ea-4ea4-9bdd-ca9db5cdfbc6/resourceGroups/rg-weu-api/providers/Microsoft.ContainerRegistry/registries/crweudev01 + crweudev01 + rg-weu-api + sub-mdm-weu-dev + crweudev01.azurecr.io + + latest + ContainerRegistry + Release + Any CPU + linux-x64 + 208fc26c-a21c-4c96-98ee-f10fdaeac508 + <_TargetId>NetSdkAzureContainerRegistry + + true + false + net8.0 + true + true + true + + \ No newline at end of file From b4239d0d5b09ac747a02138dc0e36a7dd228ced7 Mon Sep 17 00:00:00 2001 From: KobeLenjou Date: Tue, 20 Aug 2024 22:18:09 +0200 Subject: [PATCH 2/9] Preserve original roles claim and allow session context updates Added a new constant `ORIGINAL_ROLE_CLAIM_TYPE` in `AuthenticationOptions.cs` to store the original roles claim type. Modified `AuthorizationResolver` to preserve the original 'roles' claim by adding it to the `resolvedClaims` dictionary under the new key. Changed `MsSqlQueryExecutor` to set session context parameters with `@read_only = 0` to allow modifications. --- src/Config/ObjectModel/AuthenticationOptions.cs | 1 + src/Core/Authorization/AuthorizationResolver.cs | 7 ++++++- src/Core/Resolvers/MsSqlQueryExecutor.cs | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Config/ObjectModel/AuthenticationOptions.cs b/src/Config/ObjectModel/AuthenticationOptions.cs index 189540fbe6..6750d6e807 100644 --- a/src/Config/ObjectModel/AuthenticationOptions.cs +++ b/src/Config/ObjectModel/AuthenticationOptions.cs @@ -17,6 +17,7 @@ public record AuthenticationOptions(string Provider = nameof(EasyAuthType.Static public const string CLIENT_PRINCIPAL_HEADER = "X-MS-CLIENT-PRINCIPAL"; public const string NAME_CLAIM_TYPE = "name"; public const string ROLE_CLAIM_TYPE = "roles"; + public const string ORIGINAL_ROLE_CLAIM_TYPE = "original_roles"; /// /// Returns whether the configured Provider matches an diff --git a/src/Core/Authorization/AuthorizationResolver.cs b/src/Core/Authorization/AuthorizationResolver.cs index 64785de703..f368eed5f5 100644 --- a/src/Core/Authorization/AuthorizationResolver.cs +++ b/src/Core/Authorization/AuthorizationResolver.cs @@ -604,9 +604,14 @@ public static Dictionary> GetAllAuthenticatedUserClaims(Http // into a list and storing that in resolvedClaims using the claimType as the key. foreach (Claim claim in identity.Claims) { - // 'roles' claim has already been processed. + // 'roles' claim has already been processed. But we preserve the original 'roles' claim if (claim.Type.Equals(AuthenticationOptions.ROLE_CLAIM_TYPE)) { + if(!resolvedClaims.TryAdd(AuthenticationOptions.ORIGINAL_ROLE_CLAIM_TYPE, new List() { claim })) + { + resolvedClaims[AuthenticationOptions.ORIGINAL_ROLE_CLAIM_TYPE].Add(claim); + } + continue; } diff --git a/src/Core/Resolvers/MsSqlQueryExecutor.cs b/src/Core/Resolvers/MsSqlQueryExecutor.cs index 96f82cfa25..389256049f 100644 --- a/src/Core/Resolvers/MsSqlQueryExecutor.cs +++ b/src/Core/Resolvers/MsSqlQueryExecutor.cs @@ -217,9 +217,9 @@ public override string GetSessionParamsQuery(HttpContext? httpContext, IDictiona foreach ((string claimType, string claimValue) in sessionParams) { string paramName = $"{SESSION_PARAM_NAME}{counter.Next()}"; - parameters.Add(paramName, new(claimValue)); + parameters.Add(paramName, new(claimValue)); // Append statement to set read only param value - can be set only once for a connection. - string statementToSetReadOnlyParam = "EXEC sp_set_session_context " + $"'{claimType}', " + paramName + ", @read_only = 1;"; + string statementToSetReadOnlyParam = "EXEC sp_set_session_context " + $"'{claimType}', " + paramName + ", @read_only = 0;"; sessionMapQuery = sessionMapQuery.Append(statementToSetReadOnlyParam); } From 132a46eb42cc98e2affcc005bd80a9116f913c33 Mon Sep 17 00:00:00 2001 From: KobeLenjou Date: Tue, 20 Aug 2024 22:38:54 +0200 Subject: [PATCH 3/9] Revert "pp" This reverts commit 08f741c41ddae4d6ca0ad8e849cb5b727554d1f2. --- Dockerfile | 6 ++-- src/Auth/Azure.DataApiBuilder.Auth.csproj | 2 +- src/Cli.Tests/Cli.Tests.csproj | 2 +- src/Cli/Cli.csproj | 2 +- src/Config/Azure.DataApiBuilder.Config.csproj | 2 +- src/Core/Azure.DataApiBuilder.Core.csproj | 2 +- src/Directory.Packages.props | 4 +-- .../Azure.DataApiBuilder.Product.csproj | 2 +- ...taApiBuilder.Service.GraphQLBuilder.csproj | 2 +- .../Azure.DataApiBuilder.Service.Tests.csproj | 2 +- src/Service/.config/dotnet-tools.json | 5 ---- .../Azure.DataApiBuilder.Service.csproj | 7 ++--- .../PublishProfiles/crweudev01.pubxml | 30 ------------------- 13 files changed, 15 insertions(+), 53 deletions(-) delete mode 100644 src/Service/.config/dotnet-tools.json delete mode 100644 src/Service/Properties/PublishProfiles/crweudev01.pubxml diff --git a/Dockerfile b/Dockerfile index 537ea4c78c..5dbaa35a17 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ # Version values referenced from https://hub.docker.com/_/microsoft-dotnet-aspnet -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:6.0-cbl-mariner2.0. AS build WORKDIR /src COPY [".", "./"] -RUN dotnet build "./src/Service/Azure.DataApiBuilder.Service.csproj" -f net8.0 -o /out -r linux-x64 --self-contained +RUN dotnet build "./src/Service/Azure.DataApiBuilder.Service.csproj" -c Docker -o /out -r linux-x64 -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:6.0-cbl-mariner2.0 AS runtime COPY --from=build /out /App WORKDIR /App diff --git a/src/Auth/Azure.DataApiBuilder.Auth.csproj b/src/Auth/Azure.DataApiBuilder.Auth.csproj index 1ee2df57b8..9f63cd3ed6 100644 --- a/src/Auth/Azure.DataApiBuilder.Auth.csproj +++ b/src/Auth/Azure.DataApiBuilder.Auth.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net6.0 enable enable $(BaseOutputPath)\engine diff --git a/src/Cli.Tests/Cli.Tests.csproj b/src/Cli.Tests/Cli.Tests.csproj index a8081f5250..46192e3802 100644 --- a/src/Cli.Tests/Cli.Tests.csproj +++ b/src/Cli.Tests/Cli.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net6.0 enable enable false diff --git a/src/Cli/Cli.csproj b/src/Cli/Cli.csproj index 5321f52356..fec0cc9786 100644 --- a/src/Cli/Cli.csproj +++ b/src/Cli/Cli.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net8.0;net6.0 Cli enable enable diff --git a/src/Config/Azure.DataApiBuilder.Config.csproj b/src/Config/Azure.DataApiBuilder.Config.csproj index cf739f24ec..501f10bc22 100644 --- a/src/Config/Azure.DataApiBuilder.Config.csproj +++ b/src/Config/Azure.DataApiBuilder.Config.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net6.0 enable enable $(BaseOutputPath)\engine diff --git a/src/Core/Azure.DataApiBuilder.Core.csproj b/src/Core/Azure.DataApiBuilder.Core.csproj index e2cc111979..d8e314d78d 100644 --- a/src/Core/Azure.DataApiBuilder.Core.csproj +++ b/src/Core/Azure.DataApiBuilder.Core.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net6.0 enable enable true diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index ef2add3302..b33dd9cc9e 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -20,7 +20,7 @@ - + @@ -66,4 +66,4 @@ - \ No newline at end of file + diff --git a/src/Product/Azure.DataApiBuilder.Product.csproj b/src/Product/Azure.DataApiBuilder.Product.csproj index 6045200487..f0d0e70927 100644 --- a/src/Product/Azure.DataApiBuilder.Product.csproj +++ b/src/Product/Azure.DataApiBuilder.Product.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net6.0 enable enable $(BaseOutputPath)\engine diff --git a/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj b/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj index 87eab3c75b..649e46c550 100644 --- a/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj +++ b/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net6.0 enable enable $(BaseOutputPath)\engine diff --git a/src/Service.Tests/Azure.DataApiBuilder.Service.Tests.csproj b/src/Service.Tests/Azure.DataApiBuilder.Service.Tests.csproj index 26a2204725..112cb64714 100644 --- a/src/Service.Tests/Azure.DataApiBuilder.Service.Tests.csproj +++ b/src/Service.Tests/Azure.DataApiBuilder.Service.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net6.0 false disable $(BaseOutputPath)\tests diff --git a/src/Service/.config/dotnet-tools.json b/src/Service/.config/dotnet-tools.json deleted file mode 100644 index b0e38abdac..0000000000 --- a/src/Service/.config/dotnet-tools.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": {} -} \ No newline at end of file diff --git a/src/Service/Azure.DataApiBuilder.Service.csproj b/src/Service/Azure.DataApiBuilder.Service.csproj index 4d32c53912..710048b9fa 100644 --- a/src/Service/Azure.DataApiBuilder.Service.csproj +++ b/src/Service/Azure.DataApiBuilder.Service.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net6.0 Debug;Release;Docker $(BaseOutputPath)\engine win-x64;linux-x64;osx-x64 @@ -36,10 +36,6 @@ True - - True - - $(CopyToOutputDirectoryAction) @@ -49,6 +45,7 @@ + diff --git a/src/Service/Properties/PublishProfiles/crweudev01.pubxml b/src/Service/Properties/PublishProfiles/crweudev01.pubxml deleted file mode 100644 index a785ab2cac..0000000000 --- a/src/Service/Properties/PublishProfiles/crweudev01.pubxml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Container - NetSdk - /subscriptions/d81425a2-a8ea-4ea4-9bdd-ca9db5cdfbc6/resourceGroups/rg-weu-api/providers/Microsoft.ContainerRegistry/registries/crweudev01 - crweudev01 - rg-weu-api - sub-mdm-weu-dev - crweudev01.azurecr.io - - latest - ContainerRegistry - Release - Any CPU - linux-x64 - 208fc26c-a21c-4c96-98ee-f10fdaeac508 - <_TargetId>NetSdkAzureContainerRegistry - - true - false - net8.0 - true - true - true - - \ No newline at end of file From 19e9dbccde9f994665f638d80477e45478ff706d Mon Sep 17 00:00:00 2001 From: KobeLenjou Date: Wed, 21 Aug 2024 09:11:40 +0200 Subject: [PATCH 4/9] Adjust the relevant tests --- .../Authorization/AuthorizationResolverUnitTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Service.Tests/Authorization/AuthorizationResolverUnitTests.cs b/src/Service.Tests/Authorization/AuthorizationResolverUnitTests.cs index 3c7c31a8ca..733ec15b24 100644 --- a/src/Service.Tests/Authorization/AuthorizationResolverUnitTests.cs +++ b/src/Service.Tests/Authorization/AuthorizationResolverUnitTests.cs @@ -1293,7 +1293,8 @@ public void UniqueClaimsResolvedForDbPolicy_SessionCtx_Usage() new("sub", "Aa_0RISCzzZ-abC1De2fGHIjKLMNo123pQ4rStUVWXY"), new("oid", "55296aad-ea7f-4c44-9a4c-bb1e8d43a005"), new(AuthenticationOptions.ROLE_CLAIM_TYPE, TEST_ROLE), - new(AuthenticationOptions.ROLE_CLAIM_TYPE, "ROLE2") + new(AuthenticationOptions.ROLE_CLAIM_TYPE, "ROLE2"), + new(AuthenticationOptions.ROLE_CLAIM_TYPE, "ROLE3") }; //Add identity object to the Mock context object. @@ -1315,6 +1316,7 @@ public void UniqueClaimsResolvedForDbPolicy_SessionCtx_Usage() Assert.AreEqual(expected: "Aa_0RISCzzZ-abC1De2fGHIjKLMNo123pQ4rStUVWXY", actual: claimsInRequestContext["sub"], message: "Expected the sub claim to be present."); Assert.AreEqual(expected: "55296aad-ea7f-4c44-9a4c-bb1e8d43a005", actual: claimsInRequestContext["oid"], message: "Expected the oid claim to be present."); Assert.AreEqual(claimsInRequestContext[AuthenticationOptions.ROLE_CLAIM_TYPE], actual: TEST_ROLE, message: "The roles claim should have the value:" + TEST_ROLE); + Assert.AreEqual(expected: "[\"" + TEST_ROLE + "\",\"ROLE2\",\"ROLE3\"]", actual: claimsInRequestContext[AuthenticationOptions.ORIGINAL_ROLE_CLAIM_TYPE], message: "Original roles should be preserved in a new context"); } /// @@ -1365,7 +1367,7 @@ public void ValidateUnauthenticatedUserClaimsAreNotResolvedWhenProcessingUserCla Dictionary resolvedClaims = AuthorizationResolver.GetProcessedUserClaims(context.Object); // Assert - Assert.AreEqual(expected: authenticatedUserclaims.Count, actual: resolvedClaims.Count, message: "Only two claims should be present."); + Assert.AreEqual(expected: authenticatedUserclaims.Count + 1, actual: resolvedClaims.Count, message: "Only " + (authenticatedUserclaims.Count + 1) + " claims should be present."); Assert.AreEqual(expected: "openid", actual: resolvedClaims["scp"], message: "Unexpected scp claim returned."); bool didResolveUnauthenticatedRoleClaim = resolvedClaims[AuthenticationOptions.ROLE_CLAIM_TYPE] == "Don't_Parse_This_Role"; From d10be7a25eff097104f19fa88815f93b23b6f2cb Mon Sep 17 00:00:00 2001 From: M4Al Date: Fri, 30 Aug 2024 09:50:44 +0200 Subject: [PATCH 5/9] Update src/Core/Resolvers/MsSqlQueryExecutor.cs remove trailing space Co-authored-by: Aniruddh Munde --- src/Core/Resolvers/MsSqlQueryExecutor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Resolvers/MsSqlQueryExecutor.cs b/src/Core/Resolvers/MsSqlQueryExecutor.cs index 389256049f..1ac61f7dfb 100644 --- a/src/Core/Resolvers/MsSqlQueryExecutor.cs +++ b/src/Core/Resolvers/MsSqlQueryExecutor.cs @@ -217,7 +217,7 @@ public override string GetSessionParamsQuery(HttpContext? httpContext, IDictiona foreach ((string claimType, string claimValue) in sessionParams) { string paramName = $"{SESSION_PARAM_NAME}{counter.Next()}"; - parameters.Add(paramName, new(claimValue)); + parameters.Add(paramName, new(claimValue)); // Append statement to set read only param value - can be set only once for a connection. string statementToSetReadOnlyParam = "EXEC sp_set_session_context " + $"'{claimType}', " + paramName + ", @read_only = 0;"; sessionMapQuery = sessionMapQuery.Append(statementToSetReadOnlyParam); From 4c5a5b869ce8c72fedea06c370ec8885b317b3a2 Mon Sep 17 00:00:00 2001 From: KobeLenjou Date: Tue, 3 Sep 2024 23:35:39 +0200 Subject: [PATCH 6/9] Add recordcount --- src/Core/Resolvers/DWSqlQueryBuilder.cs | 44 ++++++++++++++++++++++-- src/Core/Resolvers/SqlResponseHelpers.cs | 27 +++++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/Core/Resolvers/DWSqlQueryBuilder.cs b/src/Core/Resolvers/DWSqlQueryBuilder.cs index e1768a97df..780c477364 100644 --- a/src/Core/Resolvers/DWSqlQueryBuilder.cs +++ b/src/Core/Resolvers/DWSqlQueryBuilder.cs @@ -46,8 +46,21 @@ public string Build(SqlQueryStructure structure) /// private string BuildAsJson(SqlQueryStructure structure, bool subQueryStructure = false) { + string subQueryAlias = "CountQuery"; + + string countSql = $" CROSS JOIN ( {BuildSqlCountQuery(structure)} ) {subQueryAlias}"; + + //Add a new column to the structure + structure.Columns.Add(new LabelledColumn("", subQueryAlias, "RecordCount", "RecordCount", subQueryAlias)); + + //Add a subquery 'a' ti the structure + structure.JoinQueries.Add(subQueryAlias, structure); + string columns = GenerateColumnsAsJson(structure, subQueryStructure); - string fromSql = $"{BuildSqlQuery(structure)}"; + + structure.JoinQueries.Remove(subQueryAlias); + + string fromSql = $"{BuildSqlQuery(structure, countSql)}"; string query = $"SELECT {columns}" + $" FROM ({fromSql}) AS {QuoteIdentifier(structure.SourceAlias)}"; return query; @@ -64,7 +77,7 @@ private string BuildAsJson(SqlQueryStructure structure, bool subQueryStructure = /// FROM dbo_books AS[table0] /// OUTER APPLY(SubQuery generated by recursive call to build function, will create the _subq tables) /// - private string BuildSqlQuery(SqlQueryStructure structure) + private string BuildSqlQuery(SqlQueryStructure structure, string? subQuery) { string dataIdent = QuoteIdentifier(SqlQueryStructure.DATA_IDENT); StringBuilder fromSql = new(); @@ -87,11 +100,38 @@ private string BuildSqlQuery(SqlQueryStructure structure) string query = $"SELECT TOP {structure.Limit()} {columns}" + $" FROM {fromSql}" + + $" {subQuery}" + $" WHERE {predicates}" + orderBy; return query; } + private string BuildSqlCountQuery(SqlQueryStructure structure) + { + string dataIdent = QuoteIdentifier(SqlQueryStructure.DATA_IDENT); + StringBuilder fromSql = new(); + + fromSql.Append($"{QuoteIdentifier(structure.DatabaseObject.SchemaName)}.{QuoteIdentifier(structure.DatabaseObject.Name)} " + + $"AS {QuoteIdentifier($"{structure.SourceAlias}")}{Build(structure.Joins)}"); + + fromSql.Append(string.Join( + "", + structure.JoinQueries.Select( + x => $" OUTER APPLY ({BuildAsJson(x.Value, true)}) AS {QuoteIdentifier(x.Key)}({dataIdent})"))); + + string predicates = JoinPredicateStrings( + structure.GetDbPolicyForOperation(EntityActionOperation.Read), + structure.FilterPredicates, + Build(structure.Predicates), + Build(structure.PaginationMetadata.PaginationPredicate)); + + string query = $"SELECT cast(count(1) as varchar(50)) as RecordCount " + + $" FROM {fromSql}" + + $" WHERE {predicates}"; + + return query; + } + private static string GenerateColumnsAsJson(SqlQueryStructure structure, bool subQueryStructure = false) { string columns; diff --git a/src/Core/Resolvers/SqlResponseHelpers.cs b/src/Core/Resolvers/SqlResponseHelpers.cs index 7701d662d3..9171a3a322 100644 --- a/src/Core/Resolvers/SqlResponseHelpers.cs +++ b/src/Core/Resolvers/SqlResponseHelpers.cs @@ -51,6 +51,13 @@ public static OkObjectResult FormatFindResult( ? DetermineExtraFieldsInResponse(findOperationResponse, context.FieldsToBeReturned) : DetermineExtraFieldsInResponse(findOperationResponse.EnumerateArray().First(), context.FieldsToBeReturned); + //Remove RecordCOunt from extraFieldsInResponse if present + /* + if (extraFieldsInResponse.Contains("RecordCount")) + { + extraFieldsInResponse.Remove("RecordCount"); + } + */ uint defaultPageSize = runtimeConfig.DefaultPageSize(); uint maxPageSize = runtimeConfig.MaxPageSize(); @@ -113,6 +120,16 @@ public static OkObjectResult FormatFindResult( queryStringParameters: context!.ParsedQueryString, after); + //Get the element RecordCount from the first element of the array + JsonElement recordCountElement = rootEnumerated[0].GetProperty("RecordCount"); + string jsonRecordCount = JsonSerializer.Serialize(new[] + { + new + { + recordCount = @$"{rootEnumerated[0].GetProperty("RecordCount")}" + } + }); + // When there are extra fields present, they are removed before returning the response. if (extraFieldsInResponse.Count > 0) { @@ -120,6 +137,7 @@ public static OkObjectResult FormatFindResult( } rootEnumerated.Add(nextLink); + rootEnumerated.Add(JsonSerializer.Deserialize(jsonRecordCount)); return OkResponse(JsonSerializer.SerializeToElement(rootEnumerated)); } @@ -218,13 +236,16 @@ public static OkObjectResult OkResponse(JsonElement jsonResult) // we strip the "[" and "]" and then save the nextLink element // into a dictionary with a key of "nextLink" and a value that // represents the nextLink data we require. - string nextLinkJsonString = JsonSerializer.Serialize(resultEnumerated[resultEnumerated.Count - 1]); + string nextLinkJsonString = JsonSerializer.Serialize(resultEnumerated[resultEnumerated.Count - 2]); + string recordCountJsonString = JsonSerializer.Serialize(resultEnumerated[resultEnumerated.Count - 1]); Dictionary nextLink = JsonSerializer.Deserialize>(nextLinkJsonString[1..^1])!; - IEnumerable value = resultEnumerated.Take(resultEnumerated.Count - 1); + Dictionary recordCount = JsonSerializer.Deserialize>(recordCountJsonString[1..^1])!; + IEnumerable value = resultEnumerated.Take(resultEnumerated.Count - 2); return new OkObjectResult(new { value = value, - @nextLink = nextLink["nextLink"] + @nextLink = nextLink["nextLink"], + @recordCount = recordCount["recordCount"] }); } From b560b20fa89538a3c4bff5187e68f71fe362ac41 Mon Sep 17 00:00:00 2001 From: KobeLenjou Date: Wed, 4 Sep 2024 10:25:05 +0200 Subject: [PATCH 7/9] Update dockerfile to .net8 --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5dbaa35a17..537ea4c78c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ # Version values referenced from https://hub.docker.com/_/microsoft-dotnet-aspnet -FROM mcr.microsoft.com/dotnet/sdk:6.0-cbl-mariner2.0. AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY [".", "./"] -RUN dotnet build "./src/Service/Azure.DataApiBuilder.Service.csproj" -c Docker -o /out -r linux-x64 +RUN dotnet build "./src/Service/Azure.DataApiBuilder.Service.csproj" -f net8.0 -o /out -r linux-x64 --self-contained -FROM mcr.microsoft.com/dotnet/aspnet:6.0-cbl-mariner2.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime COPY --from=build /out /App WORKDIR /App From 356778516c9599d227463d2f198e9c36286d86f2 Mon Sep 17 00:00:00 2001 From: KobeLenjou Date: Wed, 4 Sep 2024 11:30:54 +0200 Subject: [PATCH 8/9] Downgrade SqlClient --- src/Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index b33dd9cc9e..1c758176ae 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -20,7 +20,7 @@ - + From 1479f34bc3fc434fd7529dded4927638124dc5b1 Mon Sep 17 00:00:00 2001 From: KobeLenjou Date: Thu, 5 Sep 2024 16:40:29 +0200 Subject: [PATCH 9/9] Rename FIRST_URL constant value from "$first" to "$top" Updated the constant `FIRST_URL` in `RequestParser.cs` within the `Azure.DataApiBuilder.Core.Parsers` namespace to use the value `"$top"` instead of `"$first"`. This change aligns with naming conventions or standards used elsewhere in the codebase or API, ensuring consistency and improving clarity for developers. --- src/Core/Parsers/RequestParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Parsers/RequestParser.cs b/src/Core/Parsers/RequestParser.cs index 9a3a602329..86aed37d06 100644 --- a/src/Core/Parsers/RequestParser.cs +++ b/src/Core/Parsers/RequestParser.cs @@ -30,7 +30,7 @@ public class RequestParser /// /// Prefix used for specifying limit in the query string of the URL. /// - public const string FIRST_URL = "$first"; + public const string FIRST_URL = "$top"; /// /// Prefix used for specifying paging in the query string of the URL. ///