diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 14e8de546..db642b372 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -24,7 +24,7 @@ env: jobs: build: name: Sanity Build - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 @@ -33,12 +33,12 @@ jobs: # --------------------------------------- # Install .NET Versions # --------------------------------------- - - uses: actions/setup-dotnet@v2 + - uses: actions/setup-dotnet@v4 name: Install .NET with: dotnet-version: | - 6.x 8.x + 9.x # --------------------------------------- # Configure the build environment diff --git a/.github/workflows/nuget-deployment.yml b/.github/workflows/nuget-deployment.yml index 99957abba..02cecd95f 100644 --- a/.github/workflows/nuget-deployment.yml +++ b/.github/workflows/nuget-deployment.yml @@ -26,7 +26,7 @@ env: jobs: deployment: name: Pack & Deploy - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 @@ -35,12 +35,12 @@ jobs: # --------------------------------------- # Install .NET Versions # --------------------------------------- - - uses: actions/setup-dotnet@v2 + - uses: actions/setup-dotnet@v4 name: Install .NET with: dotnet-version: | - 6.x 8.x + 9.x # --------------------------------------- # Configure the build environment @@ -77,7 +77,7 @@ jobs: # --------------------------------------- # Save Artifacts for later debugging # --------------------------------------- - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 name: Save Artifacts with: name: generated-nuget-packages diff --git a/src/ancillary-projects/starwars/starwars-api80/Program.cs b/src/ancillary-projects/starwars/starwars-api90/Program.cs similarity index 100% rename from src/ancillary-projects/starwars/starwars-api80/Program.cs rename to src/ancillary-projects/starwars/starwars-api90/Program.cs diff --git a/src/ancillary-projects/starwars/starwars-api80/Properties/launchSettings.json b/src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json similarity index 91% rename from src/ancillary-projects/starwars/starwars-api80/Properties/launchSettings.json rename to src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json index 34bbebbd8..837d831d9 100644 --- a/src/ancillary-projects/starwars/starwars-api80/Properties/launchSettings.json +++ b/src/ancillary-projects/starwars/starwars-api90/Properties/launchSettings.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "StarWars: .NET 8": { + "StarWars: .NET 9": { "commandName": "Project", "applicationUrl": "http://localhost:5000", "environmentVariables": { diff --git a/src/ancillary-projects/starwars/starwars-api80/appsettings.json b/src/ancillary-projects/starwars/starwars-api90/appsettings.json similarity index 100% rename from src/ancillary-projects/starwars/starwars-api80/appsettings.json rename to src/ancillary-projects/starwars/starwars-api90/appsettings.json diff --git a/src/ancillary-projects/starwars/starwars-api80/starwars-api80.csproj b/src/ancillary-projects/starwars/starwars-api90/starwars-api90.csproj similarity index 94% rename from src/ancillary-projects/starwars/starwars-api80/starwars-api80.csproj rename to src/ancillary-projects/starwars/starwars-api90/starwars-api90.csproj index 39caf611a..44771342b 100644 --- a/src/ancillary-projects/starwars/starwars-api80/starwars-api80.csproj +++ b/src/ancillary-projects/starwars/starwars-api90/starwars-api90.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 latest $(NoWarn);1701;1702;1705;1591;NU1603 GraphQL.AspNet.StarWarsAPI6X diff --git a/src/ancillary-projects/starwars/starwars-common/starwars-common.csproj b/src/ancillary-projects/starwars/starwars-common/starwars-common.csproj index cdf1f0fc5..07a7716b1 100644 --- a/src/ancillary-projects/starwars/starwars-common/starwars-common.csproj +++ b/src/ancillary-projects/starwars/starwars-common/starwars-common.csproj @@ -1,7 +1,7 @@  - net8.0;net7.0;netstandard2.0; + net9.0;net8.0;netstandard2.0; latest $(NoWarn);1701;1702;1705;1591;NU1603 GraphQL.AspNet.StarwarsAPI.Common diff --git a/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxy.cs b/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxy.cs index 422325740..e023e335c 100644 --- a/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxy.cs +++ b/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxy.cs @@ -94,6 +94,7 @@ public GqltwsClientProxy( _serializerOptions.Converters.Add(new GqltwsServerDataMessageConverter(schema, responseWriter)); _serializerOptions.Converters.Add(new GqltwsServerCompleteMessageConverter()); _serializerOptions.Converters.Add(new GqltwsServerErrorMessageConverter(schema)); + _serializerOptions.Converters.Add(new GqltwsMessageConverter()); } /// diff --git a/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxy.cs b/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxy.cs index 0b4bc66e4..2c580f9bb 100644 --- a/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxy.cs +++ b/src/graphql-aspnet-subscriptions/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxy.cs @@ -93,6 +93,7 @@ public GraphqlWsLegacyClientProxy( _serializeOptions.Converters.Add(new GraphqlWsLegacyServerDataMessageConverter(schema, responseWriter)); _serializeOptions.Converters.Add(new GraphqlWsLegacyServerCompleteMessageConverter()); _serializeOptions.Converters.Add(new GraphqlWsLegacyServerErrorMessageConverter(schema)); + _serializeOptions.Converters.Add(new GraphqlWsLegacyMessageConverter()); } /// @@ -305,7 +306,7 @@ private async Task AcknowledgeNewConnectionAsync() /// protected override async Task ExecuteKeepAliveAsync(CancellationToken cancelToken = default) { - await this.SendMessageAsync(new GraphqlWsLegacyKeepAliveOperationMessage()); + await this.SendMessageAsync(new GraphqlWsLegacyKeepAliveOperationMessage(), cancelToken); } /// diff --git a/src/graphql-aspnet-subscriptions/Web/WebSockets/WebSocketClientConnection.cs b/src/graphql-aspnet-subscriptions/Web/WebSockets/WebSocketClientConnection.cs index 2dc728677..e5cf9a73d 100644 --- a/src/graphql-aspnet-subscriptions/Web/WebSockets/WebSocketClientConnection.cs +++ b/src/graphql-aspnet-subscriptions/Web/WebSockets/WebSocketClientConnection.cs @@ -56,7 +56,7 @@ private string DeteremineRequestedProtocol() if (_httpContext.Request.Headers.ContainsKey(SubscriptionConstants.WebSockets.WEBSOCKET_PROTOCOL_HEADER)) { var protocolHeaders = _httpContext.Request.Headers[SubscriptionConstants.WebSockets.WEBSOCKET_PROTOCOL_HEADER]; - return string.Join(",", protocolHeaders); + return string.Join(",", protocolHeaders.ToArray()); } return string.Empty; diff --git a/src/graphql-aspnet.sln b/src/graphql-aspnet.sln index f3978b89f..ac80d2c73 100644 --- a/src/graphql-aspnet.sln +++ b/src/graphql-aspnet.sln @@ -33,10 +33,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-subscription EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-tests-common", "unit-tests\graphql-aspnet-tests-common\graphql-aspnet-tests-common.csproj", "{3CB086E3-5E7B-438B-9A95-AEA264009521}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "starwars-api80", "ancillary-projects\starwars\starwars-api80\starwars-api80.csproj", "{43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "graphql-aspnet-testframework-tests", "unit-tests\graphql-aspnet-testframework-tests\graphql-aspnet-testframework-tests.csproj", "{E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "starwars-api90", "ancillary-projects\starwars\starwars-api90\starwars-api90.csproj", "{E7EE5851-57F1-4E20-B4BA-06902C77E83A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -72,14 +72,14 @@ Global {3CB086E3-5E7B-438B-9A95-AEA264009521}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CB086E3-5E7B-438B-9A95-AEA264009521}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CB086E3-5E7B-438B-9A95-AEA264009521}.Release|Any CPU.Build.0 = Release|Any CPU - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114}.Release|Any CPU.Build.0 = Release|Any CPU {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}.Release|Any CPU.ActiveCfg = Release|Any CPU {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA}.Release|Any CPU.Build.0 = Release|Any CPU + {E7EE5851-57F1-4E20-B4BA-06902C77E83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7EE5851-57F1-4E20-B4BA-06902C77E83A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7EE5851-57F1-4E20-B4BA-06902C77E83A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7EE5851-57F1-4E20-B4BA-06902C77E83A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -91,8 +91,8 @@ Global {5DE081AA-494A-4377-B2CA-6952715D513D} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} {6E4A16F5-1B98-412E-9A88-F56301F5D0E4} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} {3CB086E3-5E7B-438B-9A95-AEA264009521} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} - {43C9EB6E-5FFE-4EC6-B21B-09C715B7B114} = {22C7BC5B-EC8E-4A07-9968-961E86AB44E2} {E67D4FB2-73FF-4EC1-80F8-5D4DEC57F5AA} = {350D3594-5D97-4D9B-A01D-D3A5C036318C} + {E7EE5851-57F1-4E20-B4BA-06902C77E83A} = {22C7BC5B-EC8E-4A07-9968-961E86AB44E2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DD2C38B8-B029-4DE1-877E-B1A661AC412F} diff --git a/src/graphql-aspnet.sln.DotSettings b/src/graphql-aspnet.sln.DotSettings index fd6abeb25..280d05ffe 100644 --- a/src/graphql-aspnet.sln.DotSettings +++ b/src/graphql-aspnet.sln.DotSettings @@ -246,7 +246,7 @@ graphql-aspnet repo: https://github.com/kevin-carroll/graphql-aspnet docs: -coming soon- -- -project: $PROJECT$ +project: ${File.ProjectName} -- License: MIT ************************************************************* @@ -265,6 +265,10 @@ License: MIT <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB"><ExtraRule Prefix="ERROR_" Suffix="" Style="AA_BB" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB"><ExtraRule Prefix="ERROR_" Suffix="" Style="AA_BB" /></Policy></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB"><ExtraRule Prefix="ERROR_" Suffix="" Style="AA_BB" /></Policy></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> @@ -337,6 +341,7 @@ License: MIT NOTIFY True + True True True True @@ -345,11 +350,13 @@ License: MIT True True True + True True True True True True + True True 3 diff --git a/src/graphql-aspnet/Common/TimerAsync.cs b/src/graphql-aspnet/Common/TimerAsync.cs index 6fd016c72..2cf02f354 100644 --- a/src/graphql-aspnet/Common/TimerAsync.cs +++ b/src/graphql-aspnet/Common/TimerAsync.cs @@ -90,7 +90,8 @@ public void Start() } finally { - _semaphore.Release(); + if (!_disposed) + _semaphore.Release(); } } @@ -121,7 +122,8 @@ public async Task StopAsync() finally { this.IsRunning = false; - _semaphore.Release(); + if (!_disposed) + _semaphore.Release(); } } @@ -195,4 +197,4 @@ public void Dispose() /// true if the timer is running; otherwise, false. public bool IsRunning { get; private set; } } -} +} \ No newline at end of file diff --git a/src/graphql-aspnet/Execution/QueryPlans/DocumentParts/DocumentNamedFragmentCollection.cs b/src/graphql-aspnet/Execution/QueryPlans/DocumentParts/DocumentNamedFragmentCollection.cs index 45adcbb81..406a5a942 100644 --- a/src/graphql-aspnet/Execution/QueryPlans/DocumentParts/DocumentNamedFragmentCollection.cs +++ b/src/graphql-aspnet/Execution/QueryPlans/DocumentParts/DocumentNamedFragmentCollection.cs @@ -13,16 +13,17 @@ namespace GraphQL.AspNet.Execution.QueryPlans.DocumentParts using System.Collections.Generic; using System.Diagnostics; using GraphQL.AspNet.Common; - using GraphQL.AspNet.Common.Generics; using GraphQL.AspNet.Interfaces.Execution.QueryPlans.DocumentParts; + using OrderedDictionaryOfStringAndNamedFragment = GraphQL.AspNet.Common.Generics.OrderedDictionary; + /// /// An indexed collection of named fragments contained within a query document. /// [DebuggerDisplay("Count = {Count}")] internal class DocumentNamedFragmentCollection : INamedFragmentCollectionDocumentPart { - private OrderedDictionary _fragments; + private OrderedDictionaryOfStringAndNamedFragment _fragments; // its possible that a document declares more than one named fragment with the same // name. Keep track of the duplicates for document validation reporting. @@ -35,7 +36,7 @@ internal class DocumentNamedFragmentCollection : INamedFragmentCollectionDocumen public DocumentNamedFragmentCollection(IDocumentPart parent) { this.Parent = Validation.ThrowIfNullOrReturn(parent, nameof(parent)); - _fragments = new OrderedDictionary(); + _fragments = new OrderedDictionaryOfStringAndNamedFragment(); } /// diff --git a/src/graphql-aspnet/Execution/Response/ResponseFieldSet.cs b/src/graphql-aspnet/Execution/Response/ResponseFieldSet.cs index 1170099d0..208976e2a 100644 --- a/src/graphql-aspnet/Execution/Response/ResponseFieldSet.cs +++ b/src/graphql-aspnet/Execution/Response/ResponseFieldSet.cs @@ -11,23 +11,24 @@ namespace GraphQL.AspNet.Execution.Response { using System.Collections.Generic; using System.Diagnostics; - using GraphQL.AspNet.Common.Generics; using GraphQL.AspNet.Interfaces.Execution.Response; + using OrderedDictionaryOfStringAndQueryResponseItem = GraphQL.AspNet.Common.Generics.OrderedDictionary; + /// /// A collection of keyed items included as a result to a graphql query. /// [DebuggerDisplay("Count = {Fields.Count}")] internal class ResponseFieldSet : IQueryResponseFieldSet { - private readonly OrderedDictionary _dictionary; + private readonly OrderedDictionaryOfStringAndQueryResponseItem _dictionary; /// /// Initializes a new instance of the class. /// public ResponseFieldSet() { - _dictionary = new OrderedDictionary(); + _dictionary = new OrderedDictionaryOfStringAndQueryResponseItem(); } /// diff --git a/src/graphql-aspnet/Schemas/Structural/GraphFieldArgumentCollection.cs b/src/graphql-aspnet/Schemas/Structural/GraphFieldArgumentCollection.cs index 519cb6692..38b33ac68 100644 --- a/src/graphql-aspnet/Schemas/Structural/GraphFieldArgumentCollection.cs +++ b/src/graphql-aspnet/Schemas/Structural/GraphFieldArgumentCollection.cs @@ -14,10 +14,11 @@ namespace GraphQL.AspNet.Schemas.Structural using System.Collections.Generic; using System.Diagnostics; using GraphQL.AspNet.Common; - using GraphQL.AspNet.Common.Generics; using GraphQL.AspNet.Interfaces.Schema; using GraphQL.AspNet.Schemas.TypeSystem; + using OrderedDictionaryOfStringAndGraphArgument = GraphQL.AspNet.Common.Generics.OrderedDictionary; + /// /// A collection of allowed arguments defined for a or . /// @@ -25,7 +26,7 @@ namespace GraphQL.AspNet.Schemas.Structural internal class GraphFieldArgumentCollection : IGraphArgumentCollection { private readonly ISchemaItem _owner; - private readonly OrderedDictionary _arguments; + private readonly OrderedDictionaryOfStringAndGraphArgument _arguments; private IGraphArgument _sourceArgument; /// @@ -36,7 +37,7 @@ internal class GraphFieldArgumentCollection : IGraphArgumentCollection public GraphFieldArgumentCollection(ISchemaItem owner) { _owner = Validation.ThrowIfNullOrReturn(owner, nameof(owner)); - _arguments = new OrderedDictionary(StringComparer.Ordinal); + _arguments = new OrderedDictionaryOfStringAndGraphArgument(StringComparer.Ordinal); } /// diff --git a/src/graphql-aspnet/Schemas/TypeSystem/Introspection/Model/IntrospectedSchema.cs b/src/graphql-aspnet/Schemas/TypeSystem/Introspection/Model/IntrospectedSchema.cs index 0eff5c0bb..821a66f69 100644 --- a/src/graphql-aspnet/Schemas/TypeSystem/Introspection/Model/IntrospectedSchema.cs +++ b/src/graphql-aspnet/Schemas/TypeSystem/Introspection/Model/IntrospectedSchema.cs @@ -16,11 +16,12 @@ namespace GraphQL.AspNet.Schemas.TypeSystem.Introspection.Model using GraphQL.AspNet.Attributes; using GraphQL.AspNet.Common; using GraphQL.AspNet.Common.Extensions; - using GraphQL.AspNet.Common.Generics; using GraphQL.AspNet.Execution.Exceptions; using GraphQL.AspNet.Interfaces.Schema; using GraphQL.AspNet.Schemas.TypeSystem; + using OrderedDictionaryOfStringAndType = GraphQL.AspNet.Common.Generics.OrderedDictionary; + /// /// A model object containing data for the '__Schema' type. /// @@ -28,7 +29,7 @@ namespace GraphQL.AspNet.Schemas.TypeSystem.Introspection.Model public sealed class IntrospectedSchema : IntrospectedItem, ISchemaItem { private readonly ISchema _schema; - private OrderedDictionary _typeList; + private OrderedDictionaryOfStringAndType _typeList; private List _directiveList; /// @@ -39,7 +40,7 @@ public IntrospectedSchema(ISchema schema) : base(schema) { _schema = Validation.ThrowIfNullOrReturn(schema, nameof(schema)); - _typeList = new OrderedDictionary(); + _typeList = new OrderedDictionaryOfStringAndType(); } /// @@ -72,7 +73,7 @@ private void RebuildDirectiveList() private void RebuildIntrospectedTypeList() { _typeList.Clear(); - _typeList = new OrderedDictionary(); + _typeList = new OrderedDictionaryOfStringAndType(); // build in a two pass approach // ----------------------------------------- diff --git a/src/library-common.props b/src/library-common.props index a58b2e858..31a4b789c 100644 --- a/src/library-common.props +++ b/src/library-common.props @@ -1,7 +1,7 @@ - net8.0;net6.0;netstandard2.0; + net9.0;net8.0;netstandard2.0; latest $(NoWarn);1701;1702;1705;1591;NU1603;IDE0019;IDE0017;RCS1146;RCS1194; @@ -55,10 +55,10 @@ - + - + @@ -68,7 +68,7 @@ - + diff --git a/src/library-tests.props b/src/library-tests.props index 5d3fee9ea..0b086b1ea 100644 --- a/src/library-tests.props +++ b/src/library-tests.props @@ -1,7 +1,7 @@ - net8.0;net6.0; + net9.0;net8.0; latest $(NoWarn);1701;1702;1705;1591;NU1603;IDE0019;IDE0017;RCS1146;RCS1194; GraphQL.AspNet.Tests diff --git a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientAsserts.cs b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientAsserts.cs index 9cd2488b7..a902cb612 100644 --- a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientAsserts.cs +++ b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientAsserts.cs @@ -25,12 +25,13 @@ public static class GqltwsClientAsserts /// The connection. /// The type of message to check for. /// if true, the message is removed from the queue. - internal static void AssertGqltwsResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGqltwsResponse( this MockClientConnection connection, GqltwsMessageType type, bool dequeue = true) { - connection.AssertGqltwsResponse(type, null, false, null, false, dequeue); + return connection.AssertGqltwsResponse(type, null, false, null, false, dequeue); } /// @@ -40,13 +41,14 @@ internal static void AssertGqltwsResponse( /// The type of message to check for. /// The id returned by the server, if supplied. /// if true, the message is removed from the queue. - internal static void AssertGqltwsResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGqltwsResponse( this MockClientConnection connection, GqltwsMessageType type, string id, bool dequeue = true) { - connection.AssertGqltwsResponse(type, id, true, null, false, dequeue); + return connection.AssertGqltwsResponse(type, id, true, null, false, dequeue); } /// @@ -58,17 +60,18 @@ internal static void AssertGqltwsResponse( /// The expected identifier of the subscription that rendered the data. /// The expected payload of the message, converted to a json string. /// if set to true if the message should be removed from the queue. - internal static void AssertGqltwsResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGqltwsResponse( this MockClientConnection connection, GqltwsMessageType type, string id, string expectedPayloadJson, bool dequeue = true) { - connection.AssertGqltwsResponse(type, id, true, expectedPayloadJson, true, dequeue); + return connection.AssertGqltwsResponse(type, id, true, expectedPayloadJson, true, dequeue); } - private static void AssertGqltwsResponse( + private static string AssertGqltwsResponse( this MockClientConnection connection, GqltwsMessageType type, string id, @@ -81,14 +84,14 @@ private static void AssertGqltwsResponse( Assert.Fail("No messages queued."); var message = dequeue ? connection.DequeueNextReceivedMessage() : connection.PeekNextReceivedMessage(); - var str = Encoding.UTF8.GetString(message.Data); + var rawMessageData = Encoding.UTF8.GetString(message.Data); var options = new JsonSerializerOptions(); options.PropertyNameCaseInsensitive = true; options.AllowTrailingCommas = true; options.Converters.Add(new GqltwsResponseMessageConverter()); - var convertedMessage = JsonSerializer.Deserialize(str, options); + var convertedMessage = JsonSerializer.Deserialize(rawMessageData, options); Assert.IsNotNull(convertedMessage, "Could not deserialize response message"); Assert.AreEqual(type, convertedMessage.Type, $"Expected message type of {type.ToString()} but got {convertedMessage.Type.ToString()}"); @@ -103,6 +106,8 @@ private static void AssertGqltwsResponse( if (compareId) Assert.AreEqual(id, convertedMessage.Id); + + return rawMessageData; } } } \ No newline at end of file diff --git a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxyTests.cs b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxyTests.cs index 31b2cdfc0..533890d27 100644 --- a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxyTests.cs +++ b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlTransportWs/GqltwsClientProxyTests.cs @@ -746,5 +746,23 @@ public async Task Deserialize_InvalidMessage_ProcessesUnknownMessage() connection.AssertServerClosedConnection((ConnectionCloseStatus)GqltwsConstants.CustomCloseEventIds.InvalidMessageType); graphqlWsClient.Dispose(); } + + [Test] + public async Task SendConnectionInitMessage_RespondsWithCorrectAckMessage() + { + using var restorePoint = new GraphQLGlobalSubscriptionRestorePoint(); + (var socketClient, var client, var router) = this.CreateConnection(); + + socketClient.QueueClientMessage(new GqltwsClientConnectionInitMessage()); + socketClient.QueueConnectionClosedByClient(); + + await client.StartConnectionAsync(); + + var rawMessageData = socketClient.AssertGqltwsResponse(GqltwsMessageType.CONNECTION_ACK); + socketClient.AssertClientClosedConnection(); + + var expectedData = "{ \"type\": \"connection_ack\" }"; + CommonAssertions.AreEqualJsonStrings(expectedData, rawMessageData); + } } } \ No newline at end of file diff --git a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientAsserts.cs b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientAsserts.cs index ca3609107..45937a07f 100644 --- a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientAsserts.cs +++ b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientAsserts.cs @@ -25,12 +25,13 @@ public static class GraphqlWsLegacyClientAsserts /// The connection. /// The type of message to check for. /// if true, the message is removed from the queue. - internal static void AssertGraphqlWsLegacyResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGraphqlWsLegacyResponse( this MockClientConnection connection, GraphqlWsLegacyMessageType type, bool dequeue = true) { - connection.AssertGraphqlWsLegacyResponse(type, null, false, null, false, dequeue); + return connection.AssertGraphqlWsLegacyResponse(type, null, false, null, false, dequeue); } /// @@ -40,13 +41,14 @@ internal static void AssertGraphqlWsLegacyResponse( /// The type of message to check for. /// The id returned by the server, if supplied. /// if true, the message is removed from the queue. - internal static void AssertGraphqlWsLegacyResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGraphqlWsLegacyResponse( this MockClientConnection connection, GraphqlWsLegacyMessageType type, string id, bool dequeue = true) { - connection.AssertGraphqlWsLegacyResponse(type, id, true, null, false, dequeue); + return connection.AssertGraphqlWsLegacyResponse(type, id, true, null, false, dequeue); } /// @@ -58,17 +60,18 @@ internal static void AssertGraphqlWsLegacyResponse( /// The expected identifier of the subscription that rendered the data. /// The expected payload of the message, converted to a json string. /// if set to true if the message should be removed from the queue. - internal static void AssertGraphqlWsLegacyResponse( + /// The raw string data (usually json formatted) of the message data recevied by the connection proxy + internal static string AssertGraphqlWsLegacyResponse( this MockClientConnection connection, GraphqlWsLegacyMessageType type, string id, string expectedPayloadJson, bool dequeue = true) { - connection.AssertGraphqlWsLegacyResponse(type, id, true, expectedPayloadJson, true, dequeue); + return connection.AssertGraphqlWsLegacyResponse(type, id, true, expectedPayloadJson, true, dequeue); } - private static void AssertGraphqlWsLegacyResponse( + private static string AssertGraphqlWsLegacyResponse( this MockClientConnection connection, GraphqlWsLegacyMessageType type, string id, @@ -81,14 +84,14 @@ private static void AssertGraphqlWsLegacyResponse( Assert.Fail("No messages queued."); var message = dequeue ? connection.DequeueNextReceivedMessage() : connection.PeekNextReceivedMessage(); - var str = Encoding.UTF8.GetString(message.Data); + var rawData = Encoding.UTF8.GetString(message.Data); var options = new JsonSerializerOptions(); options.PropertyNameCaseInsensitive = true; options.AllowTrailingCommas = true; options.Converters.Add(new GraphqlWsLegacyResponseMessageConverter()); - var convertedMessage = JsonSerializer.Deserialize(str, options); + var convertedMessage = JsonSerializer.Deserialize(rawData, options); Assert.IsNotNull(convertedMessage, "Could not deserialized response message"); Assert.AreEqual(type, convertedMessage.Type, $"Expected message type of {type.ToString()} but got {convertedMessage.Type.ToString()}"); @@ -103,6 +106,8 @@ private static void AssertGraphqlWsLegacyResponse( if (compareId) Assert.AreEqual(id, convertedMessage.Id); + + return rawData; } } } \ No newline at end of file diff --git a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxyTests.cs b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxyTests.cs index 4bf1a0865..0547ee6ea 100644 --- a/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxyTests.cs +++ b/src/unit-tests/graphql-aspnet-subscriptions-tests/SubscriptionServer/Protocols/GraphqlWsLegacy/GraphqlWsLegacyClientProxyTests.cs @@ -501,5 +501,23 @@ public async Task Deserialize_InvalidMessage_ProcessesUnknownMessage() socketClient.AssertGraphqlWsLegacyResponse(GraphqlWsLegacyMessageType.ERROR); socketClient.AssertClientClosedConnection(); } + + [Test] + public async Task SendConnectionInitMessage_RespondsWithCorrectAckMessage() + { + using var restorePoint = new GraphQLGlobalSubscriptionRestorePoint(); + (var socketClient, var client, var router) = this.CreateConnection(); + + socketClient.QueueClientMessage(new GraphqlWsLegacyClientConnectionInitMessage()); + socketClient.QueueConnectionClosedByClient(); + + await client.StartConnectionAsync(); + + var rawMessageData = socketClient.AssertGraphqlWsLegacyResponse(GraphqlWsLegacyMessageType.CONNECTION_ACK); + socketClient.AssertClientClosedConnection(); + + var expectedData = "{ \"type\": \"connection_ack\" }"; + CommonAssertions.AreEqualJsonStrings(expectedData, rawMessageData); + } } } \ No newline at end of file diff --git a/src/unit-tests/graphql-aspnet-testframework/graphql-aspnet-testframework.csproj b/src/unit-tests/graphql-aspnet-testframework/graphql-aspnet-testframework.csproj index d294329bb..31430a712 100644 --- a/src/unit-tests/graphql-aspnet-testframework/graphql-aspnet-testframework.csproj +++ b/src/unit-tests/graphql-aspnet-testframework/graphql-aspnet-testframework.csproj @@ -2,7 +2,7 @@ - net8.0;net7.0;net6.0; + net9.0;net8.0; GraphQL.AspNet.Tests.Framework GraphQL.AspNet.TestFramework GraphQL ASP.NET Test Framework diff --git a/src/unit-tests/graphql-aspnet-tests-thirdpartydll/graphql-aspnet-tests-thirdpartydll.csproj b/src/unit-tests/graphql-aspnet-tests-thirdpartydll/graphql-aspnet-tests-thirdpartydll.csproj index fa889e4e6..ccb585eab 100644 --- a/src/unit-tests/graphql-aspnet-tests-thirdpartydll/graphql-aspnet-tests-thirdpartydll.csproj +++ b/src/unit-tests/graphql-aspnet-tests-thirdpartydll/graphql-aspnet-tests-thirdpartydll.csproj @@ -1,7 +1,7 @@  - net8.0;net7.0;net6.0; + net9.0;net8.0; latest $(NoWarn);1701;1702;1705;1591;NU1603;IDE0060;IDE0052;IDE0044;IDE0059;IDE0052 GraphQL.AspNet.Tests.ThirdPartyDll diff --git a/src/unit-tests/graphql-aspnet-tests/Common/OrderedDictionaryTests.cs b/src/unit-tests/graphql-aspnet-tests/Common/OrderedDictionaryTests.cs index ef8174de5..e56e4398d 100644 --- a/src/unit-tests/graphql-aspnet-tests/Common/OrderedDictionaryTests.cs +++ b/src/unit-tests/graphql-aspnet-tests/Common/OrderedDictionaryTests.cs @@ -16,13 +16,15 @@ namespace GraphQL.AspNet.Tests.Common using System.Linq; using GraphQL.AspNet.Common.Generics; using NUnit.Framework; + using OrderedDictionaryOfStringAndInt = GraphQL.AspNet.Common.Generics.OrderedDictionary; + using OrderedDictionaryOfStringAndString = GraphQL.AspNet.Common.Generics.OrderedDictionary; [TestFixture] public class OrderedDictionaryTests { - private OrderedDictionary GetAlphabetDictionary(IEqualityComparer comparer = null) + private OrderedDictionaryOfStringAndString GetAlphabetDictionary(IEqualityComparer comparer = null) { - OrderedDictionary alphabet = new OrderedDictionary(comparer); + OrderedDictionaryOfStringAndString alphabet = new OrderedDictionaryOfStringAndString(comparer); for (var a = Convert.ToInt32('a'); a <= Convert.ToInt32('z'); a++) { var c = Convert.ToChar(a); @@ -57,11 +59,11 @@ public int Compare(int x, int y) [Test] public void Constructor_FromOtherDictionary() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); od.Add("key1", "value1"); od.Add("key2", "value2"); - var od2 = new OrderedDictionary(od); + var od2 = new OrderedDictionaryOfStringAndString(od); Assert.AreEqual(2, od2.Count); Assert.AreEqual("value1", od2["key1"]); Assert.AreEqual("value2", od2["key2"]); @@ -70,12 +72,12 @@ public void Constructor_FromOtherDictionary() [Test] public void Constructor_FromOtherDictionary_CaseInsensitive() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); od.Add("key1", "value1"); od.Add("key2", "value2"); Assert.IsFalse(od.ContainsKey("KEY1")); - var od2 = new OrderedDictionary(od, StringComparer.InvariantCultureIgnoreCase); + var od2 = new OrderedDictionaryOfStringAndString(od, StringComparer.InvariantCultureIgnoreCase); Assert.AreEqual(2, od2.Count); Assert.AreEqual("value1", od2["KEY1"]); Assert.AreEqual("value2", od2["KEY2"]); @@ -84,7 +86,7 @@ public void Constructor_FromOtherDictionary_CaseInsensitive() [Test] public void Browser_PropertyCheck() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndInt(); dic.Add("key1", 1); dic.Add("key2", 2); @@ -110,7 +112,7 @@ public void Browser_PropertyCheck() [Test] public void DuplicateAdd_ThrowsError() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndInt(); dic.Add("key1", 1); Assert.Throws(() => { dic.Add("key1", 1); }); @@ -119,7 +121,7 @@ public void DuplicateAdd_ThrowsError() [Test] public void ICollectionKVP_CastingCheck() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndInt(); var kvp = new KeyValuePair("key1", 3); var col = dic as ICollection>; @@ -149,7 +151,7 @@ public void ICollectionKVP_CastingCheck() [Test] public void IDicionaryKVP_CastingCheck() { - var od = new OrderedDictionary() as IDictionary; + var od = new OrderedDictionaryOfStringAndString() as IDictionary; Assert.AreEqual(0, od.Count); od.Add("foo", "bar"); @@ -182,7 +184,7 @@ public void IDicionaryKVP_CastingCheck() [Test] public void IOrderedDictionary_CastingCheck() { - var od = new OrderedDictionary() as IOrderedDictionary; + var od = new OrderedDictionaryOfStringAndString() as IOrderedDictionary; Assert.AreEqual(0, od.Count); // IOrderedDictionary.Insert @@ -252,7 +254,7 @@ public void IDictionary_CastingCheck() [Test] public void Add() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); Assert.AreEqual(0, od.Count); Assert.AreEqual(-1, od.IndexOf("foo")); @@ -268,7 +270,7 @@ public void Add() [Test] public void Remove() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); od.Add("foo", "bar"); Assert.AreEqual(1, od.Count); @@ -280,7 +282,7 @@ public void Remove() [Test] public void RemoveAt() { - var od = new OrderedDictionary(); + var od = new OrderedDictionaryOfStringAndString(); od.Add("foo", "bar"); Assert.AreEqual(1, od.Count); @@ -585,7 +587,7 @@ public void DelegateKeyCollection_PropertyCheck() [Test] public void DictionaryEnumerator_Reset_YieldsFirstItemAgain() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndString(); dic.Add("a", "string1"); dic.Add("b", "string2"); @@ -604,7 +606,7 @@ public void DictionaryEnumerator_Reset_YieldsFirstItemAgain() [Test] public void DictionaryEnumerator_PropertyCheck() { - var dic = new OrderedDictionary(); + var dic = new OrderedDictionaryOfStringAndString(); dic.Add("a", "string1"); dic.Add("b", "string2");