From 67b1f8c53c7706aa4dfcef3597845e11c141c7d3 Mon Sep 17 00:00:00 2001 From: martincostello Date: Wed, 11 Sep 2024 22:49:41 +0100 Subject: [PATCH 01/11] Use JSON polymorphism Use JSON polymorphism to (de)serialize Alexa requests and responses. --- src/LondonTravel.Skill/AlexaSkill.cs | 4 +- .../AppJsonSerializerContext.cs | 2 +- src/LondonTravel.Skill/FunctionHandler.cs | 10 ++--- src/LondonTravel.Skill/Models/IRequest.cs | 15 -------- .../Models/ISessionEndedRequest.cs | 11 ------ .../Models/ISystemExceptionRequest.cs | 11 ------ .../Models/IntentRequest.cs | 18 +++++++++ .../{IIntentRequest.cs => LaunchRequest.cs} | 9 +++-- src/LondonTravel.Skill/Models/Request.cs | 37 ++++--------------- .../Models/SessionEndedRequest.cs | 20 ++++++++++ .../Models/SystemExceptionRequest.cs | 19 ++++++++++ .../EndToEndTests.cs | 20 +++++----- .../AlexaFunctionTests.cs | 4 +- .../LondonTravel.Skill.Tests/EndToEndTests.cs | 10 ++--- .../LondonTravel.Skill.Tests/FunctionTests.cs | 10 ++--- test/LondonTravel.Skill.Tests/LaunchTests.cs | 2 +- .../SerializationTests.cs | 11 +++--- .../SessionEndedTests.cs | 2 +- .../UnknownIntentTests.cs | 5 +++ .../UnknownRequestTests.cs | 7 +++- 20 files changed, 119 insertions(+), 108 deletions(-) delete mode 100644 src/LondonTravel.Skill/Models/IRequest.cs delete mode 100644 src/LondonTravel.Skill/Models/ISessionEndedRequest.cs delete mode 100644 src/LondonTravel.Skill/Models/ISystemExceptionRequest.cs create mode 100644 src/LondonTravel.Skill/Models/IntentRequest.cs rename src/LondonTravel.Skill/Models/{IIntentRequest.cs => LaunchRequest.cs} (60%) create mode 100644 src/LondonTravel.Skill/Models/SessionEndedRequest.cs create mode 100644 src/LondonTravel.Skill/Models/SystemExceptionRequest.cs diff --git a/src/LondonTravel.Skill/AlexaSkill.cs b/src/LondonTravel.Skill/AlexaSkill.cs index 43046726..40cbde3b 100644 --- a/src/LondonTravel.Skill/AlexaSkill.cs +++ b/src/LondonTravel.Skill/AlexaSkill.cs @@ -26,7 +26,7 @@ internal sealed class AlexaSkill( /// /// The to return from the skill. /// - public SkillResponse OnError(ISystemExceptionRequest error, Session session) + public SkillResponse OnError(SystemExceptionRequest error, Session session) { Log.SystemError( logger, @@ -67,7 +67,7 @@ public SkillResponse OnError(Exception? exception, Session session, string reque /// A representing the asynchronous operation /// which returns the to return from the skill. /// - public async Task OnIntentAsync(IIntentRequest intent, Session session) + public async Task OnIntentAsync(IntentRequest intent, Session session) { var handler = intentFactory.Create(intent.Intent); return await handler.RespondAsync(intent.Intent, session); diff --git a/src/LondonTravel.Skill/AppJsonSerializerContext.cs b/src/LondonTravel.Skill/AppJsonSerializerContext.cs index 04a1f94f..731becbc 100644 --- a/src/LondonTravel.Skill/AppJsonSerializerContext.cs +++ b/src/LondonTravel.Skill/AppJsonSerializerContext.cs @@ -19,5 +19,5 @@ namespace MartinCostello.LondonTravel.Skill; [JsonSerializable(typeof(SkillResponse))] [JsonSerializable(typeof(SkillUserPreferences))] [JsonSerializable(typeof(StandardCard))] -[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] +[JsonSourceGenerationOptions(AllowOutOfOrderMetadataProperties = true, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] public sealed partial class AppJsonSerializerContext : JsonSerializerContext; diff --git a/src/LondonTravel.Skill/FunctionHandler.cs b/src/LondonTravel.Skill/FunctionHandler.cs index 8eb73f42..98f0ee9f 100644 --- a/src/LondonTravel.Skill/FunctionHandler.cs +++ b/src/LondonTravel.Skill/FunctionHandler.cs @@ -49,12 +49,12 @@ private async Task HandleRequestAsync(SkillRequest request) { try { - return request.Request.Type switch + return request.Request switch { - RequestTypes.Intent => await skill.OnIntentAsync(request.Request, request.Session), - RequestTypes.Launch => skill.OnLaunch(request.Session), - RequestTypes.SessionEnded => skill.OnSessionEnded(request.Session), - RequestTypes.SystemException => skill.OnError(request.Request, request.Session), + IntentRequest intent => await skill.OnIntentAsync(intent, request.Session), + LaunchRequest => skill.OnLaunch(request.Session), + SessionEndedRequest => skill.OnSessionEnded(request.Session), + SystemExceptionRequest exception => skill.OnError(exception, request.Session), _ => skill.OnError(null, request.Session, request.Request.Type), }; } diff --git a/src/LondonTravel.Skill/Models/IRequest.cs b/src/LondonTravel.Skill/Models/IRequest.cs deleted file mode 100644 index c92a4bc5..00000000 --- a/src/LondonTravel.Skill/Models/IRequest.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Martin Costello, 2017. All rights reserved. -// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. - -namespace MartinCostello.LondonTravel.Skill.Models; - -internal interface IRequest -{ - string Type { get; } - - string RequestId { get; } - - string Locale { get; } - - DateTime Timestamp { get; } -} diff --git a/src/LondonTravel.Skill/Models/ISessionEndedRequest.cs b/src/LondonTravel.Skill/Models/ISessionEndedRequest.cs deleted file mode 100644 index 12b9809d..00000000 --- a/src/LondonTravel.Skill/Models/ISessionEndedRequest.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Martin Costello, 2017. All rights reserved. -// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. - -namespace MartinCostello.LondonTravel.Skill.Models; - -internal interface ISessionEndedRequest : IRequest -{ - Reason Reason { get; } - - AlexaError Error { get; } -} diff --git a/src/LondonTravel.Skill/Models/ISystemExceptionRequest.cs b/src/LondonTravel.Skill/Models/ISystemExceptionRequest.cs deleted file mode 100644 index dfef918b..00000000 --- a/src/LondonTravel.Skill/Models/ISystemExceptionRequest.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Martin Costello, 2017. All rights reserved. -// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. - -namespace MartinCostello.LondonTravel.Skill.Models; - -internal interface ISystemExceptionRequest : IRequest -{ - AlexaErrorCause ErrorCause { get; } - - AlexaError Error { get; } -} diff --git a/src/LondonTravel.Skill/Models/IntentRequest.cs b/src/LondonTravel.Skill/Models/IntentRequest.cs new file mode 100644 index 00000000..fa7fb912 --- /dev/null +++ b/src/LondonTravel.Skill/Models/IntentRequest.cs @@ -0,0 +1,18 @@ +// Copyright (c) Martin Costello, 2017. All rights reserved. +// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. + +using System.Text.Json.Serialization; + +namespace MartinCostello.LondonTravel.Skill.Models; + +public sealed class IntentRequest : Request +{ + [JsonIgnore] + public override string Type => "IntentRequest"; + + [JsonPropertyName("dialogState")] + public string DialogState { get; set; } = default!; + + [JsonPropertyName("intent")] + public Intent Intent { get; set; } = default!; +} diff --git a/src/LondonTravel.Skill/Models/IIntentRequest.cs b/src/LondonTravel.Skill/Models/LaunchRequest.cs similarity index 60% rename from src/LondonTravel.Skill/Models/IIntentRequest.cs rename to src/LondonTravel.Skill/Models/LaunchRequest.cs index 7f646b69..4982ec2e 100644 --- a/src/LondonTravel.Skill/Models/IIntentRequest.cs +++ b/src/LondonTravel.Skill/Models/LaunchRequest.cs @@ -1,11 +1,12 @@ // Copyright (c) Martin Costello, 2017. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. +using System.Text.Json.Serialization; + namespace MartinCostello.LondonTravel.Skill.Models; -internal interface IIntentRequest : IRequest +public sealed class LaunchRequest : Request { - string DialogState { get; } - - Intent Intent { get; } + [JsonIgnore] + public override string Type => "LaunchRequest"; } diff --git a/src/LondonTravel.Skill/Models/Request.cs b/src/LondonTravel.Skill/Models/Request.cs index d2d408d5..2e93ff30 100644 --- a/src/LondonTravel.Skill/Models/Request.cs +++ b/src/LondonTravel.Skill/Models/Request.cs @@ -5,11 +5,15 @@ namespace MartinCostello.LondonTravel.Skill.Models; -public sealed class Request : IRequest, IIntentRequest, ISessionEndedRequest, ISystemExceptionRequest +[JsonDerivedType(typeof(IntentRequest), RequestTypes.Intent)] +[JsonDerivedType(typeof(LaunchRequest), RequestTypes.Launch)] +[JsonDerivedType(typeof(SessionEndedRequest), RequestTypes.SessionEnded)] +[JsonDerivedType(typeof(SystemExceptionRequest), RequestTypes.SystemException)] +[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] +public abstract class Request { - [JsonPropertyName("type")] - [JsonRequired] - public string Type { get; set; } = default!; + [JsonIgnore] + public abstract string Type { get; } [JsonPropertyName("requestId")] public string RequestId { get; set; } = default!; @@ -20,29 +24,4 @@ public sealed class Request : IRequest, IIntentRequest, ISessionEndedRequest, IS [JsonConverter(typeof(MixedDateTimeConverter))] [JsonPropertyName("timestamp")] public DateTime Timestamp { get; set; } - - //// Properties for "IntentRequest" - - [JsonPropertyName("dialogState")] - public string DialogState { get; set; } = default!; - - [JsonPropertyName("intent")] - public Intent Intent { get; set; } = default!; - - //// Properties for "SessionEndedRequest" - - [JsonConverter(typeof(JsonStringEnumConverter))] - [JsonPropertyName("reason")] - public Reason Reason { get; set; } - - //// Properties for "System.ExceptionEncountered" - - [JsonPropertyName("cause")] - public AlexaErrorCause ErrorCause { get; set; } = default!; - - //// Properties for "SessionEndedRequest" and "System.ExceptionEncountered" - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("error")] - public AlexaError Error { get; set; } = default!; } diff --git a/src/LondonTravel.Skill/Models/SessionEndedRequest.cs b/src/LondonTravel.Skill/Models/SessionEndedRequest.cs new file mode 100644 index 00000000..7737a994 --- /dev/null +++ b/src/LondonTravel.Skill/Models/SessionEndedRequest.cs @@ -0,0 +1,20 @@ +// Copyright (c) Martin Costello, 2017. All rights reserved. +// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. + +using System.Text.Json.Serialization; + +namespace MartinCostello.LondonTravel.Skill.Models; + +public sealed class SessionEndedRequest : Request +{ + [JsonIgnore] + public override string Type => "SessionEndedRequest"; + + [JsonConverter(typeof(JsonStringEnumConverter))] + [JsonPropertyName("reason")] + public Reason Reason { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("error")] + public AlexaError Error { get; set; } = default!; +} diff --git a/src/LondonTravel.Skill/Models/SystemExceptionRequest.cs b/src/LondonTravel.Skill/Models/SystemExceptionRequest.cs new file mode 100644 index 00000000..32edf6a0 --- /dev/null +++ b/src/LondonTravel.Skill/Models/SystemExceptionRequest.cs @@ -0,0 +1,19 @@ +// Copyright (c) Martin Costello, 2017. All rights reserved. +// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. + +using System.Text.Json.Serialization; + +namespace MartinCostello.LondonTravel.Skill.Models; + +public sealed class SystemExceptionRequest : Request +{ + [JsonIgnore] + public override string Type => "System.ExceptionEncountered"; + + [JsonPropertyName("cause")] + public AlexaErrorCause ErrorCause { get; set; } = default!; + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("error")] + public AlexaError Error { get; set; } = default!; +} diff --git a/test/LondonTravel.Skill.NativeAotTests/EndToEndTests.cs b/test/LondonTravel.Skill.NativeAotTests/EndToEndTests.cs index 00c00d31..cec1ade7 100644 --- a/test/LondonTravel.Skill.NativeAotTests/EndToEndTests.cs +++ b/test/LondonTravel.Skill.NativeAotTests/EndToEndTests.cs @@ -132,7 +132,7 @@ public async Task Alexa_Function_Can_Process_Intent_Request_For_Line_Status() public async Task Alexa_Function_Can_Process_Launch_Request() { // Arrange - var request = CreateRequest("LaunchRequest"); + var request = CreateRequest(); // Act var actual = await ProcessRequestAsync(request); @@ -153,7 +153,7 @@ public async Task Alexa_Function_Can_Process_Launch_Request() public async Task Alexa_Function_Can_Process_Session_Ended_Request() { // Arrange - var session = new Request() + var session = new SessionEndedRequest() { Reason = Reason.ExceededMaxReprompts, Error = new() @@ -163,7 +163,7 @@ public async Task Alexa_Function_Can_Process_Session_Ended_Request() }, }; - var request = CreateRequest("SessionEndedRequest", session); + var request = CreateRequest(session); // Act var actual = await ProcessRequestAsync(request); @@ -184,7 +184,7 @@ public async Task Alexa_Function_Can_Process_Session_Ended_Request() public async Task Alexa_Function_Can_Process_System_Exception_Request() { // Arrange - var exception = new Request() + var exception = new SystemExceptionRequest() { Error = new() { @@ -197,7 +197,7 @@ public async Task Alexa_Function_Can_Process_System_Exception_Request() }, }; - var request = CreateRequest("System.ExceptionEncountered", exception); + var request = CreateRequest(exception); // Act var actual = await ProcessRequestAsync(request); @@ -215,7 +215,7 @@ public async Task Alexa_Function_Can_Process_System_Exception_Request() private static SkillRequest CreateIntentRequest(string name, params Slot[] slots) { - var request = new Request() + var request = new IntentRequest() { Intent = new Intent() { @@ -233,10 +233,11 @@ private static SkillRequest CreateIntentRequest(string name, params Slot[] slots } } - return CreateRequest("IntentRequest", request); + return CreateRequest(request); } - private static SkillRequest CreateRequest(string type, Request? request = null) + private static SkillRequest CreateRequest(T? request = null) + where T : Request, new() { var application = new Application() { @@ -265,7 +266,7 @@ private static SkillRequest CreateRequest(string type, Request? request = null) User = user, }, }, - Request = request ?? new(), + Request = request ?? new T(), Session = new() { Application = application, @@ -276,7 +277,6 @@ private static SkillRequest CreateRequest(string type, Request? request = null) Version = "1.0", }; - result.Request.Type = type; result.Request.Locale = "en-GB"; return result; diff --git a/test/LondonTravel.Skill.Tests/AlexaFunctionTests.cs b/test/LondonTravel.Skill.Tests/AlexaFunctionTests.cs index ce872b9e..b9654f35 100644 --- a/test/LondonTravel.Skill.Tests/AlexaFunctionTests.cs +++ b/test/LondonTravel.Skill.Tests/AlexaFunctionTests.cs @@ -58,7 +58,7 @@ public async Task Cannot_Invoke_Function_With_System_Failure() var function = await CreateFunctionAsync(); var context = new TestLambdaContext(); - var error = new Request() + var error = new SystemExceptionRequest() { Error = new() { @@ -71,7 +71,7 @@ public async Task Cannot_Invoke_Function_With_System_Failure() }, }; - var request = CreateRequest("System.ExceptionEncountered", error); + var request = CreateRequest(error); // Act var actual = await function.HandlerAsync(request, context); diff --git a/test/LondonTravel.Skill.Tests/EndToEndTests.cs b/test/LondonTravel.Skill.Tests/EndToEndTests.cs index d05bd3ee..f218185b 100644 --- a/test/LondonTravel.Skill.Tests/EndToEndTests.cs +++ b/test/LondonTravel.Skill.Tests/EndToEndTests.cs @@ -126,7 +126,7 @@ public async Task Alexa_Function_Can_Process_Intent_Request_For_Line_Status( public async Task Alexa_Function_Can_Process_Launch_Request() { // Arrange - var request = CreateRequest("LaunchRequest"); + var request = CreateRequest(); // Act var actual = await ProcessRequestAsync(request); @@ -146,7 +146,7 @@ public async Task Alexa_Function_Can_Process_Launch_Request() public async Task Alexa_Function_Can_Process_Session_Ended_Request() { // Arrange - var session = new Request() + var session = new SessionEndedRequest() { Reason = Reason.ExceededMaxReprompts, Error = new() @@ -156,7 +156,7 @@ public async Task Alexa_Function_Can_Process_Session_Ended_Request() }, }; - var request = CreateRequest("SessionEndedRequest", session); + var request = CreateRequest(session); // Act var actual = await ProcessRequestAsync(request); @@ -176,7 +176,7 @@ public async Task Alexa_Function_Can_Process_Session_Ended_Request() public async Task Alexa_Function_Can_Process_System_Exception_Request() { // Arrange - var exception = new Request() + var exception = new SystemExceptionRequest() { Error = new() { @@ -189,7 +189,7 @@ public async Task Alexa_Function_Can_Process_System_Exception_Request() }, }; - var request = CreateRequest("System.ExceptionEncountered", exception); + var request = CreateRequest(exception); // Act var actual = await ProcessRequestAsync(request); diff --git a/test/LondonTravel.Skill.Tests/FunctionTests.cs b/test/LondonTravel.Skill.Tests/FunctionTests.cs index 5ba890f7..207f55cf 100644 --- a/test/LondonTravel.Skill.Tests/FunctionTests.cs +++ b/test/LondonTravel.Skill.Tests/FunctionTests.cs @@ -38,7 +38,7 @@ protected virtual async Task CreateFunctionAsync() protected virtual SkillRequest CreateIntentRequest(string name, params Slot[] slots) { - var request = new Request() + var request = new IntentRequest() { Intent = new Intent() { @@ -56,10 +56,11 @@ protected virtual SkillRequest CreateIntentRequest(string name, params Slot[] sl } } - return CreateRequest("IntentRequest", request); + return CreateRequest(request); } - protected virtual SkillRequest CreateRequest(string type, Request? request = null) + protected virtual SkillRequest CreateRequest(T? request = null) + where T : Request, new() { var application = new Application() { @@ -88,7 +89,7 @@ protected virtual SkillRequest CreateRequest(string type, Request? request = nul User = user, }, }, - Request = request ?? new(), + Request = request ?? new T(), Session = new() { Application = application, @@ -99,7 +100,6 @@ protected virtual SkillRequest CreateRequest(string type, Request? request = nul Version = "1.0", }; - result.Request.Type = type; result.Request.Locale = "en-GB"; return result; diff --git a/test/LondonTravel.Skill.Tests/LaunchTests.cs b/test/LondonTravel.Skill.Tests/LaunchTests.cs index 7ae7d87a..a8ed22bf 100644 --- a/test/LondonTravel.Skill.Tests/LaunchTests.cs +++ b/test/LondonTravel.Skill.Tests/LaunchTests.cs @@ -14,7 +14,7 @@ public async Task Can_Invoke_Function() // Arrange var function = await CreateFunctionAsync(); - var request = CreateRequest("LaunchRequest"); + var request = CreateRequest(); var context = new TestLambdaContext(); // Act diff --git a/test/LondonTravel.Skill.Tests/SerializationTests.cs b/test/LondonTravel.Skill.Tests/SerializationTests.cs index 2c638e5e..f1eaf8bf 100644 --- a/test/LondonTravel.Skill.Tests/SerializationTests.cs +++ b/test/LondonTravel.Skill.Tests/SerializationTests.cs @@ -9,11 +9,11 @@ namespace MartinCostello.LondonTravel.Skill; public static class SerializationTests { [Theory] - [InlineData("IntentRequest")] - [InlineData("LaunchRequest")] - [InlineData("LaunchRequestWithEpochTimestamp")] - [InlineData("SessionEndedRequest")] - public static void Can_Deserialize_Request(string name) + [InlineData("IntentRequest", typeof(IntentRequest))] + [InlineData("LaunchRequest", typeof(LaunchRequest))] + [InlineData("LaunchRequestWithEpochTimestamp", typeof(LaunchRequest))] + [InlineData("SessionEndedRequest", typeof(SessionEndedRequest))] + public static void Can_Deserialize_Request(string name, Type expectedType) { // Arrange JsonSerializer.IsReflectionEnabledByDefault.ShouldBeFalse(); @@ -27,6 +27,7 @@ public static void Can_Deserialize_Request(string name) // Assert actual.ShouldNotBeNull(); actual.Request.ShouldNotBeNull(); + actual.Request.ShouldBeOfType(expectedType); } [Fact] diff --git a/test/LondonTravel.Skill.Tests/SessionEndedTests.cs b/test/LondonTravel.Skill.Tests/SessionEndedTests.cs index f20e9a28..830cc4a1 100644 --- a/test/LondonTravel.Skill.Tests/SessionEndedTests.cs +++ b/test/LondonTravel.Skill.Tests/SessionEndedTests.cs @@ -14,7 +14,7 @@ public async Task Can_Invoke_Function() // Arrange var function = await CreateFunctionAsync(); - var request = CreateRequest("SessionEndedRequest"); + var request = CreateRequest(); var context = new TestLambdaContext(); // Act diff --git a/test/LondonTravel.Skill.Tests/UnknownIntentTests.cs b/test/LondonTravel.Skill.Tests/UnknownIntentTests.cs index f26ff149..6b478650 100644 --- a/test/LondonTravel.Skill.Tests/UnknownIntentTests.cs +++ b/test/LondonTravel.Skill.Tests/UnknownIntentTests.cs @@ -30,4 +30,9 @@ public async Task Can_Invoke_Function() response.OutputSpeech.Type.ShouldBe("SSML"); response.OutputSpeech.Ssml.ShouldBe("Sorry, I don't understand how to do that."); } + + private sealed class UnknownRequest : Request + { + public override string Type => "Unknown"; + } } diff --git a/test/LondonTravel.Skill.Tests/UnknownRequestTests.cs b/test/LondonTravel.Skill.Tests/UnknownRequestTests.cs index 8de4420a..93501056 100644 --- a/test/LondonTravel.Skill.Tests/UnknownRequestTests.cs +++ b/test/LondonTravel.Skill.Tests/UnknownRequestTests.cs @@ -15,7 +15,7 @@ public async Task Can_Invoke_Function() var function = await CreateFunctionAsync(); var context = new TestLambdaContext(); - var request = CreateRequest("Unknown"); + var request = CreateRequest(); // Act var actual = await function.HandlerAsync(request, context); @@ -23,4 +23,9 @@ public async Task Can_Invoke_Function() // Assert AssertResponse(actual); } + + private sealed class UnknownRequest : Request + { + public override string Type => "Unknown"; + } } From 0daf0b9da7ff164ade49666b1b615c19d09a827a Mon Sep 17 00:00:00 2001 From: martincostello Date: Wed, 11 Sep 2024 22:53:23 +0100 Subject: [PATCH 02/11] Consume .NET daily builds Update to the latest daily build of .NET 9. --- Directory.Packages.props | 16 ++++++++-------- NuGet.config | 4 ++++ global.json | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 326b381e..a7218e3d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,15 +15,15 @@ - - - - - - + + + + + + - + @@ -38,7 +38,7 @@ - + diff --git a/NuGet.config b/NuGet.config index 38ac8e75..25f97f34 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,9 +2,13 @@ + + + + diff --git a/global.json b/global.json index 52dae233..e9318a1c 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100-rc.1.24452.12", + "version": "9.0.100-rc.2.24461.4", "allowPrerelease": false, "rollForward": "latestMajor" }, From f1ae630e31ef0ccfa7f10135c6dd29eba5dd3355 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 12 Sep 2024 10:34:28 +0100 Subject: [PATCH 03/11] Debug JSON payloads Attempt to debug JSON payloads. --- src/LondonTravel.Skill/AppLambdaSerializer.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/LondonTravel.Skill/AppLambdaSerializer.cs b/src/LondonTravel.Skill/AppLambdaSerializer.cs index 3b43de6f..c531c8c9 100644 --- a/src/LondonTravel.Skill/AppLambdaSerializer.cs +++ b/src/LondonTravel.Skill/AppLambdaSerializer.cs @@ -10,4 +10,41 @@ public sealed class AppLambdaSerializer() : SourceGeneratorLambdaJsonSerializer< { protected override JsonSerializerOptions CreateDefaultJsonSerializationOptions() => new(AppJsonSerializerContext.Default.Options); + + protected override T InternalDeserialize(byte[] utf8Json) + { + try + { + Console.WriteLine(Convert.ToBase64String(utf8Json)); + return base.InternalDeserialize(utf8Json); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + throw; + } + } + + protected override void InternalSerialize(Utf8JsonWriter writer, T response) + { + try + { + using (var stream = new MemoryStream()) + { + using var writer2 = new Utf8JsonWriter(stream, WriterOptions); + base.InternalSerialize(writer2, response); + stream.Position = 0L; + + Console.WriteLine(Convert.ToBase64String(stream.ToArray())); + } + + Console.WriteLine(response.GetType().ToString()); + base.InternalSerialize(writer, response); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + throw; + } + } } From 3da1df7e776825d9a2b11ea1aa9b09eabe7b55ec Mon Sep 17 00:00:00 2001 From: costellobot <102549341+costellobot@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:11:01 +0100 Subject: [PATCH 04/11] Update .NET SDK to 9.0.100-rc.2.24462.3 (#1433) * Update .NET SDK Update .NET SDK to version 9.0.100-rc.2.24462.3. --- updated-dependencies: - dependency-name: Microsoft.NET.Sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: costellobot <102549341+costellobot@users.noreply.github.com> * Bump .NET NuGet packages Bumps .NET dependencies to their latest versions for the .NET 9.0.100-rc.2.24462.3 SDK. Bumps Microsoft.AspNetCore.WebUtilities from 9.0.0-rc.2.24460.5 to 9.0.0-rc.2.24461.26. Bumps Microsoft.Extensions.Configuration.Binder from 9.0.0-rc.2.24459.11 to 9.0.0-rc.2.24461.13. Bumps Microsoft.Extensions.Configuration.EnvironmentVariables from 9.0.0-rc.2.24459.11 to 9.0.0-rc.2.24461.13. Bumps Microsoft.Extensions.Configuration.Json from 9.0.0-rc.2.24459.11 to 9.0.0-rc.2.24461.13. Bumps Microsoft.Extensions.DependencyInjection from 9.0.0-rc.2.24459.11 to 9.0.0-rc.2.24461.13. Bumps Microsoft.Extensions.Http from 9.0.0-rc.2.24459.11 to 9.0.0-rc.2.24461.13. Bumps Microsoft.Extensions.Logging.Console from 9.0.0-rc.2.24459.11 to 9.0.0-rc.2.24461.13. Bumps System.Text.Json from 9.0.0-rc.2.24459.11 to 9.0.0-rc.2.24461.13. --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.WebUtilities dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Configuration.Binder dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Configuration.EnvironmentVariables dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Configuration.Json dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.DependencyInjection dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Http dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Logging.Console dependency-type: direct:production update-type: version-update:semver-major - dependency-name: System.Text.Json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: costellobot <102549341+costellobot@users.noreply.github.com> --------- Signed-off-by: costellobot <102549341+costellobot@users.noreply.github.com> --- Directory.Packages.props | 16 ++++++++-------- global.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index a7218e3d..6617e2fe 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,15 +15,15 @@ - - - - - - + + + + + + - + @@ -38,7 +38,7 @@ - + diff --git a/global.json b/global.json index e9318a1c..0d9f414d 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100-rc.2.24461.4", + "version": "9.0.100-rc.2.24462.3", "allowPrerelease": false, "rollForward": "latestMajor" }, From a3fd3bafd4959ed41d4ab98ecb1a32ae773bdbca Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 12 Sep 2024 11:51:37 +0100 Subject: [PATCH 05/11] Add more logging Add more logging to see where the hang is happening. --- src/LondonTravel.Skill/AlexaFunction.cs | 10 +++++++++- src/LondonTravel.Skill/AppLambdaSerializer.cs | 20 ++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/LondonTravel.Skill/AlexaFunction.cs b/src/LondonTravel.Skill/AlexaFunction.cs index c30a158a..dbc1c4bf 100644 --- a/src/LondonTravel.Skill/AlexaFunction.cs +++ b/src/LondonTravel.Skill/AlexaFunction.cs @@ -62,12 +62,18 @@ public virtual async ValueTask DisposeAsync() /// public async Task HandlerAsync(SkillRequest request, ILambdaContext context) { + Console.WriteLine("HandlerAsync() Start"); + EnsureInitialized(); - return await OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaWrapper.TraceAsync( + var result = await OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaWrapper.TraceAsync( _serviceProvider.GetRequiredService(), HandlerCoreAsync, request, context); + + Console.WriteLine("HandlerAsync() End"); + + return result; } /// @@ -79,7 +85,9 @@ public async Task HandlerAsync(SkillRequest request, ILambdaConte [MemberNotNull(nameof(_serviceProvider))] public Task InitializeAsync() { + Console.WriteLine("InitializeAsync() Start"); _serviceProvider ??= CreateServiceProvider(); + Console.WriteLine("InitializeAsync() End"); return Task.FromResult(true); } diff --git a/src/LondonTravel.Skill/AppLambdaSerializer.cs b/src/LondonTravel.Skill/AppLambdaSerializer.cs index c531c8c9..2950deb3 100644 --- a/src/LondonTravel.Skill/AppLambdaSerializer.cs +++ b/src/LondonTravel.Skill/AppLambdaSerializer.cs @@ -15,12 +15,16 @@ protected override T InternalDeserialize(byte[] utf8Json) { try { - Console.WriteLine(Convert.ToBase64String(utf8Json)); - return base.InternalDeserialize(utf8Json); + Console.WriteLine($"Request: {Convert.ToBase64String(utf8Json)}"); + var result = base.InternalDeserialize(utf8Json); + + Console.WriteLine($"Request: {result.GetType()}"); + + return result; } catch (Exception ex) { - Console.WriteLine(ex.ToString()); + Console.WriteLine(ex); throw; } } @@ -29,21 +33,23 @@ protected override void InternalSerialize(Utf8JsonWriter writer, T response) { try { + Console.WriteLine($"Response: {response.GetType()}"); + using (var stream = new MemoryStream()) { using var writer2 = new Utf8JsonWriter(stream, WriterOptions); base.InternalSerialize(writer2, response); stream.Position = 0L; - - Console.WriteLine(Convert.ToBase64String(stream.ToArray())); + Console.WriteLine($"Response: {Convert.ToBase64String(stream.ToArray())}"); } - Console.WriteLine(response.GetType().ToString()); base.InternalSerialize(writer, response); + + Console.WriteLine("Response serialized"); } catch (Exception ex) { - Console.WriteLine(ex.ToString()); + Console.WriteLine(ex); throw; } } From e3a172585e851ed8b96802e103eaa1120062e261 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 12 Sep 2024 12:01:12 +0100 Subject: [PATCH 06/11] Avoid test deadlock Avoid deadlock in AoT tests when writing to the console. --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index 79471a3b..0d7d602a 100755 --- a/build.ps1 +++ b/build.ps1 @@ -109,7 +109,7 @@ $testProjects = @( ) $testProjectsForAot = @( - (Join-Path $solutionPath "test" "LondonTravel.Skill.NativeAotTests" "LondonTravel.Skill.NativeAotTests.csproj") + #(Join-Path $solutionPath "test" "LondonTravel.Skill.NativeAotTests" "LondonTravel.Skill.NativeAotTests.csproj") ) $publishProjects = @( From 14640282a9222fc1194e7f40935c43c3ff35aced Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 12 Sep 2024 12:08:41 +0100 Subject: [PATCH 07/11] Disable tests Disable the tests entirely - will probably cause a deadlock when deployed, but let's see... --- build.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.ps1 b/build.ps1 index 0d7d602a..afe98cc3 100755 --- a/build.ps1 +++ b/build.ps1 @@ -104,8 +104,8 @@ function DotNetPublish { } $testProjects = @( - (Join-Path $solutionPath "test" "LondonTravel.Skill.Tests" "LondonTravel.Skill.Tests.csproj"), - (Join-Path $solutionPath "test" "LondonTravel.Skill.EndToEndTests" "LondonTravel.Skill.EndToEndTests.csproj") + #(Join-Path $solutionPath "test" "LondonTravel.Skill.Tests" "LondonTravel.Skill.Tests.csproj"), + #(Join-Path $solutionPath "test" "LondonTravel.Skill.EndToEndTests" "LondonTravel.Skill.EndToEndTests.csproj") ) $testProjectsForAot = @( From 9c5caecf98f214284079035a8053616ef765e9d5 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 12 Sep 2024 12:26:49 +0100 Subject: [PATCH 08/11] Do not await handler Do not await the handler to see if the things get logged. --- src/LondonTravel.Skill/AlexaFunction.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LondonTravel.Skill/AlexaFunction.cs b/src/LondonTravel.Skill/AlexaFunction.cs index dbc1c4bf..4d3723c9 100644 --- a/src/LondonTravel.Skill/AlexaFunction.cs +++ b/src/LondonTravel.Skill/AlexaFunction.cs @@ -60,12 +60,12 @@ public virtual async ValueTask DisposeAsync() /// /// A representing the asynchronous operation to get the skill's response. /// - public async Task HandlerAsync(SkillRequest request, ILambdaContext context) + public Task HandlerAsync(SkillRequest request, ILambdaContext context) { Console.WriteLine("HandlerAsync() Start"); EnsureInitialized(); - var result = await OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaWrapper.TraceAsync( + var result = OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaWrapper.TraceAsync( _serviceProvider.GetRequiredService(), HandlerCoreAsync, request, From 908a103a531f9cf47ed7bec80a093cb20d164364 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 12 Sep 2024 12:34:28 +0100 Subject: [PATCH 09/11] Disable logging Disable logging to the console. --- src/LondonTravel.Skill/AlexaFunction.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/LondonTravel.Skill/AlexaFunction.cs b/src/LondonTravel.Skill/AlexaFunction.cs index 4d3723c9..28755af9 100644 --- a/src/LondonTravel.Skill/AlexaFunction.cs +++ b/src/LondonTravel.Skill/AlexaFunction.cs @@ -60,20 +60,14 @@ public virtual async ValueTask DisposeAsync() /// /// A representing the asynchronous operation to get the skill's response. /// - public Task HandlerAsync(SkillRequest request, ILambdaContext context) + public async Task HandlerAsync(SkillRequest request, ILambdaContext context) { - Console.WriteLine("HandlerAsync() Start"); - EnsureInitialized(); - var result = OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaWrapper.TraceAsync( + return await OpenTelemetry.Instrumentation.AWSLambda.AWSLambdaWrapper.TraceAsync( _serviceProvider.GetRequiredService(), HandlerCoreAsync, request, context); - - Console.WriteLine("HandlerAsync() End"); - - return result; } /// @@ -119,7 +113,7 @@ protected virtual void ConfigureServices(IServiceCollection services) services.AddLogging((builder) => { builder.AddConfiguration(configuration.GetSection("Logging")); - builder.AddJsonConsole(); + ////builder.AddJsonConsole(); }); services.AddHttpClients(); From 4aff1d19094ecc36df88e8d09262f022f367db9d Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 12 Sep 2024 18:04:41 +0100 Subject: [PATCH 10/11] Remove debugging changes Remove changes made while debugging hang. --- build.ps1 | 6 +-- src/LondonTravel.Skill/AlexaFunction.cs | 4 +- src/LondonTravel.Skill/AppLambdaSerializer.cs | 43 ------------------- 3 files changed, 4 insertions(+), 49 deletions(-) diff --git a/build.ps1 b/build.ps1 index afe98cc3..79471a3b 100755 --- a/build.ps1 +++ b/build.ps1 @@ -104,12 +104,12 @@ function DotNetPublish { } $testProjects = @( - #(Join-Path $solutionPath "test" "LondonTravel.Skill.Tests" "LondonTravel.Skill.Tests.csproj"), - #(Join-Path $solutionPath "test" "LondonTravel.Skill.EndToEndTests" "LondonTravel.Skill.EndToEndTests.csproj") + (Join-Path $solutionPath "test" "LondonTravel.Skill.Tests" "LondonTravel.Skill.Tests.csproj"), + (Join-Path $solutionPath "test" "LondonTravel.Skill.EndToEndTests" "LondonTravel.Skill.EndToEndTests.csproj") ) $testProjectsForAot = @( - #(Join-Path $solutionPath "test" "LondonTravel.Skill.NativeAotTests" "LondonTravel.Skill.NativeAotTests.csproj") + (Join-Path $solutionPath "test" "LondonTravel.Skill.NativeAotTests" "LondonTravel.Skill.NativeAotTests.csproj") ) $publishProjects = @( diff --git a/src/LondonTravel.Skill/AlexaFunction.cs b/src/LondonTravel.Skill/AlexaFunction.cs index 28755af9..c30a158a 100644 --- a/src/LondonTravel.Skill/AlexaFunction.cs +++ b/src/LondonTravel.Skill/AlexaFunction.cs @@ -79,9 +79,7 @@ public async Task HandlerAsync(SkillRequest request, ILambdaConte [MemberNotNull(nameof(_serviceProvider))] public Task InitializeAsync() { - Console.WriteLine("InitializeAsync() Start"); _serviceProvider ??= CreateServiceProvider(); - Console.WriteLine("InitializeAsync() End"); return Task.FromResult(true); } @@ -113,7 +111,7 @@ protected virtual void ConfigureServices(IServiceCollection services) services.AddLogging((builder) => { builder.AddConfiguration(configuration.GetSection("Logging")); - ////builder.AddJsonConsole(); + builder.AddJsonConsole(); }); services.AddHttpClients(); diff --git a/src/LondonTravel.Skill/AppLambdaSerializer.cs b/src/LondonTravel.Skill/AppLambdaSerializer.cs index 2950deb3..3b43de6f 100644 --- a/src/LondonTravel.Skill/AppLambdaSerializer.cs +++ b/src/LondonTravel.Skill/AppLambdaSerializer.cs @@ -10,47 +10,4 @@ public sealed class AppLambdaSerializer() : SourceGeneratorLambdaJsonSerializer< { protected override JsonSerializerOptions CreateDefaultJsonSerializationOptions() => new(AppJsonSerializerContext.Default.Options); - - protected override T InternalDeserialize(byte[] utf8Json) - { - try - { - Console.WriteLine($"Request: {Convert.ToBase64String(utf8Json)}"); - var result = base.InternalDeserialize(utf8Json); - - Console.WriteLine($"Request: {result.GetType()}"); - - return result; - } - catch (Exception ex) - { - Console.WriteLine(ex); - throw; - } - } - - protected override void InternalSerialize(Utf8JsonWriter writer, T response) - { - try - { - Console.WriteLine($"Response: {response.GetType()}"); - - using (var stream = new MemoryStream()) - { - using var writer2 = new Utf8JsonWriter(stream, WriterOptions); - base.InternalSerialize(writer2, response); - stream.Position = 0L; - Console.WriteLine($"Response: {Convert.ToBase64String(stream.ToArray())}"); - } - - base.InternalSerialize(writer, response); - - Console.WriteLine("Response serialized"); - } - catch (Exception ex) - { - Console.WriteLine(ex); - throw; - } - } } From 6d697abcea190f6d1e2a310cd18796318e41caaa Mon Sep 17 00:00:00 2001 From: costellobot <102549341+costellobot@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:10:59 +0100 Subject: [PATCH 11/11] Update .NET SDK to 9.0.100-rc.2.24463.1 (#1436) * Update .NET SDK Update .NET SDK to version 9.0.100-rc.2.24463.1. --- updated-dependencies: - dependency-name: Microsoft.NET.Sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: costellobot <102549341+costellobot@users.noreply.github.com> * Bump .NET NuGet packages Bumps .NET dependencies to their latest versions for the .NET 9.0.100-rc.2.24463.1 SDK. Bumps Microsoft.AspNetCore.WebUtilities from 9.0.0-rc.2.24461.26 to 9.0.0-rc.2.24462.10. Bumps Microsoft.Extensions.Configuration.Binder from 9.0.0-rc.2.24461.13 to 9.0.0-rc.2.24462.5. Bumps Microsoft.Extensions.Configuration.EnvironmentVariables from 9.0.0-rc.2.24461.13 to 9.0.0-rc.2.24462.5. Bumps Microsoft.Extensions.Configuration.Json from 9.0.0-rc.2.24461.13 to 9.0.0-rc.2.24462.5. Bumps Microsoft.Extensions.DependencyInjection from 9.0.0-rc.2.24461.13 to 9.0.0-rc.2.24462.5. Bumps Microsoft.Extensions.Http from 9.0.0-rc.2.24461.13 to 9.0.0-rc.2.24462.5. Bumps Microsoft.Extensions.Logging.Console from 9.0.0-rc.2.24461.13 to 9.0.0-rc.2.24462.5. Bumps System.Text.Json from 9.0.0-rc.2.24461.13 to 9.0.0-rc.2.24462.5. --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.WebUtilities dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Configuration.Binder dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Configuration.EnvironmentVariables dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Configuration.Json dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.DependencyInjection dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Http dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Logging.Console dependency-type: direct:production update-type: version-update:semver-major - dependency-name: System.Text.Json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: costellobot <102549341+costellobot@users.noreply.github.com> --------- Signed-off-by: costellobot <102549341+costellobot@users.noreply.github.com> --- Directory.Packages.props | 16 ++++++++-------- global.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 6617e2fe..324714b2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,15 +15,15 @@ - - - - - - + + + + + + - + @@ -38,7 +38,7 @@ - + diff --git a/global.json b/global.json index 0d9f414d..7c2687c0 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100-rc.2.24462.3", + "version": "9.0.100-rc.2.24463.1", "allowPrerelease": false, "rollForward": "latestMajor" },