From 646c55e80e55b5ffe0fd5380bd2c378314272b1f Mon Sep 17 00:00:00 2001 From: Shane32 Date: Thu, 16 Jan 2025 00:12:10 -0500 Subject: [PATCH 1/7] add nativeaot sample --- .github/workflows/test.yml | 70 ++++++++++++++++++- Directory.Build.props | 2 +- GraphQL.Server.sln | 7 ++ README.md | 1 + .../Samples.NativeAot/GraphTypes/QueryType.cs | 12 ++++ samples/Samples.NativeAot/MySchema.cs | 13 ++++ samples/Samples.NativeAot/Program.cs | 18 +++++ .../Properties/launchSettings.json | 15 ++++ .../Samples.NativeAot.csproj | 17 +++++ .../Samples.NativeAot/Samples.NativeAot.http | 11 +++ .../appsettings.Development.json | 8 +++ samples/Samples.NativeAot/appsettings.json | 9 +++ samples/Samples.NativeAot/sample-request.json | 3 + .../Samples.NativeAot/sample-response.json | 3 + 14 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 samples/Samples.NativeAot/GraphTypes/QueryType.cs create mode 100644 samples/Samples.NativeAot/MySchema.cs create mode 100644 samples/Samples.NativeAot/Program.cs create mode 100644 samples/Samples.NativeAot/Properties/launchSettings.json create mode 100644 samples/Samples.NativeAot/Samples.NativeAot.csproj create mode 100644 samples/Samples.NativeAot/Samples.NativeAot.http create mode 100644 samples/Samples.NativeAot/appsettings.Development.json create mode 100644 samples/Samples.NativeAot/appsettings.json create mode 100644 samples/Samples.NativeAot/sample-request.json create mode 100644 samples/Samples.NativeAot/sample-response.json diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d20aef6e..65beaf82 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -71,15 +71,81 @@ jobs: with: files: .coverage/GraphQL.Server.Transports.AspNetCore.Tests/coverage.net7.0.opencover.xml,.coverage/GraphQL.Server.Transports.AspNetCore.Tests/coverage.netcoreapp2.1.opencover.xml,.coverage/GraphQL.Server.Samples.Server.Tests/coverage.net7.0.opencover.xml + nativeaot: + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + name: NativeAOT Sample on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + steps: + - name: Checkout source + uses: actions/checkout@v4 + - name: Setup .NET SDK for NativeAOT + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + source-url: https://nuget.pkg.github.com/graphql-dotnet/index.json + env: + NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Publish NativeAOT sample + working-directory: samples/Samples.NativeAot + run: dotnet publish -c Release -o published + - name: Start NativeAOT sample in background + working-directory: samples/Samples.NativeAot/published + shell: bash + run: | + # Using bash on both Windows and Linux. + if [ "$RUNNER_OS" == "Windows" ]; then + ./Samples.NativeAot.exe & + else + ./Samples.NativeAot & + fi + - name: Wait for NativeAOT sample to spin up + shell: bash + run: | + # Disable exit-on-error to allow retries + set +e + for i in {1..60}; do + echo "Request $i to the GraphQL endpoint..." + # Replace the URL below with the actual endpoint used by your NativeAOT application. + response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000/graphql || true) + if [ "$response" -eq 200 ]; then + echo "Received 200 response, NativeAOT sample is ready." + exit 0 + fi + echo "Did not receive a 200 response, sleeping for 0.5 second..." + sleep 0.5 + done + echo "NativeAOT sample did not spin up in time." + exit 1 + - name: Run GraphQL query against NativeAOT sample + shell: bash + working-directory: samples/Samples.NativeAot + run: | + # Run a simple GraphQL query. Adjust the request as needed for your sample. + curl -X POST -H "Content-Type: application/json" \ + -d @sample-request.json \ + http://localhost:5000/graphql > nativeaot_response.json + - name: Print query result + working-directory: samples/Samples.NativeAot + run: cat nativeaot_response.json + - name: Compare query result to expected response + working-directory: samples/Samples.NativeAot + run: | + jq . nativeaot_response.json > actual-response.json + jq . sample-response.json > expected-response.json + diff -b actual-response.json expected-response.json + buildcheck: needs: - test + - nativeaot runs-on: ubuntu-latest if: always() steps: - name: Pass build check - if: ${{ needs.test.result == 'success' }} + if: ${{ needs.test.result == 'success' && needs.nativeaot.result == 'success' }} run: exit 0 - name: Fail build check - if: ${{ needs.test.result != 'success' }} + if: ${{ needs.test.result != 'success' || needs.nativeaot.result != 'success' }} run: exit 1 diff --git a/Directory.Build.props b/Directory.Build.props index a3ef8a3c..516629f7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -32,7 +32,7 @@ GraphQL.Server.$(MSBuildProjectName) GraphQL.Server.$(MSBuildProjectName) - [8.2.1,9.0.0) + [8.0.1-preview-1114] true <_FriendAssembliesPublicKey>PublicKey=0024000004800000940000000602000000240000525341310004000001000100352162dbf27be78fc45136884b8f324aa9f1dfc928c96c24704bf1df1a8779b2f26c760ed8321eca5b95ea6bd9bb60cd025b300f73bd1f4ae1ee6e281f85c527fa013ab5cb2c3fc7a1cbef7f9bf0c9014152e6a21f6e0ac6a371f8b45c6d7139c9119df9eeecf1cf59063545bb7c07437b1bc12be2c57d108d72d6c27176fbb8 diff --git a/GraphQL.Server.sln b/GraphQL.Server.sln index ad78bc67..4775b9a1 100644 --- a/GraphQL.Server.sln +++ b/GraphQL.Server.sln @@ -122,6 +122,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.Upload", "samples\S EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.Upload.Tests", "tests\Samples.Upload.Tests\Samples.Upload.Tests.csproj", "{DE3059F4-B548-4091-BFC0-5879246A2DF9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.NativeAot", "samples\Samples.NativeAot\Samples.NativeAot.csproj", "{56042483-2E36-41DF-9DC4-71DC527A36E4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -264,6 +266,10 @@ Global {DE3059F4-B548-4091-BFC0-5879246A2DF9}.Debug|Any CPU.Build.0 = Debug|Any CPU {DE3059F4-B548-4091-BFC0-5879246A2DF9}.Release|Any CPU.ActiveCfg = Release|Any CPU {DE3059F4-B548-4091-BFC0-5879246A2DF9}.Release|Any CPU.Build.0 = Release|Any CPU + {56042483-2E36-41DF-9DC4-71DC527A36E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56042483-2E36-41DF-9DC4-71DC527A36E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56042483-2E36-41DF-9DC4-71DC527A36E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56042483-2E36-41DF-9DC4-71DC527A36E4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -304,6 +310,7 @@ Global {A204E359-05E8-4CEE-891C-4CCA6570FA52} = {BBD07745-C962-4D2D-B302-6DA1BCC2FF43} {33E2CDF5-F854-4F1A-80D5-DBF0BDF8EEA8} = {5C07AFA3-12F2-40EA-807D-7A1EEF29012B} {DE3059F4-B548-4091-BFC0-5879246A2DF9} = {BBD07745-C962-4D2D-B302-6DA1BCC2FF43} + {56042483-2E36-41DF-9DC4-71DC527A36E4} = {5C07AFA3-12F2-40EA-807D-7A1EEF29012B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3FC7FA59-E938-453C-8C4A-9D5635A9489A} diff --git a/README.md b/README.md index 5aefc067..62dc1e43 100644 --- a/README.md +++ b/README.md @@ -1138,6 +1138,7 @@ typical ASP.NET Core scenarios. | EndpointRouting | .NET 8 Minimal | Demonstrates configuring GraphQL through endpoint routing | | Jwt | .NET 8 Minimal | Demonstrates authenticating GraphQL requests with a JWT bearer token over HTTP POST and WebSocket connections | | MultipleSchemas | .NET 8 Minimal | Demonstrates configuring multiple schemas within a single server | +| NativeAot | .NET 8 Minimal | Demonstrates configuring GraphQL for Native AOT publishing | | Net48 | .NET Core 2.1 / .NET 4.8 | Demonstrates configuring GraphQL on .NET 4.8 / Core 2.1 | | Pages | .NET 8 Minimal | Demonstrates configuring GraphQL on top of a Razor Pages template | | Upload | .NET 8 Minimal | Demonstrates uploading files via the `multipart/form-data` content type | diff --git a/samples/Samples.NativeAot/GraphTypes/QueryType.cs b/samples/Samples.NativeAot/GraphTypes/QueryType.cs new file mode 100644 index 00000000..a9015107 --- /dev/null +++ b/samples/Samples.NativeAot/GraphTypes/QueryType.cs @@ -0,0 +1,12 @@ +using GraphQL.Types; + +namespace GraphQL.Server.Samples.NativeAot.GraphTypes; + +public class QueryType : ObjectGraphType +{ + public QueryType() + { + Field("hello") + .Resolve(context => "world"); + } +} diff --git a/samples/Samples.NativeAot/MySchema.cs b/samples/Samples.NativeAot/MySchema.cs new file mode 100644 index 00000000..03205ab2 --- /dev/null +++ b/samples/Samples.NativeAot/MySchema.cs @@ -0,0 +1,13 @@ +using GraphQL.Server.Samples.NativeAot.GraphTypes; +using GraphQL.Types; + +namespace GraphQL.Server.Samples.NativeAot; + +public class MySchema : Schema +{ + public MySchema(IServiceProvider services, QueryType queryType) + : base(services) + { + Query = queryType; + } +} diff --git a/samples/Samples.NativeAot/Program.cs b/samples/Samples.NativeAot/Program.cs new file mode 100644 index 00000000..566583b6 --- /dev/null +++ b/samples/Samples.NativeAot/Program.cs @@ -0,0 +1,18 @@ +using GraphQL; +using GraphQL.Server.Samples.NativeAot; +using GraphQL.Server.Samples.NativeAot.GraphTypes; + +var builder = WebApplication.CreateSlimBuilder(args); + +builder.Services.AddGraphQL(b => b + .AddSchema() + .AddSystemTextJson()); + +builder.Services.AddTransient(); + +var app = builder.Build(); + +app.UseGraphQLGraphiQL("/"); +app.UseGraphQL(); + +app.Run(); diff --git a/samples/Samples.NativeAot/Properties/launchSettings.json b/samples/Samples.NativeAot/Properties/launchSettings.json new file mode 100644 index 00000000..45a6cec2 --- /dev/null +++ b/samples/Samples.NativeAot/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "", + "applicationUrl": "http://localhost:5003", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/samples/Samples.NativeAot/Samples.NativeAot.csproj b/samples/Samples.NativeAot/Samples.NativeAot.csproj new file mode 100644 index 00000000..9f7e7b40 --- /dev/null +++ b/samples/Samples.NativeAot/Samples.NativeAot.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + true + true + true + + + + + + + + diff --git a/samples/Samples.NativeAot/Samples.NativeAot.http b/samples/Samples.NativeAot/Samples.NativeAot.http new file mode 100644 index 00000000..3c630207 --- /dev/null +++ b/samples/Samples.NativeAot/Samples.NativeAot.http @@ -0,0 +1,11 @@ +@Samples.NativeAot_HostAddress = http://localhost:5003 + +GET {{Samples.NativeAot_HostAddress}}/todos/ +Accept: application/json + +### + +GET {{Samples.NativeAot_HostAddress}}/todos/1 +Accept: application/json + +### diff --git a/samples/Samples.NativeAot/appsettings.Development.json b/samples/Samples.NativeAot/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/samples/Samples.NativeAot/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/samples/Samples.NativeAot/appsettings.json b/samples/Samples.NativeAot/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/samples/Samples.NativeAot/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/samples/Samples.NativeAot/sample-request.json b/samples/Samples.NativeAot/sample-request.json new file mode 100644 index 00000000..767e195f --- /dev/null +++ b/samples/Samples.NativeAot/sample-request.json @@ -0,0 +1,3 @@ +{ + "query": "{ hello }" +} diff --git a/samples/Samples.NativeAot/sample-response.json b/samples/Samples.NativeAot/sample-response.json new file mode 100644 index 00000000..f2a886f3 --- /dev/null +++ b/samples/Samples.NativeAot/sample-response.json @@ -0,0 +1,3 @@ +{ + "hello": "world" +} From 1cad418856f2db1c804b5575d667addc099f361f Mon Sep 17 00:00:00 2001 From: Shane32 Date: Thu, 16 Jan 2025 00:18:15 -0500 Subject: [PATCH 2/7] update workflow --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 65beaf82..0c38519d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -96,9 +96,9 @@ jobs: run: | # Using bash on both Windows and Linux. if [ "$RUNNER_OS" == "Windows" ]; then - ./Samples.NativeAot.exe & + ./GraphQL.Server.Samples.NativeAot.exe & else - ./Samples.NativeAot & + ./GraphQL.Server.Samples.NativeAot & fi - name: Wait for NativeAOT sample to spin up shell: bash From a0fa941b3deb065cc667f9043fb1aa850633de44 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Thu, 16 Jan 2025 00:22:23 -0500 Subject: [PATCH 3/7] update workflow --- .github/workflows/test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c38519d..69e197a0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -94,7 +94,6 @@ jobs: working-directory: samples/Samples.NativeAot/published shell: bash run: | - # Using bash on both Windows and Linux. if [ "$RUNNER_OS" == "Windows" ]; then ./GraphQL.Server.Samples.NativeAot.exe & else @@ -107,8 +106,7 @@ jobs: set +e for i in {1..60}; do echo "Request $i to the GraphQL endpoint..." - # Replace the URL below with the actual endpoint used by your NativeAOT application. - response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000/graphql || true) + response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5000/ || true) if [ "$response" -eq 200 ]; then echo "Received 200 response, NativeAOT sample is ready." exit 0 From b5da27b0f6e94878cabc27c250a006d4053f2ebd Mon Sep 17 00:00:00 2001 From: Shane32 Date: Thu, 16 Jan 2025 00:24:21 -0500 Subject: [PATCH 4/7] fix expected response --- samples/Samples.NativeAot/sample-response.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/Samples.NativeAot/sample-response.json b/samples/Samples.NativeAot/sample-response.json index f2a886f3..4b3fa5b6 100644 --- a/samples/Samples.NativeAot/sample-response.json +++ b/samples/Samples.NativeAot/sample-response.json @@ -1,3 +1,5 @@ { - "hello": "world" + "data": { + "hello": "world" + } } From 64d79801a385e64cb7e54ce392f5d1251db17f71 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Thu, 16 Jan 2025 00:30:40 -0500 Subject: [PATCH 5/7] update workflow --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 69e197a0..2b0cc07f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -117,8 +117,8 @@ jobs: echo "NativeAOT sample did not spin up in time." exit 1 - name: Run GraphQL query against NativeAOT sample - shell: bash working-directory: samples/Samples.NativeAot + shell: bash run: | # Run a simple GraphQL query. Adjust the request as needed for your sample. curl -X POST -H "Content-Type: application/json" \ @@ -126,9 +126,11 @@ jobs: http://localhost:5000/graphql > nativeaot_response.json - name: Print query result working-directory: samples/Samples.NativeAot + shell: bash run: cat nativeaot_response.json - name: Compare query result to expected response working-directory: samples/Samples.NativeAot + shell: bash run: | jq . nativeaot_response.json > actual-response.json jq . sample-response.json > expected-response.json From bb39d5e8f0c7f07c81900103a3e565497b17ba92 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Thu, 16 Jan 2025 11:28:59 -0500 Subject: [PATCH 6/7] update --- README.md | 2 +- samples/Samples.NativeAot/Samples.NativeAot.http | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 samples/Samples.NativeAot/Samples.NativeAot.http diff --git a/README.md b/README.md index cfde6d10..1d88207c 100644 --- a/README.md +++ b/README.md @@ -1138,7 +1138,7 @@ typical ASP.NET Core scenarios. | EndpointRouting | .NET 8 Minimal | Demonstrates configuring GraphQL through endpoint routing | | Jwt | .NET 8 Minimal | Demonstrates authenticating GraphQL requests with a JWT bearer token over HTTP POST and WebSocket connections | | MultipleSchemas | .NET 8 Minimal | Demonstrates configuring multiple schemas within a single server | -| NativeAot | .NET 8 Minimal | Demonstrates configuring GraphQL for Native AOT publishing | +| NativeAot | .NET 8 Slim | Demonstrates configuring GraphQL for Native AOT publishing | | Net48 | .NET Core 2.1 / .NET 4.8 | Demonstrates configuring GraphQL on .NET 4.8 / Core 2.1 | | Pages | .NET 8 Minimal | Demonstrates configuring GraphQL on top of a Razor Pages template | | Upload | .NET 8 Minimal | Demonstrates uploading files via the `multipart/form-data` content type | diff --git a/samples/Samples.NativeAot/Samples.NativeAot.http b/samples/Samples.NativeAot/Samples.NativeAot.http deleted file mode 100644 index 3c630207..00000000 --- a/samples/Samples.NativeAot/Samples.NativeAot.http +++ /dev/null @@ -1,11 +0,0 @@ -@Samples.NativeAot_HostAddress = http://localhost:5003 - -GET {{Samples.NativeAot_HostAddress}}/todos/ -Accept: application/json - -### - -GET {{Samples.NativeAot_HostAddress}}/todos/1 -Accept: application/json - -### From 4930238d56d593ba0fef3b079000b4da5346630b Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Thu, 16 Jan 2025 11:42:32 -0500 Subject: [PATCH 7/7] Update Directory.Build.props --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 516629f7..00e0ef5d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -32,7 +32,7 @@ GraphQL.Server.$(MSBuildProjectName) GraphQL.Server.$(MSBuildProjectName) - [8.0.1-preview-1114] + [8.3.0,9.0.0) true <_FriendAssembliesPublicKey>PublicKey=0024000004800000940000000602000000240000525341310004000001000100352162dbf27be78fc45136884b8f324aa9f1dfc928c96c24704bf1df1a8779b2f26c760ed8321eca5b95ea6bd9bb60cd025b300f73bd1f4ae1ee6e281f85c527fa013ab5cb2c3fc7a1cbef7f9bf0c9014152e6a21f6e0ac6a371f8b45c6d7139c9119df9eeecf1cf59063545bb7c07437b1bc12be2c57d108d72d6c27176fbb8