diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8a5afda..c068604 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,6 +1,7 @@
name: Build
on:
+ workflow_dispatch:
push:
branches:
- main
@@ -15,15 +16,15 @@ jobs:
steps:
- name: Check out our repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: true
# Build with .NET 6.0 SDK
- - name: Setup .NET 6.0
+ - name: Setup .NET 8.0
uses: actions/setup-dotnet@v3
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Build
run: |
diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml
index 4ee48a5..be4f97e 100644
--- a/.github/workflows/nuget.yml
+++ b/.github/workflows/nuget.yml
@@ -13,7 +13,7 @@ jobs:
steps:
- name: Check out our repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: true
@@ -21,7 +21,7 @@ jobs:
- name: Setup .NET 6.0
uses: actions/setup-dotnet@v3
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Build
run: |
diff --git a/CloudEvents.sln b/CloudEvents.sln
index 530452a..93bd82a 100644
--- a/CloudEvents.sln
+++ b/CloudEvents.sln
@@ -72,6 +72,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "xml", "xml", "{4012C753-68D
conformance\format\xml\valid-events.xml = conformance\format\xml\valid-events.xml
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpSendJson", "samples\HttpSendJson\HttpSendJson.csproj", "{730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5AD5E051-9A8E-46D9-B0C5-8933718C6D1F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudNative.CloudEvents.MinApiSample", "samples\CloudNative.CloudEvents.MinApiSample\CloudNative.CloudEvents.MinApiSample.csproj", "{1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -238,15 +244,43 @@ Global
{9D82AC2B-0075-4161-AE0E-4A6629C9FF2A}.Release|x64.Build.0 = Release|Any CPU
{9D82AC2B-0075-4161-AE0E-4A6629C9FF2A}.Release|x86.ActiveCfg = Release|Any CPU
{9D82AC2B-0075-4161-AE0E-4A6629C9FF2A}.Release|x86.Build.0 = Release|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Debug|x64.Build.0 = Debug|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Debug|x86.Build.0 = Debug|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Release|x64.ActiveCfg = Release|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Release|x64.Build.0 = Release|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Release|x86.ActiveCfg = Release|Any CPU
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8}.Release|x86.Build.0 = Release|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Debug|x64.Build.0 = Debug|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Debug|x86.Build.0 = Debug|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Release|x64.ActiveCfg = Release|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Release|x64.Build.0 = Release|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Release|x86.ActiveCfg = Release|Any CPU
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
+ {F1B9B769-DB6B-481F-905C-24FE3B12E00E} = {5AD5E051-9A8E-46D9-B0C5-8933718C6D1F}
+ {9760D744-D1BF-40E3-BD6F-7F639BFB9188} = {5AD5E051-9A8E-46D9-B0C5-8933718C6D1F}
{A5906FBA-D73A-4A09-8539-CB10D7B586AE} = {8CCC98B3-1776-49FF-96D6-947A9E5DFB0A}
{D8055631-E6BB-4CD2-8162-F674D6D30E76} = {A5906FBA-D73A-4A09-8539-CB10D7B586AE}
{119AD438-878B-4383-BC9F-779F1605E711} = {A5906FBA-D73A-4A09-8539-CB10D7B586AE}
{4012C753-68DE-4737-936F-F5DBC485C51B} = {A5906FBA-D73A-4A09-8539-CB10D7B586AE}
+ {730D4C5E-DC5B-498C-ADFB-05CB81ECCEC8} = {5AD5E051-9A8E-46D9-B0C5-8933718C6D1F}
+ {1566A665-9FFF-4D87-9C7B-CC06C72C9BFF} = {5AD5E051-9A8E-46D9-B0C5-8933718C6D1F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F77A454C-CC17-4AD6-823A-64E1A94FDA0A}
diff --git a/samples/CloudNative.CloudEvents.MinApiSample/CloudNative.CloudEvents.MinApiSample.csproj b/samples/CloudNative.CloudEvents.MinApiSample/CloudNative.CloudEvents.MinApiSample.csproj
new file mode 100644
index 0000000..5e20f7b
--- /dev/null
+++ b/samples/CloudNative.CloudEvents.MinApiSample/CloudNative.CloudEvents.MinApiSample.csproj
@@ -0,0 +1,18 @@
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+ true
+ true
+ None
+ False
+
+
diff --git a/samples/CloudNative.CloudEvents.MinApiSample/Program.cs b/samples/CloudNative.CloudEvents.MinApiSample/Program.cs
new file mode 100644
index 0000000..6f142a6
--- /dev/null
+++ b/samples/CloudNative.CloudEvents.MinApiSample/Program.cs
@@ -0,0 +1,85 @@
+// Copyright (c) Cloud Native Foundation.
+// Licensed under the Apache 2.0 license.
+// See LICENSE file in the project root for full license information.
+
+using CloudNative.CloudEvents;
+using CloudNative.CloudEvents.Http;
+using CloudNative.CloudEvents.SystemTextJson;
+using CloudNative.CloudEvents.AspNetCore;
+using System.Text.Json.Serialization;
+using System.Text.Json;
+using System.Text;
+
+var builder = WebApplication.CreateBuilder(args);
+var app = builder.Build();
+var formatter = new JsonEventFormatter(MyJsonContext.Default);
+
+app.MapPost("/api/events/receive/", async (HttpRequest request) =>
+{
+ var cloudEvent = await request.ToCloudEventAsync(formatter);
+ using var ms = new MemoryStream();
+ using var writer = new Utf8JsonWriter(ms, new() { Indented = true });
+ writer.WriteStartObject();
+ foreach (var (attribute, value) in cloudEvent.GetPopulatedAttributes())
+ writer.WriteString(attribute.Name, attribute.Format(value));
+ writer.WriteEndObject();
+ await writer.FlushAsync();
+ var attributeMap = Encoding.UTF8.GetString(ms.ToArray());
+ return Results.Text($"Received event with ID {cloudEvent.Id}, attributes: {attributeMap}");
+});
+
+app.MapPost("/api/events/receive2/", (Event e) => Results.Json(e.CloudEvent.Data, MyJsonContext.Default));
+
+app.MapPost("/api/events/receive3/", (Message message) => Results.Json(message, MyJsonContext.Default));
+
+app.MapGet("/api/events/generate/", () =>
+{
+ var evt = new CloudEvent
+ {
+ Type = "CloudNative.CloudEvents.MinApiSample",
+ Source = new Uri("https://github.com/cloudevents/sdk-csharp"),
+ Time = DateTimeOffset.Now,
+ DataContentType = "application/json",
+ Id = Guid.NewGuid().ToString(),
+ Data = new Message("C#", Environment.Version.ToString())
+ };
+ // Format the event as the body of the response. This is UTF-8 JSON because of
+ // the CloudEventFormatter we're using, but EncodeStructuredModeMessage always
+ // returns binary data. We could return the data directly, but for debugging
+ // purposes it's useful to have the JSON string.
+ var bytes = formatter.EncodeStructuredModeMessage(evt, out var contentType);
+ string json = Encoding.UTF8.GetString(bytes.Span);
+ // Specify the content type of the response: this is what makes it a CloudEvent.
+ // (In "binary mode", the content type is the content type of the data, and headers
+ // indicate that it's a CloudEvent.)
+ return Results.Content(json, contentType.MediaType, Encoding.UTF8);
+});
+
+app.Run();
+
+[JsonSerializable(typeof(Message))]
+internal partial class MyJsonContext : JsonSerializerContext { }
+
+public class Event
+{
+ private readonly static JsonEventFormatter formatter = new JsonEventFormatter(MyJsonContext.Default);
+ // required for receive2
+ public static async ValueTask BindAsync(HttpContext context)
+ {
+ var cloudEvent = await context.Request.ToCloudEventAsync(formatter);
+ return new Event { CloudEvent = cloudEvent };
+ }
+ public required CloudEvent CloudEvent { get; init; }
+}
+
+record class Message(string Language, string EnvironmentVersion)
+{
+ private readonly static JsonEventFormatter formatter = new JsonEventFormatter(MyJsonContext.Default);
+ // required for receive3
+ public static async ValueTask BindAsync(HttpContext context)
+ {
+ var cloudEvent = await context.Request.ToCloudEventAsync(formatter);
+ return cloudEvent.Data is Message message ? message : null;
+ }
+}
+
diff --git a/samples/CloudNative.CloudEvents.MinApiSample/Properties/launchSettings.json b/samples/CloudNative.CloudEvents.MinApiSample/Properties/launchSettings.json
new file mode 100644
index 0000000..c202106
--- /dev/null
+++ b/samples/CloudNative.CloudEvents.MinApiSample/Properties/launchSettings.json
@@ -0,0 +1,14 @@
+{
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "api/events/generate",
+ "applicationUrl": "http://localhost:5002",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/samples/CloudNative.CloudEvents.MinApiSample/appsettings.Development.json b/samples/CloudNative.CloudEvents.MinApiSample/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/samples/CloudNative.CloudEvents.MinApiSample/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/samples/CloudNative.CloudEvents.MinApiSample/appsettings.json b/samples/CloudNative.CloudEvents.MinApiSample/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/samples/CloudNative.CloudEvents.MinApiSample/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props
index b688048..deb85b9 100644
--- a/samples/Directory.Build.props
+++ b/samples/Directory.Build.props
@@ -14,5 +14,6 @@
False
+ 12.0
diff --git a/samples/HttpSendJson/HttpSendJson.csproj b/samples/HttpSendJson/HttpSendJson.csproj
new file mode 100644
index 0000000..39f79b1
--- /dev/null
+++ b/samples/HttpSendJson/HttpSendJson.csproj
@@ -0,0 +1,19 @@
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+ true
+ true
+ None
+ False
+
+
diff --git a/samples/HttpSendJson/Program.cs b/samples/HttpSendJson/Program.cs
new file mode 100644
index 0000000..2715286
--- /dev/null
+++ b/samples/HttpSendJson/Program.cs
@@ -0,0 +1,70 @@
+// Copyright (c) Cloud Native Foundation.
+// Licensed under the Apache 2.0 license.
+// See LICENSE file in the project root for full license information.
+
+using CloudNative.CloudEvents;
+using CloudNative.CloudEvents.Http;
+using CloudNative.CloudEvents.SystemTextJson;
+using DocoptNet;
+using System.Net.Mime;
+using static System.Console;
+
+// This application uses the docopt.net library for parsing the command
+// line and calling the application code.
+ProgramArguments programArguments = new();
+var result = await ProgramArguments.CreateParserWithVersion()
+.Parse(args)
+.Match(RunAsync,
+ result => { WriteLine(result.Help); return Task.FromResult(1); },
+ result => { WriteLine(result.Version); return Task.FromResult(0); },
+ result => { Error.WriteLine(result.Usage); return Task.FromResult(1); });
+return result;
+
+static async Task RunAsync(ProgramArguments args)
+{
+ var cloudEvent = new CloudEvent
+ {
+ Id = Guid.NewGuid().ToString(),
+ Type = args.OptType,
+ Source = new Uri(args.OptSource),
+ DataContentType = MediaTypeNames.Application.Json,
+ Data = System.Text.Json.JsonSerializer.Serialize("hey there!", GeneratedJsonContext.Default.String)
+ };
+
+ var content = cloudEvent.ToHttpContent(ContentMode.Structured, new JsonEventFormatter(GeneratedJsonContext.Default));
+
+ var httpClient = new HttpClient();
+ // Your application remains in charge of adding any further headers or
+ // other information required to authenticate/authorize or otherwise
+ // dispatch the call at the server.
+ var result = await httpClient.PostAsync(args.OptUrl, content);
+
+ WriteLine(result.StatusCode);
+ return 0;
+}
+
+[System.Text.Json.Serialization.JsonSerializable(typeof(string))]
+internal partial class GeneratedJsonContext : System.Text.Json.Serialization.JsonSerializerContext
+{
+}
+
+[DocoptArguments]
+partial class ProgramArguments
+{
+ const string Help = @"HttpSendJson.
+
+ Usage:
+ HttpSendJson --url=URL [--type=TYPE] [--source=SOURCE]
+ HttpSendJson (-h | --help)
+ HttpSendJson --version
+
+ Options:
+ --url=URL HTTP(S) address to send the event to.
+ --type=TYPE CloudEvents 'type' [default: com.example.myevent].
+ --source=SOURCE CloudEvents 'source' [default: urn:example-com:mysource:abc].
+ -h --help Show this screen.
+ --version Show version.
+";
+ public static string Version => $"producer {typeof(ProgramArguments).Assembly.GetName().Version}";
+ public static IParser CreateParserWithVersion() => CreateParser().WithVersion(Version);
+}
\ No newline at end of file
diff --git a/src/CloudNative.CloudEvents.Amqp/AmqpExtensions.cs b/src/CloudNative.CloudEvents.Amqp/AmqpExtensions.cs
index 001b832..6515320 100644
--- a/src/CloudNative.CloudEvents.Amqp/AmqpExtensions.cs
+++ b/src/CloudNative.CloudEvents.Amqp/AmqpExtensions.cs
@@ -8,6 +8,7 @@
using CloudNative.CloudEvents.Core;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net.Mime;
@@ -145,7 +146,7 @@ public static CloudEvent ToCloudEvent(
}
}
- private static bool HasCloudEventsContentType(Message message, out string? contentType)
+ private static bool HasCloudEventsContentType(Message message, [NotNullWhen(true)] out string? contentType)
{
contentType = message.Properties.ContentType?.ToString();
return MimeUtilities.IsCloudEventsContentType(contentType);
@@ -249,4 +250,23 @@ private static ApplicationProperties MapHeaders(CloudEvent cloudEvent, string pr
return applicationProperties;
}
}
-}
\ No newline at end of file
+}
+
+#if NETSTANDARD2_0
+namespace System.Diagnostics.CodeAnalysis
+{
+ /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it.
+ [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+ internal sealed class NotNullWhenAttribute : Attribute
+ {
+ /// Initializes the attribute with the specified return value condition.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter will not be null.
+ ///
+ public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/CloudNative.CloudEvents.Amqp/CloudNative.CloudEvents.Amqp.csproj b/src/CloudNative.CloudEvents.Amqp/CloudNative.CloudEvents.Amqp.csproj
index a0506ec..6e499ee 100644
--- a/src/CloudNative.CloudEvents.Amqp/CloudNative.CloudEvents.Amqp.csproj
+++ b/src/CloudNative.CloudEvents.Amqp/CloudNative.CloudEvents.Amqp.csproj
@@ -1,9 +1,8 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
AMQP extensions for CloudNative.CloudEvents
- 8.0
enable
cncf;cloudnative;cloudevents;events;amqp
diff --git a/src/CloudNative.CloudEvents.AspNetCore/CloudNative.CloudEvents.AspNetCore.csproj b/src/CloudNative.CloudEvents.AspNetCore/CloudNative.CloudEvents.AspNetCore.csproj
index b073a81..eb74f91 100644
--- a/src/CloudNative.CloudEvents.AspNetCore/CloudNative.CloudEvents.AspNetCore.csproj
+++ b/src/CloudNative.CloudEvents.AspNetCore/CloudNative.CloudEvents.AspNetCore.csproj
@@ -1,9 +1,8 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
ASP.Net Core extensions for CloudNative.CloudEvents
- 8.0
enable
cncf;cloudnative;cloudevents;events;aspnetcore;aspnet
diff --git a/src/CloudNative.CloudEvents.Avro/AvroEventFormatter.cs b/src/CloudNative.CloudEvents.Avro/AvroEventFormatter.cs
index 47ded29..27f6bf0 100644
--- a/src/CloudNative.CloudEvents.Avro/AvroEventFormatter.cs
+++ b/src/CloudNative.CloudEvents.Avro/AvroEventFormatter.cs
@@ -185,7 +185,7 @@ private static RecordSchema ParseEmbeddedSchema()
// will fail and that's okay since the type is useless without the proper schema.
using var sr = new StreamReader(typeof(AvroEventFormatter)
.Assembly
- .GetManifestResourceStream("CloudNative.CloudEvents.Avro.AvroSchema.json"));
+ .GetManifestResourceStream("CloudNative.CloudEvents.Avro.AvroSchema.json")!);
return (RecordSchema) Schema.Parse(sr.ReadToEnd());
}
diff --git a/src/CloudNative.CloudEvents.Avro/CloudNative.CloudEvents.Avro.csproj b/src/CloudNative.CloudEvents.Avro/CloudNative.CloudEvents.Avro.csproj
index 3f0fb6e..bcab240 100644
--- a/src/CloudNative.CloudEvents.Avro/CloudNative.CloudEvents.Avro.csproj
+++ b/src/CloudNative.CloudEvents.Avro/CloudNative.CloudEvents.Avro.csproj
@@ -1,10 +1,9 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
Avro extensions for CloudNative.CloudEvents
cncf;cloudnative;cloudevents;events;avro
- 10.0
enable
diff --git a/src/CloudNative.CloudEvents.Kafka/CloudNative.CloudEvents.Kafka.csproj b/src/CloudNative.CloudEvents.Kafka/CloudNative.CloudEvents.Kafka.csproj
index 9926330..d091a60 100644
--- a/src/CloudNative.CloudEvents.Kafka/CloudNative.CloudEvents.Kafka.csproj
+++ b/src/CloudNative.CloudEvents.Kafka/CloudNative.CloudEvents.Kafka.csproj
@@ -1,10 +1,9 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
Kafka extensions for CloudNative.CloudEvents
cncf;cloudnative;cloudevents;events;kafka
- 8.0
enable
diff --git a/src/CloudNative.CloudEvents.Mqtt/CloudNative.CloudEvents.Mqtt.csproj b/src/CloudNative.CloudEvents.Mqtt/CloudNative.CloudEvents.Mqtt.csproj
index 58f622e..1cae6ed 100644
--- a/src/CloudNative.CloudEvents.Mqtt/CloudNative.CloudEvents.Mqtt.csproj
+++ b/src/CloudNative.CloudEvents.Mqtt/CloudNative.CloudEvents.Mqtt.csproj
@@ -1,10 +1,9 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
MQTT extensions for CloudNative.CloudEvents
cncf;cloudnative;cloudevents;events;mqtt
- 8.0
enable
diff --git a/src/CloudNative.CloudEvents.NewtonsoftJson/CloudNative.CloudEvents.NewtonsoftJson.csproj b/src/CloudNative.CloudEvents.NewtonsoftJson/CloudNative.CloudEvents.NewtonsoftJson.csproj
index 3ee42e3..0d178d8 100644
--- a/src/CloudNative.CloudEvents.NewtonsoftJson/CloudNative.CloudEvents.NewtonsoftJson.csproj
+++ b/src/CloudNative.CloudEvents.NewtonsoftJson/CloudNative.CloudEvents.NewtonsoftJson.csproj
@@ -1,9 +1,8 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
JSON support for the CNCF CloudEvents SDK, based on Newtonsoft.Json.
- 8.0
enable
cncf;cloudnative;cloudevents;events;json;newtonsoft
diff --git a/src/CloudNative.CloudEvents.NewtonsoftJson/JsonEventFormatter.cs b/src/CloudNative.CloudEvents.NewtonsoftJson/JsonEventFormatter.cs
index 2d21be4..191ace4 100644
--- a/src/CloudNative.CloudEvents.NewtonsoftJson/JsonEventFormatter.cs
+++ b/src/CloudNative.CloudEvents.NewtonsoftJson/JsonEventFormatter.cs
@@ -345,7 +345,9 @@ protected virtual void DecodeStructuredModeDataBase64Property(JToken dataBase64T
{
throw new ArgumentException($"Structured mode property '{DataBase64PropertyName}' must be a string, when present.");
}
- cloudEvent.Data = Convert.FromBase64String((string?)dataBase64Token);
+ var tokenString = (string?)dataBase64Token;
+ if (tokenString != null)
+ cloudEvent.Data = Convert.FromBase64String(tokenString);
}
///
@@ -524,7 +526,7 @@ protected virtual void EncodeStructuredModeData(CloudEvent cloudEvent, JsonWrite
}
else
{
- ContentType dataContentType = new ContentType(GetOrInferDataContentType(cloudEvent));
+ ContentType dataContentType = new ContentType(GetOrInferDataContentType(cloudEvent)!);
if (IsJsonMediaType(dataContentType.MediaType))
{
writer.WritePropertyName(DataPropertyName);
@@ -696,7 +698,7 @@ public override void DecodeBinaryModeEventData(ReadOnlyMemory body, CloudE
///
protected override void EncodeStructuredModeData(CloudEvent cloudEvent, JsonWriter writer)
{
- T data = (T)cloudEvent.Data;
+ var data = (T?)cloudEvent.Data;
writer.WritePropertyName(DataPropertyName);
Serializer.Serialize(writer, data);
}
diff --git a/src/CloudNative.CloudEvents.Protobuf/CloudNative.CloudEvents.Protobuf.csproj b/src/CloudNative.CloudEvents.Protobuf/CloudNative.CloudEvents.Protobuf.csproj
index c21c60e..628f82c 100644
--- a/src/CloudNative.CloudEvents.Protobuf/CloudNative.CloudEvents.Protobuf.csproj
+++ b/src/CloudNative.CloudEvents.Protobuf/CloudNative.CloudEvents.Protobuf.csproj
@@ -1,10 +1,9 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
Support for the Protobuf event format in for CloudNative.CloudEvents
cncf;cloudnative;cloudevents;events;protobuf
- 10.0
enable
diff --git a/src/CloudNative.CloudEvents.SystemTextJson/CloudNative.CloudEvents.SystemTextJson.csproj b/src/CloudNative.CloudEvents.SystemTextJson/CloudNative.CloudEvents.SystemTextJson.csproj
index d5c0916..81c21b9 100644
--- a/src/CloudNative.CloudEvents.SystemTextJson/CloudNative.CloudEvents.SystemTextJson.csproj
+++ b/src/CloudNative.CloudEvents.SystemTextJson/CloudNative.CloudEvents.SystemTextJson.csproj
@@ -1,9 +1,8 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
JSON support for the CNCF CloudEvents SDK, based on System.Text.Json.
- 8.0
cncf;cloudnative;cloudevents;events;json;systemtextjson
enable
diff --git a/src/CloudNative.CloudEvents.SystemTextJson/JsonEventFormatter.cs b/src/CloudNative.CloudEvents.SystemTextJson/JsonEventFormatter.cs
index decdb77..46daab1 100644
--- a/src/CloudNative.CloudEvents.SystemTextJson/JsonEventFormatter.cs
+++ b/src/CloudNative.CloudEvents.SystemTextJson/JsonEventFormatter.cs
@@ -5,10 +5,12 @@
using CloudNative.CloudEvents.Core;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
+using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Xml.Linq;
@@ -94,6 +96,13 @@ public class JsonEventFormatter : CloudEventFormatter
///
protected const string DataPropertyName = "data";
+#if NET7_0_OR_GREATER
+ ///
+ /// Json serialization context used to serialize and enable trimming and AOT.
+ ///
+ protected readonly JsonSerializerContext? JsonSerializerContext;
+#endif
+
///
/// The options to use when serializing objects to JSON.
///
@@ -108,22 +117,54 @@ public class JsonEventFormatter : CloudEventFormatter
/// Creates a JsonEventFormatter that uses the default
/// and for serializing and parsing.
///
+#if NET7_0_OR_GREATER
+ [RequiresUnreferencedCode("Use a constructor that takes a JsonSerializerContext.")]
+#endif
public JsonEventFormatter() : this(null, default)
{
}
+#if NET7_0_OR_GREATER
+ ///
+ /// Creates a JsonEventFormatter that uses the default
+ /// and for serializing and parsing.
+ ///
+ /// The json context used for serializing objects to JSON.
+ public JsonEventFormatter(JsonSerializerContext jsonSerializerContext) : this(default, jsonSerializerContext)
+ {
+ }
+#endif
+
///
/// Creates a JsonEventFormatter that uses the specified
/// and for serializing and parsing.
///
/// The options to use when serializing objects to JSON. May be null.
/// The options to use when parsing JSON documents.
+#if NET7_0_OR_GREATER
+ [RequiresUnreferencedCode("Use a constructor that takes a JsonSerializerContext.")]
+#endif
public JsonEventFormatter(JsonSerializerOptions? serializerOptions, JsonDocumentOptions documentOptions)
{
SerializerOptions = serializerOptions;
DocumentOptions = documentOptions;
}
+#if NET7_0_OR_GREATER
+ ///
+ /// Creates a JsonEventFormatter that uses the specified
+ /// and for serializing and parsing.
+ ///
+ /// The options to use when parsing JSON documents.
+ /// The json context used for serializing objects to JSON.
+ public JsonEventFormatter(JsonDocumentOptions documentOptions, JsonSerializerContext jsonSerializerContext)
+ {
+ Validation.CheckNotNull(jsonSerializerContext, nameof(jsonSerializerContext));
+ DocumentOptions = documentOptions;
+ JsonSerializerContext = jsonSerializerContext;
+ }
+#endif
+
///
public override async Task DecodeStructuredModeMessageAsync(Stream body, ContentType? contentType, IEnumerable? extensionAttributes) =>
await DecodeStructuredModeMessageImpl(body, contentType, extensionAttributes, true).ConfigureAwait(false);
@@ -533,6 +574,10 @@ private void WriteCloudEventForBatchOrStructuredMode(Utf8JsonWriter writer, Clou
/// The CloudEvent being encoded, which will have a non-null value for
/// its property.
/// The writer to serialize the data to. Will not be null.
+#if NET7_0_OR_GREATER
+ [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Constructor already annotated.")]
+ [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Constructor already annotated.")]
+#endif
protected virtual void EncodeStructuredModeData(CloudEvent cloudEvent, Utf8JsonWriter writer)
{
// Binary data is encoded using the data_base64 property, regardless of content type.
@@ -548,7 +593,12 @@ protected virtual void EncodeStructuredModeData(CloudEvent cloudEvent, Utf8JsonW
if (IsJsonMediaType(dataContentType.MediaType))
{
writer.WritePropertyName(DataPropertyName);
- JsonSerializer.Serialize(writer, cloudEvent.Data, SerializerOptions);
+#if NET7_0_OR_GREATER
+ if (JsonSerializerContext != null)
+ JsonSerializer.Serialize(writer, cloudEvent.Data, cloudEvent.Data!.GetType(), JsonSerializerContext);
+ else
+#endif
+ JsonSerializer.Serialize(writer, cloudEvent.Data, SerializerOptions);
}
else if (cloudEvent.Data is string text && dataContentType.MediaType.StartsWith("text/"))
{
@@ -564,6 +614,10 @@ protected virtual void EncodeStructuredModeData(CloudEvent cloudEvent, Utf8JsonW
}
///
+#if NET7_0_OR_GREATER
+ [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Constructor already annotated.")]
+ [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Constructor already annotated.")]
+#endif
public override ReadOnlyMemory EncodeBinaryModeEventData(CloudEvent cloudEvent)
{
Validation.CheckCloudEventArgument(cloudEvent, nameof(cloudEvent));
@@ -584,10 +638,18 @@ public override ReadOnlyMemory EncodeBinaryModeEventData(CloudEvent cloudE
var encoding = MimeUtilities.GetEncoding(contentType);
if (encoding is UTF8Encoding)
{
+#if NET7_0_OR_GREATER
+ if (JsonSerializerContext != null)
+ return JsonSerializer.SerializeToUtf8Bytes(cloudEvent.Data, cloudEvent.Data.GetType(), JsonSerializerContext);
+#endif
return JsonSerializer.SerializeToUtf8Bytes(cloudEvent.Data, SerializerOptions);
}
else
{
+#if NET7_0_OR_GREATER
+ if (JsonSerializerContext != null)
+ return MimeUtilities.GetEncoding(contentType).GetBytes(JsonSerializer.Serialize(cloudEvent.Data, cloudEvent.Data.GetType(), JsonSerializerContext));
+#endif
return MimeUtilities.GetEncoding(contentType).GetBytes(JsonSerializer.Serialize(cloudEvent.Data, SerializerOptions));
}
}
@@ -654,22 +716,57 @@ public class JsonEventFormatter : JsonEventFormatter
/// Creates a JsonEventFormatter that uses the default
/// and for serializing and parsing.
///
+#if NET7_0_OR_GREATER
+ [RequiresUnreferencedCode("Use a constructor that takes a JsonSerializerContext.")]
+#endif
public JsonEventFormatter()
{
}
+#if NET7_0_OR_GREATER
+ ///
+ /// Creates a JsonEventFormatter that uses the serializer
+ /// and for serializing and parsing.
+ ///
+ /// The json context used for serializing objects to JSON.
+ public JsonEventFormatter(JsonSerializerContext jsonSerializerContext)
+ : base(default, jsonSerializerContext)
+ {
+ }
+#endif
+
///
/// Creates a JsonEventFormatter that uses the serializer
/// and for serializing and parsing.
///
/// The options to use when serializing and parsing. May be null.
/// The options to use when parsing JSON documents.
+#if NET7_0_OR_GREATER
+ [RequiresUnreferencedCode("Use a constructor that takes a JsonSerializerContext.")]
+#endif
public JsonEventFormatter(JsonSerializerOptions serializerOptions, JsonDocumentOptions documentOptions)
: base(serializerOptions, documentOptions)
{
}
+#if NET7_0_OR_GREATER
+ ///
+ /// Creates a JsonEventFormatter that uses the serializer
+ /// and for serializing and parsing.
+ ///
+ /// The options to use when parsing JSON documents.
+ /// The json context used for serializing objects to JSON.
+ public JsonEventFormatter(JsonDocumentOptions documentOptions, JsonSerializerContext jsonSerializerContext)
+ : base(documentOptions, jsonSerializerContext)
+ {
+ }
+#endif
+
///
+#if NET7_0_OR_GREATER
+ [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Constructor already annotated.")]
+ [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Constructor already annotated.")]
+#endif
public override ReadOnlyMemory EncodeBinaryModeEventData(CloudEvent cloudEvent)
{
Validation.CheckCloudEventArgument(cloudEvent, nameof(cloudEvent));
@@ -679,10 +776,18 @@ public override ReadOnlyMemory EncodeBinaryModeEventData(CloudEvent cloudE
return Array.Empty();
}
T data = (T)cloudEvent.Data;
+#if NET7_0_OR_GREATER
+ if (JsonSerializerContext != null)
+ return JsonSerializer.SerializeToUtf8Bytes(data, data.GetType(), JsonSerializerContext);
+#endif
return JsonSerializer.SerializeToUtf8Bytes(data, SerializerOptions);
}
///
+#if NET7_0_OR_GREATER
+ [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Constructor already annotated.")]
+ [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Constructor already annotated.")]
+#endif
public override void DecodeBinaryModeEventData(ReadOnlyMemory body, CloudEvent cloudEvent)
{
Validation.CheckNotNull(cloudEvent, nameof(cloudEvent));
@@ -692,22 +797,45 @@ public override void DecodeBinaryModeEventData(ReadOnlyMemory body, CloudE
cloudEvent.Data = null;
return;
}
- cloudEvent.Data = JsonSerializer.Deserialize(body.Span, SerializerOptions);
+#if NET7_0_OR_GREATER
+ if (JsonSerializerContext != null)
+ cloudEvent.Data = JsonSerializer.Deserialize(body.Span, typeof(T), JsonSerializerContext);
+ else
+#endif
+ cloudEvent.Data = JsonSerializer.Deserialize(body.Span, SerializerOptions);
}
///
+#if NET7_0_OR_GREATER
+ [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Constructor already annotated.")]
+ [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Constructor already annotated.")]
+#endif
protected override void EncodeStructuredModeData(CloudEvent cloudEvent, Utf8JsonWriter writer)
{
- T data = (T)cloudEvent.Data;
+ var data = (T?)cloudEvent.Data;
writer.WritePropertyName(DataPropertyName);
- JsonSerializer.Serialize(writer, data, SerializerOptions);
+#if NET7_0_OR_GREATER
+ if (JsonSerializerContext != null)
+ JsonSerializer.Serialize(writer, data, data!.GetType(), JsonSerializerContext);
+ else
+#endif
+ JsonSerializer.Serialize(writer, data, SerializerOptions);
}
///
- protected override void DecodeStructuredModeDataProperty(JsonElement dataElement, CloudEvent cloudEvent) =>
- // Note: this is an inefficient way of doing this.
- // See https://github.com/dotnet/runtime/issues/31274 - when that's implemented, we can use the new method here.
- cloudEvent.Data = JsonSerializer.Deserialize(dataElement.GetRawText(), SerializerOptions);
+#if NET7_0_OR_GREATER
+ [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Constructor already annotated.")]
+ [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Constructor already annotated.")]
+#endif
+ protected override void DecodeStructuredModeDataProperty(JsonElement dataElement, CloudEvent cloudEvent)
+ {
+#if NET7_0_OR_GREATER
+ if (JsonSerializerContext != null)
+ cloudEvent.Data = JsonSerializer.Deserialize(dataElement, typeof(T), JsonSerializerContext);
+ else
+#endif
+ cloudEvent.Data = JsonSerializer.Deserialize(dataElement.GetRawText(), SerializerOptions);
+ }
// TODO: Consider decoding the base64 data as a byte array, then using DecodeBinaryModeData.
///
diff --git a/src/CloudNative.CloudEvents/CloudEventFormatterAttribute.cs b/src/CloudNative.CloudEvents/CloudEventFormatterAttribute.cs
index 74f30d7..757c207 100644
--- a/src/CloudNative.CloudEvents/CloudEventFormatterAttribute.cs
+++ b/src/CloudNative.CloudEvents/CloudEventFormatterAttribute.cs
@@ -4,6 +4,7 @@
using CloudNative.CloudEvents.Core;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
namespace CloudNative.CloudEvents
@@ -21,6 +22,9 @@ public sealed class CloudEventFormatterAttribute : Attribute
///
/// The type to use for CloudEvent formatting. Must not be null.
///
+#if NET7_0_OR_GREATER
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
+#endif
public Type FormatterType { get; }
///
@@ -56,7 +60,7 @@ public CloudEventFormatterAttribute(Type formatterType) =>
throw new ArgumentException($"The {nameof(CloudEventFormatterAttribute)} on type {targetType} has no converter type specified.", nameof(targetType));
}
- object instance;
+ object? instance;
try
{
instance = Activator.CreateInstance(formatterType);
@@ -73,6 +77,6 @@ public CloudEventFormatterAttribute(Type formatterType) =>
}
return formatter;
- }
+ }
}
}
\ No newline at end of file
diff --git a/src/CloudNative.CloudEvents/CloudNative.CloudEvents.csproj b/src/CloudNative.CloudEvents/CloudNative.CloudEvents.csproj
index 3561218..50c8649 100644
--- a/src/CloudNative.CloudEvents/CloudNative.CloudEvents.csproj
+++ b/src/CloudNative.CloudEvents/CloudNative.CloudEvents.csproj
@@ -1,9 +1,8 @@
- netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1;net7.0;net8.0
CNCF CloudEvents SDK
- latest
enable
cloudnative;cloudevents;events
diff --git a/src/CloudNative.CloudEvents/Core/BinaryDataUtilities.cs b/src/CloudNative.CloudEvents/Core/BinaryDataUtilities.cs
index 3f951f0..2323fde 100644
--- a/src/CloudNative.CloudEvents/Core/BinaryDataUtilities.cs
+++ b/src/CloudNative.CloudEvents/Core/BinaryDataUtilities.cs
@@ -32,7 +32,7 @@ public async static Task> ToReadOnlyMemoryAsync(Stream stre
// It's safe to use memory.GetBuffer() and memory.Position here, as this is a stream
// we've created using the parameterless constructor.
var buffer = memory.GetBuffer();
- return new ReadOnlyMemory(buffer, 0, (int) memory.Position);
+ return new ReadOnlyMemory(buffer, 0, (int)memory.Position);
}
///
@@ -65,7 +65,7 @@ public static ReadOnlyMemory ToReadOnlyMemory(Stream stream)
public static MemoryStream AsStream(ReadOnlyMemory memory)
{
var segment = GetArraySegment(memory);
- return new MemoryStream(segment.Array, segment.Offset, segment.Count, false);
+ return new MemoryStream(segment.Array!, segment.Offset, segment.Count, false);
}
///
@@ -79,7 +79,7 @@ public static string GetString(ReadOnlyMemory memory, Encoding encoding)
// TODO: If we introduce an additional netstandard2.1 target, we can use encoding.GetString(memory.Span)
var segment = GetArraySegment(memory);
- return encoding.GetString(segment.Array, segment.Offset, segment.Count);
+ return encoding.GetString(segment.Array!, segment.Offset, segment.Count);
}
///
@@ -92,7 +92,7 @@ public static async Task CopyToStreamAsync(ReadOnlyMemory source, Stream d
{
Validation.CheckNotNull(destination, nameof(destination));
var segment = GetArraySegment(source);
- await destination.WriteAsync(segment.Array, segment.Offset, segment.Count).ConfigureAwait(false);
+ await destination.WriteAsync(segment.Array!, segment.Offset, segment.Count).ConfigureAwait(false);
}
///
@@ -108,7 +108,7 @@ public static byte[] AsArray(ReadOnlyMemory memory)
var segment = GetArraySegment(memory);
// We probably don't actually need to check the offset: if the count is the same as the length,
// I can't see how the offset can be non-zero. But it doesn't *hurt* as a check.
- return segment.Offset == 0 && segment.Count == segment.Array.Length
+ return segment.Array is not null && segment.Offset == 0 && segment.Count == segment.Array.Length
? segment.Array
: memory.ToArray();
}
diff --git a/src/CloudNative.CloudEvents/Core/MimeUtilities.cs b/src/CloudNative.CloudEvents/Core/MimeUtilities.cs
index b660086..09ddc36 100644
--- a/src/CloudNative.CloudEvents/Core/MimeUtilities.cs
+++ b/src/CloudNative.CloudEvents/Core/MimeUtilities.cs
@@ -3,6 +3,7 @@
// See LICENSE file in the project root for full license information.
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
@@ -57,7 +58,7 @@ public static Encoding GetEncoding(ContentType? contentType) =>
var header = new MediaTypeHeaderValue(contentType.MediaType);
foreach (string parameterName in contentType.Parameters.Keys)
{
- header.Parameters.Add(new NameValueHeaderValue(parameterName, contentType.Parameters[parameterName].ToString()));
+ header.Parameters.Add(new NameValueHeaderValue(parameterName, contentType.Parameters[parameterName]!.ToString()));
}
return header;
}
@@ -76,7 +77,7 @@ public static Encoding GetEncoding(ContentType? contentType) =>
///
/// The content type to check. May be null, in which case the result is false.
/// true if the given content type denotes a (non-batch) CloudEvent; false otherwise
- public static bool IsCloudEventsContentType(string? contentType) =>
+ public static bool IsCloudEventsContentType([NotNullWhen(true)] string? contentType) =>
contentType is string &&
contentType.StartsWith(MediaType, StringComparison.InvariantCultureIgnoreCase) &&
!contentType.StartsWith(BatchMediaType, StringComparison.InvariantCultureIgnoreCase);
@@ -86,7 +87,7 @@ contentType is string &&
///
/// The content type to check. May be null, in which case the result is false.
/// true if the given content type represents a CloudEvent batch; false otherwise
- public static bool IsCloudEventsBatchContentType(string? contentType) =>
+ public static bool IsCloudEventsBatchContentType([NotNullWhen(true)] string? contentType) =>
contentType is string && contentType.StartsWith(BatchMediaType, StringComparison.InvariantCultureIgnoreCase);
}
}
diff --git a/src/CloudNative.CloudEvents/Http/HttpClientExtensions.cs b/src/CloudNative.CloudEvents/Http/HttpClientExtensions.cs
index c1965d7..cf92ccb 100644
--- a/src/CloudNative.CloudEvents/Http/HttpClientExtensions.cs
+++ b/src/CloudNative.CloudEvents/Http/HttpClientExtensions.cs
@@ -5,6 +5,7 @@
using CloudNative.CloudEvents.Core;
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
@@ -60,6 +61,7 @@ public static bool IsCloudEventBatch(this HttpRequestMessage httpRequestMessage)
Validation.CheckNotNull(httpRequestMessage, nameof(httpRequestMessage));
return HasCloudEventsBatchContentType(httpRequestMessage.Content);
}
+
///
/// Indicates whether this holds a batch of CloudEvents.
@@ -83,7 +85,7 @@ public static Task ToCloudEventAsync(
this HttpResponseMessage httpResponseMessage,
CloudEventFormatter formatter,
params CloudEventAttribute[]? extensionAttributes) =>
- ToCloudEventAsync(httpResponseMessage, formatter, (IEnumerable?) extensionAttributes);
+ ToCloudEventAsync(httpResponseMessage, formatter, (IEnumerable?)extensionAttributes);
///
/// Converts this HTTP response message into a CloudEvent object
@@ -112,7 +114,7 @@ public static Task ToCloudEventAsync(
this HttpRequestMessage httpRequestMessage,
CloudEventFormatter formatter,
params CloudEventAttribute[]? extensionAttributes) =>
- ToCloudEventAsync(httpRequestMessage, formatter, (IEnumerable?) extensionAttributes);
+ ToCloudEventAsync(httpRequestMessage, formatter, (IEnumerable?)extensionAttributes);
///
/// Converts this HTTP request message into a CloudEvent object.
@@ -130,7 +132,7 @@ public static Task ToCloudEventAsync(
return ToCloudEventInternalAsync(httpRequestMessage.Headers, httpRequestMessage.Content, formatter, extensionAttributes, nameof(httpRequestMessage));
}
- private static async Task ToCloudEventInternalAsync(HttpHeaders headers, HttpContent content,
+ private static async Task ToCloudEventInternalAsync(HttpHeaders headers, HttpContent? content,
CloudEventFormatter formatter, IEnumerable? extensionAttributes, string paramName)
{
Validation.CheckNotNull(formatter, nameof(formatter));
@@ -142,7 +144,7 @@ private static async Task ToCloudEventInternalAsync(HttpHeaders head
}
else
{
- string? versionId = MaybeGetVersionId(headers) ?? MaybeGetVersionId(content.Headers);
+ string? versionId = MaybeGetVersionId(headers) ?? MaybeGetVersionId(content?.Headers);
if (versionId is null)
{
throw new ArgumentException($"Request does not represent a CloudEvent. It has neither a {HttpUtilities.SpecVersionHttpHeader} header, nor a suitable content type.", nameof(paramName));
@@ -151,7 +153,7 @@ private static async Task ToCloudEventInternalAsync(HttpHeaders head
?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", paramName);
var cloudEvent = new CloudEvent(version, extensionAttributes);
- foreach (var header in headers.Concat(content.Headers))
+ foreach (var header in headers.Concat(content!.Headers))
{
string? attributeName = HttpUtilities.GetAttributeNameFromHeaderName(header.Key);
if (attributeName is null || attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
@@ -231,7 +233,7 @@ public static Task> ToCloudEventBatchAsync(
return ToCloudEventBatchInternalAsync(httpRequestMessage.Content, formatter, extensionAttributes, nameof(httpRequestMessage));
}
- private static async Task> ToCloudEventBatchInternalAsync(HttpContent content,
+ private static async Task> ToCloudEventBatchInternalAsync(HttpContent? content,
CloudEventFormatter formatter, IEnumerable? extensionAttributes, string paramName)
{
Validation.CheckNotNull(formatter, nameof(formatter));
@@ -332,15 +334,15 @@ public static HttpContent ToHttpContent(this IReadOnlyList cloudEven
private static ByteArrayContent ToByteArrayContent(ReadOnlyMemory content) =>
MemoryMarshal.TryGetArray(content, out var segment)
- ? new ByteArrayContent(segment.Array, segment.Offset, segment.Count)
+ ? new ByteArrayContent(segment.Array!, segment.Offset, segment.Count)
// TODO: Just throw?
: new ByteArrayContent(content.ToArray());
// TODO: This would include "application/cloudeventsarerubbish" for example...
- private static bool HasCloudEventsContentType(HttpContent content) =>
+ private static bool HasCloudEventsContentType([NotNullWhen(true)] HttpContent? content) =>
MimeUtilities.IsCloudEventsContentType(content?.Headers?.ContentType?.MediaType);
- private static bool HasCloudEventsBatchContentType(HttpContent content) =>
+ private static bool HasCloudEventsBatchContentType([NotNullWhen(true)] HttpContent? content) =>
MimeUtilities.IsCloudEventsBatchContentType(content?.Headers?.ContentType?.MediaType);
private static string? MaybeGetVersionId(HttpHeaders? headers) =>
diff --git a/src/CloudNative.CloudEvents/Http/HttpListenerExtensions.cs b/src/CloudNative.CloudEvents/Http/HttpListenerExtensions.cs
index 7e83936..16ed690 100644
--- a/src/CloudNative.CloudEvents/Http/HttpListenerExtensions.cs
+++ b/src/CloudNative.CloudEvents/Http/HttpListenerExtensions.cs
@@ -151,7 +151,7 @@ public async static Task ToCloudEventAsync(this HttpListenerRequest
/// A reference to a validated CloudEvent instance.
public static CloudEvent ToCloudEvent(this HttpListenerRequest httpListenerRequest,
CloudEventFormatter formatter, params CloudEventAttribute[]? extensionAttributes) =>
- ToCloudEvent(httpListenerRequest, formatter, (IEnumerable?) extensionAttributes);
+ ToCloudEvent(httpListenerRequest, formatter, (IEnumerable?)extensionAttributes);
///
/// Converts this listener request into a CloudEvent object, with the given extension attributes.
@@ -179,7 +179,7 @@ private async static Task ToCloudEventAsyncImpl(HttpListenerRequest
}
else
{
- string versionId = httpListenerRequest.Headers[HttpUtilities.SpecVersionHttpHeader];
+ string? versionId = httpListenerRequest.Headers[HttpUtilities.SpecVersionHttpHeader];
if (versionId is null)
{
throw new ArgumentException($"Request does not represent a CloudEvent. It has neither a {HttpUtilities.SpecVersionHttpHeader} header, nor a suitable content type.", nameof(httpListenerRequest));
@@ -191,12 +191,12 @@ private async static Task ToCloudEventAsyncImpl(HttpListenerRequest
var headers = httpListenerRequest.Headers;
foreach (var key in headers.AllKeys)
{
- string? attributeName = HttpUtilities.GetAttributeNameFromHeaderName(key);
+ string? attributeName = HttpUtilities.GetAttributeNameFromHeaderName(key!);
if (attributeName is null || attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
{
continue;
}
- string attributeValue = HttpUtilities.DecodeHeaderValue(headers[key]);
+ string attributeValue = HttpUtilities.DecodeHeaderValue(headers[key]!);
cloudEvent.SetAttributeFromString(attributeName, attributeValue);
}
@@ -223,7 +223,7 @@ public static Task> ToCloudEventBatchAsync(
this HttpListenerRequest httpListenerRequest,
CloudEventFormatter formatter,
params CloudEventAttribute[]? extensionAttributes) =>
- ToCloudEventBatchAsync(httpListenerRequest, formatter, (IEnumerable?)extensionAttributes);
+ ToCloudEventBatchAsync(httpListenerRequest, formatter, (IEnumerable?) extensionAttributes);
///
/// Converts this HTTP request message into a CloudEvent batch.
@@ -263,6 +263,7 @@ public static IReadOnlyList ToCloudEventBatch(
CloudEventFormatter formatter,
IEnumerable? extensionAttributes) =>
ToCloudEventBatchInternalAsync(httpListenerRequest, formatter, extensionAttributes, async: false).GetAwaiter().GetResult();
+
private async static Task> ToCloudEventBatchInternalAsync(HttpListenerRequest httpListenerRequest,
CloudEventFormatter formatter, IEnumerable? extensionAttributes, bool async)
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 0f81436..997763d 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -27,6 +27,10 @@
Apache-2.0
https://cloudevents.io
Copyright Cloud Native Foundation
+
+ true
+ true
+ 12.0
diff --git a/test/CloudNative.CloudEvents.IntegrationTests/CloudNative.CloudEvents.IntegrationTests.csproj b/test/CloudNative.CloudEvents.IntegrationTests/CloudNative.CloudEvents.IntegrationTests.csproj
index da33b50..ba679bb 100644
--- a/test/CloudNative.CloudEvents.IntegrationTests/CloudNative.CloudEvents.IntegrationTests.csproj
+++ b/test/CloudNative.CloudEvents.IntegrationTests/CloudNative.CloudEvents.IntegrationTests.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
diff --git a/test/CloudNative.CloudEvents.UnitTests/CloudNative.CloudEvents.UnitTests.csproj b/test/CloudNative.CloudEvents.UnitTests/CloudNative.CloudEvents.UnitTests.csproj
index 0fc8ce6..2c989ff 100644
--- a/test/CloudNative.CloudEvents.UnitTests/CloudNative.CloudEvents.UnitTests.csproj
+++ b/test/CloudNative.CloudEvents.UnitTests/CloudNative.CloudEvents.UnitTests.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
enable
diff --git a/test/CloudNative.CloudEvents.UnitTests/SystemTextJson/ConformanceTest.cs b/test/CloudNative.CloudEvents.UnitTests/SystemTextJson/ConformanceTest.cs
index 8cac6f9..2e23c71 100644
--- a/test/CloudNative.CloudEvents.UnitTests/SystemTextJson/ConformanceTest.cs
+++ b/test/CloudNative.CloudEvents.UnitTests/SystemTextJson/ConformanceTest.cs
@@ -4,6 +4,7 @@
using CloudNative.CloudEvents.UnitTests;
using CloudNative.CloudEvents.UnitTests.ConformanceTestData;
+using Microsoft.Extensions.ObjectPool;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -21,7 +22,8 @@ public class ConformanceTest
private static IEnumerable
- [Fact]
- public void EncodeStructuredModeMessage_V1Attributes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_V1Attributes(bool useContext)
{
var cloudEvent = new CloudEvent(CloudEventsSpecVersion.V1_0)
{
@@ -47,7 +49,8 @@ public void EncodeStructuredModeMessage_V1Attributes()
Type = "event-type"
};
- var encoded = new JsonEventFormatter().EncodeStructuredModeMessage(cloudEvent, out var contentType);
+ var encoded = (useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter())
+ .EncodeStructuredModeMessage(cloudEvent, out var contentType);
Assert.Equal("application/cloudevents+json; charset=utf-8", contentType.ToString());
JsonElement obj = ParseJson(encoded);
var asserter = new JsonElementAsserter
@@ -65,8 +68,10 @@ public void EncodeStructuredModeMessage_V1Attributes()
asserter.AssertProperties(obj, assertCount: true);
}
- [Fact]
- public void EncodeStructuredModeMessage_AllAttributeTypes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_AllAttributeTypes(bool useContext)
{
var cloudEvent = new CloudEvent(AllTypesExtensions)
{
@@ -81,7 +86,7 @@ public void EncodeStructuredModeMessage_AllAttributeTypes()
// We're not going to check these.
cloudEvent.PopulateRequiredAttributes();
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
var asserter = new JsonElementAsserter
{
{ "binary", JsonValueKind.String, SampleBinaryDataBase64 },
@@ -101,7 +106,8 @@ public void EncodeStructuredModeMessage_JsonDataType_ObjectSerialization()
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = new { Text = "simple text" };
cloudEvent.DataContentType = "application/json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ // anonymous type do not support source generation for json serialization
+ JsonElement element = EncodeAndParseStructured(cloudEvent, false);
JsonElement dataProperty = element.GetProperty("data");
var asserter = new JsonElementAsserter
{
@@ -110,13 +116,15 @@ public void EncodeStructuredModeMessage_JsonDataType_ObjectSerialization()
asserter.AssertProperties(dataProperty, assertCount: true);
}
- [Fact]
- public void EncodeStructuredModeMessage_JsonDataType_NumberSerialization()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_JsonDataType_NumberSerialization(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = 10;
cloudEvent.DataContentType = "application/json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
var asserter = new JsonElementAsserter
{
{ "data", JsonValueKind.Number, 10 }
@@ -146,13 +154,15 @@ public void EncodeStructuredModeMessage_JsonDataType_CustomSerializerOptions()
asserter.AssertProperties(dataProperty, assertCount: true);
}
- [Fact]
- public void EncodeStructuredModeMessage_JsonDataType_AttributedModel()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_JsonDataType_AttributedModel(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = new AttributedModel { AttributedProperty = "simple text" };
cloudEvent.DataContentType = "application/json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
JsonElement dataProperty = element.GetProperty("data");
var asserter = new JsonElementAsserter
{
@@ -161,13 +171,15 @@ public void EncodeStructuredModeMessage_JsonDataType_AttributedModel()
asserter.AssertProperties(dataProperty, assertCount: true);
}
- [Fact]
- public void EncodeStructuredModeMessage_JsonDataType_JsonElementObject()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_JsonDataType_JsonElementObject(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = ParseJson("{ \"value\": { \"Key\": \"value\" } }").GetProperty("value");
cloudEvent.DataContentType = "application/json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
JsonElement data = element.GetProperty("data");
var asserter = new JsonElementAsserter
{
@@ -176,107 +188,125 @@ public void EncodeStructuredModeMessage_JsonDataType_JsonElementObject()
asserter.AssertProperties(data, assertCount: true);
}
- [Fact]
- public void EncodeStructuredModeMessage_JsonDataType_JsonElementString()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_JsonDataType_JsonElementString(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = ParseJson("{ \"value\": \"text\" }").GetProperty("value");
cloudEvent.DataContentType = "application/json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
JsonElement data = element.GetProperty("data");
Assert.Equal(JsonValueKind.String, data.ValueKind);
Assert.Equal("text", data.GetString());
}
- [Fact]
- public void EncodeStructuredModeMessage_JsonDataType_JsonElementNull()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_JsonDataType_JsonElementNull(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = ParseJson("{ \"value\": null }").GetProperty("value");
cloudEvent.DataContentType = "application/json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
JsonElement data = element.GetProperty("data");
Assert.Equal(JsonValueKind.Null, data.ValueKind);
}
- [Fact]
- public void EncodeStructuredModeMessage_JsonDataType_JsonElementNumeric()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_JsonDataType_JsonElementNumeric(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = ParseJson("{ \"value\": 100 }").GetProperty("value");
cloudEvent.DataContentType = "application/json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
JsonElement data = element.GetProperty("data");
Assert.Equal(JsonValueKind.Number, data.ValueKind);
Assert.Equal(100, data.GetInt32());
}
- [Fact]
- public void EncodeStructuredModeMessage_JsonDataType_NullValue()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_JsonDataType_NullValue(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = null;
cloudEvent.DataContentType = "application/json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
Assert.False(element.TryGetProperty("data", out _));
}
- [Fact]
- public void EncodeStructuredModeMessage_TextType_String()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_TextType_String(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = "some text";
cloudEvent.DataContentType = "text/anything";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
var dataProperty = element.GetProperty("data");
Assert.Equal(JsonValueKind.String, dataProperty.ValueKind);
Assert.Equal("some text", dataProperty.GetString());
}
// A text content type with bytes as data is serialized like any other bytes.
- [Fact]
- public void EncodeStructuredModeMessage_TextType_Bytes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_TextType_Bytes(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = SampleBinaryData;
cloudEvent.DataContentType = "text/anything";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
Assert.False(element.TryGetProperty("data", out _));
var dataBase64 = element.GetProperty("data_base64");
Assert.Equal(JsonValueKind.String, dataBase64.ValueKind);
Assert.Equal(SampleBinaryDataBase64, dataBase64.GetString());
}
- [Fact]
- public void EncodeStructuredModeMessage_TextType_NotStringOrBytes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_TextType_NotStringOrBytes(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = new object();
cloudEvent.DataContentType = "text/anything";
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
Assert.Throws(() => formatter.EncodeStructuredModeMessage(cloudEvent, out _));
}
- [Fact]
- public void EncodeStructuredModeMessage_ArbitraryType_Bytes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_ArbitraryType_Bytes(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = SampleBinaryData;
cloudEvent.DataContentType = "not_text/or_json";
- JsonElement element = EncodeAndParseStructured(cloudEvent);
+ JsonElement element = EncodeAndParseStructured(cloudEvent, useContext);
Assert.False(element.TryGetProperty("data", out _));
var dataBase64 = element.GetProperty("data_base64");
Assert.Equal(JsonValueKind.String, dataBase64.ValueKind);
Assert.Equal(SampleBinaryDataBase64, dataBase64.GetString());
}
- [Fact]
- public void EncodeStructuredModeMessage_ArbitraryType_NotBytes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeStructuredModeMessage_ArbitraryType_NotBytes(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = new object();
cloudEvent.DataContentType = "not_text/or_json";
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
Assert.Throws(() => formatter.EncodeStructuredModeMessage(cloudEvent, out _));
}
@@ -286,7 +316,9 @@ public void EncodeBinaryModeEventData_JsonDataType_ObjectSerialization()
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = new { Text = "simple text" };
cloudEvent.DataContentType = "application/json";
- var bytes = new JsonEventFormatter().EncodeBinaryModeEventData(cloudEvent);
+ // anonymous type do not support source generation for json serialization
+ var bytes = new JsonEventFormatter()
+ .EncodeBinaryModeEventData(cloudEvent);
JsonElement data = ParseJson(bytes);
var asserter = new JsonElementAsserter
{
@@ -316,13 +348,16 @@ public void EncodeBinaryModeEventData_JsonDataType_CustomSerializer()
asserter.AssertProperties(data, assertCount: true);
}
- [Fact]
- public void EncodeBinaryModeEventData_JsonDataType_AttributedModel()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBinaryModeEventData_JsonDataType_AttributedModel(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = new AttributedModel { AttributedProperty = "simple text" };
cloudEvent.DataContentType = "application/json";
- var bytes = new JsonEventFormatter().EncodeBinaryModeEventData(cloudEvent);
+ var bytes = (useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter())
+ .EncodeBinaryModeEventData(cloudEvent);
JsonElement data = ParseJson(bytes);
var asserter = new JsonElementAsserter
{
@@ -332,78 +367,97 @@ public void EncodeBinaryModeEventData_JsonDataType_AttributedModel()
}
[Theory]
- [InlineData("utf-8")]
- [InlineData("utf-16")]
- public void EncodeBinaryModeEventData_JsonDataType_JsonElement(string charset)
+ [InlineData("utf-8", true)]
+ [InlineData("utf-8", false)]
+ [InlineData("utf-16", true)]
+ [InlineData("utf-16", false)]
+ public void EncodeBinaryModeEventData_JsonDataType_JsonElement(string charset, bool useContext)
{
// This would definitely be an odd thing to do, admittedly...
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = ParseJson($"{{ \"value\": \"some text\" }}").GetProperty("value");
cloudEvent.DataContentType = $"application/json; charset={charset}";
- var bytes = new JsonEventFormatter().EncodeBinaryModeEventData(cloudEvent);
+ var bytes = (useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter())
+ .EncodeBinaryModeEventData(cloudEvent);
Assert.Equal("\"some text\"", BinaryDataUtilities.GetString(bytes, Encoding.GetEncoding(charset)));
}
- [Fact]
- public void EncodeBinaryModeEventData_JsonDataType_NullValue()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBinaryModeEventData_JsonDataType_NullValue(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = null;
cloudEvent.DataContentType = "application/json";
- var bytes = new JsonEventFormatter().EncodeBinaryModeEventData(cloudEvent);
+ var bytes = (useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter())
+ .EncodeBinaryModeEventData(cloudEvent);
Assert.True(bytes.IsEmpty);
}
[Theory]
- [InlineData("utf-8")]
- [InlineData("iso-8859-1")]
- public void EncodeBinaryModeEventData_TextType_String(string charset)
+ [InlineData("utf-8", true)]
+ [InlineData("utf-8", false)]
+ [InlineData("iso-8859-1", true)]
+ [InlineData("iso-8859-1", false)]
+ public void EncodeBinaryModeEventData_TextType_String(string charset, bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = "some text";
cloudEvent.DataContentType = $"text/anything; charset={charset}";
- var bytes = new JsonEventFormatter().EncodeBinaryModeEventData(cloudEvent);
+ var bytes = (useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter())
+ .EncodeBinaryModeEventData(cloudEvent);
Assert.Equal("some text", BinaryDataUtilities.GetString(bytes, Encoding.GetEncoding(charset)));
}
// A text content type with bytes as data is serialized like any other bytes.
- [Fact]
- public void EncodeBinaryModeEventData_TextType_Bytes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBinaryModeEventData_TextType_Bytes(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = SampleBinaryData;
cloudEvent.DataContentType = "text/anything";
- var bytes = new JsonEventFormatter().EncodeBinaryModeEventData(cloudEvent);
+ var bytes = (useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter())
+ .EncodeBinaryModeEventData(cloudEvent);
Assert.Equal(SampleBinaryData, bytes);
}
- [Fact]
- public void EncodeBinaryModeEventData_TextType_NotStringOrBytes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBinaryModeEventData_TextType_NotStringOrBytes(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = new object();
cloudEvent.DataContentType = "text/anything";
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
Assert.Throws(() => formatter.EncodeBinaryModeEventData(cloudEvent));
}
- [Fact]
- public void EncodeBinaryModeEventData_ArbitraryType_Bytes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBinaryModeEventData_ArbitraryType_Bytes(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = SampleBinaryData;
cloudEvent.DataContentType = "not_text/or_json";
- var bytes = new JsonEventFormatter().EncodeBinaryModeEventData(cloudEvent);
+ var bytes = (useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter())
+ .EncodeBinaryModeEventData(cloudEvent);
Assert.Equal(SampleBinaryData, bytes);
}
- [Fact]
- public void EncodeBinaryModeEventData_ArbitraryType_NotBytes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBinaryModeEventData_ArbitraryType_NotBytes(bool useContext)
{
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
cloudEvent.Data = new object();
cloudEvent.DataContentType = "not_text/or_json";
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
Assert.Throws(() => formatter.EncodeBinaryModeEventData(cloudEvent));
}
@@ -440,11 +494,13 @@ public void EncodeBinaryModeEventData_NoContentType_LeavesBinaryData()
// per-CloudEvent implementation is shared with structured mode, so we rely on
// structured mode testing for things like custom serialization.
- [Fact]
- public void EncodeBatchModeMessage_Empty()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBatchModeMessage_Empty(bool useContext)
{
var cloudEvents = new CloudEvent[0];
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var bytes = formatter.EncodeBatchModeMessage(cloudEvents, out var contentType);
Assert.Equal("application/cloudevents-batch+json; charset=utf-8", contentType.ToString());
var array = ParseJson(bytes);
@@ -452,8 +508,10 @@ public void EncodeBatchModeMessage_Empty()
Assert.Equal(0, array.GetArrayLength());
}
- [Fact]
- public void EncodeBatchModeMessage_TwoEvents()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBatchModeMessage_TwoEvents(bool useContext)
{
var event1 = new CloudEvent().PopulateRequiredAttributes();
event1.Id = "event1";
@@ -464,7 +522,7 @@ public void EncodeBatchModeMessage_TwoEvents()
event2.Id = "event2";
var cloudEvents = new[] { event1, event2 };
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var bytes = formatter.EncodeBatchModeMessage(cloudEvents, out var contentType);
Assert.Equal("application/cloudevents-batch+json; charset=utf-8", contentType.ToString());
var array = ParseJson(bytes).EnumerateArray().ToList();
@@ -491,10 +549,12 @@ public void EncodeBatchModeMessage_TwoEvents()
asserter2.AssertProperties(array[1], assertCount: true);
}
- [Fact]
- public void EncodeBatchModeMessage_Invalid()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void EncodeBatchModeMessage_Invalid(bool useContext)
{
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
// Invalid CloudEvent
Assert.Throws(() => formatter.EncodeBatchModeMessage(new[] { new CloudEvent() }, out _));
// Null argument
@@ -504,18 +564,22 @@ public void EncodeBatchModeMessage_Invalid()
Assert.Throws(() => formatter.EncodeBatchModeMessage(new CloudEvent[1], out _));
}
- [Fact]
- public void DecodeStructuredModeMessage_NotJson()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_NotJson(bool useContext)
{
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
Assert.ThrowsAny(() => formatter.DecodeStructuredModeMessage(new byte[10], new ContentType("application/json"), null));
}
// Just a single test for the code that parses asynchronously... the guts are all the same.
[Theory]
- [InlineData("utf-8")]
- [InlineData("iso-8859-1")]
- public async Task DecodeStructuredModeMessageAsync_Minimal(string charset)
+ [InlineData("utf-8", true)]
+ [InlineData("utf-8", false)]
+ [InlineData("iso-8859-1", true)]
+ [InlineData("iso-8859-1", false)]
+ public async Task DecodeStructuredModeMessageAsync_Minimal(string charset, bool useContext)
{
// Note: just using Json.NET to get the JSON in a simple way...
var obj = new JObject
@@ -528,7 +592,7 @@ public async Task DecodeStructuredModeMessageAsync_Minimal(string charset)
};
var bytes = Encoding.GetEncoding(charset).GetBytes(obj.ToString());
var stream = new MemoryStream(bytes);
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var cloudEvent = await formatter.DecodeStructuredModeMessageAsync(stream, new ContentType($"application/cloudevents+json; charset={charset}"), null);
Assert.Equal("test-type", cloudEvent.Type);
Assert.Equal("test-id", cloudEvent.Id);
@@ -537,9 +601,11 @@ public async Task DecodeStructuredModeMessageAsync_Minimal(string charset)
}
[Theory]
- [InlineData("utf-8")]
- [InlineData("iso-8859-1")]
- public void DecodeStructuredModeMessage_Minimal(string charset)
+ [InlineData("utf-8", true)]
+ [InlineData("utf-8", false)]
+ [InlineData("iso-8859-1", true)]
+ [InlineData("iso-8859-1", false)]
+ public void DecodeStructuredModeMessage_Minimal(string charset, bool useContext)
{
var obj = new JObject
{
@@ -551,15 +617,17 @@ public void DecodeStructuredModeMessage_Minimal(string charset)
};
var bytes = Encoding.GetEncoding(charset).GetBytes(obj.ToString());
var stream = new MemoryStream(bytes);
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var cloudEvent = formatter.DecodeStructuredModeMessage(stream, new ContentType($"application/cloudevents+json; charset={charset}"), null);
Assert.Equal("test-type", cloudEvent.Type);
Assert.Equal("test-id", cloudEvent.Id);
Assert.Equal(SampleUri, cloudEvent.Source);
}
- [Fact]
- public void DecodeStructuredModeMessage_NoSpecVersion()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_NoSpecVersion(bool useContext)
{
var obj = new JObject
{
@@ -567,11 +635,13 @@ public void DecodeStructuredModeMessage_NoSpecVersion()
["id"] = "test-id",
["source"] = SampleUriText,
};
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
- [Fact]
- public void DecodeStructuredModeMessage_UnknownSpecVersion()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_UnknownSpecVersion(bool useContext)
{
var obj = new JObject
{
@@ -580,11 +650,13 @@ public void DecodeStructuredModeMessage_UnknownSpecVersion()
["id"] = "test-id",
["source"] = SampleUriText,
};
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
- [Fact]
- public void DecodeStructuredModeMessage_MissingRequiredAttributes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_MissingRequiredAttributes(bool useContext)
{
var obj = new JObject
{
@@ -593,11 +665,13 @@ public void DecodeStructuredModeMessage_MissingRequiredAttributes()
["id"] = "test-id"
// Source is missing
};
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
- [Fact]
- public void DecodeStructuredModeMessage_SpecVersionNotString()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_SpecVersionNotString(bool useContext)
{
var obj = new JObject
{
@@ -606,11 +680,13 @@ public void DecodeStructuredModeMessage_SpecVersionNotString()
["id"] = "test-id",
["source"] = SampleUriText,
};
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
- [Fact]
- public void DecodeStructuredModeMessage_TypeNotString()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_TypeNotString(bool useContext)
{
var obj = new JObject
{
@@ -619,11 +695,13 @@ public void DecodeStructuredModeMessage_TypeNotString()
["id"] = "test-id",
["source"] = SampleUriText,
};
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
- [Fact]
- public void DecodeStructuredModeMessage_V1Attributes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_V1Attributes(bool useContext)
{
var obj = new JObject
{
@@ -637,7 +715,7 @@ public void DecodeStructuredModeMessage_V1Attributes()
["source"] = "//event-source",
["time"] = SampleTimestampText
};
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
Assert.Equal(CloudEventsSpecVersion.V1_0, cloudEvent.SpecVersion);
Assert.Equal("test-type", cloudEvent.Type);
Assert.Equal("test-id", cloudEvent.Id);
@@ -648,8 +726,10 @@ public void DecodeStructuredModeMessage_V1Attributes()
AssertTimestampsEqual(SampleTimestamp, cloudEvent.Time);
}
- [Fact]
- public void DecodeStructuredModeMessage_AllAttributeTypes()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_AllAttributeTypes(bool useContext)
{
var obj = new JObject
{
@@ -669,7 +749,7 @@ public void DecodeStructuredModeMessage_AllAttributeTypes()
};
var bytes = Encoding.UTF8.GetBytes(obj.ToString());
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var cloudEvent = formatter.DecodeStructuredModeMessage(bytes, s_jsonCloudEventContentType, AllTypesExtensions);
Assert.Equal(SampleBinaryData, cloudEvent["binary"]);
Assert.True((bool)cloudEvent["boolean"]!);
@@ -680,8 +760,10 @@ public void DecodeStructuredModeMessage_AllAttributeTypes()
Assert.Equal(SampleUriReference, cloudEvent["urireference"]);
}
- [Fact]
- public void DecodeStructuredModeMessage_IncorrectExtensionTypeWithValidValue()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_IncorrectExtensionTypeWithValidValue(bool useContext)
{
var obj = new JObject
{
@@ -694,7 +776,7 @@ public void DecodeStructuredModeMessage_IncorrectExtensionTypeWithValidValue()
};
// Decode the event, providing the extension with the correct type.
var bytes = Encoding.UTF8.GetBytes(obj.ToString());
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var cloudEvent = formatter.DecodeStructuredModeMessage(bytes, s_jsonCloudEventContentType, AllTypesExtensions);
// The value will have been decoded according to the extension.
@@ -702,65 +784,81 @@ public void DecodeStructuredModeMessage_IncorrectExtensionTypeWithValidValue()
}
// There are other invalid token types as well; this is just one of them.
- [Fact]
- public void DecodeStructuredModeMessage_AttributeValueAsArrayToken()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_AttributeValueAsArrayToken(bool useContext)
{
var obj = CreateMinimalValidJObject();
obj["attr"] = new Newtonsoft.Json.Linq.JArray();
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
- [Fact]
- public void DecodeStructuredModeMessage_Null()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_Null(bool useContext)
{
var obj = CreateMinimalValidJObject();
obj["attr"] = Newtonsoft.Json.Linq.JValue.CreateNull();
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
// The JSON event format spec demands that we ignore null values, so we shouldn't
// have created an extension attribute.
Assert.Null(cloudEvent.GetAttribute("attr"));
}
[Theory]
- [InlineData(null)]
- [InlineData("application/json")]
- [InlineData("text/plain")]
- [InlineData("application/binary")]
- public void DecodeStructuredModeMessage_NoData(string contentType)
+ [InlineData(null, true)]
+ [InlineData(null, false)]
+ [InlineData("application/json", true)]
+ [InlineData("application/json", false)]
+ [InlineData("text/plain", true)]
+ [InlineData("text/plain", false)]
+ [InlineData("application/binary", true)]
+ [InlineData("application/binary", false)]
+ public void DecodeStructuredModeMessage_NoData(string contentType, bool useContext)
{
var obj = CreateMinimalValidJObject();
if (contentType is object)
{
obj["datacontenttype"] = contentType;
}
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
Assert.Null(cloudEvent.Data);
}
- [Fact]
- public void DecodeStructuredModeMessage_BothDataAndDataBase64()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_BothDataAndDataBase64(bool useContext)
{
var obj = CreateMinimalValidJObject();
obj["data"] = "text";
obj["data_base64"] = SampleBinaryDataBase64;
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
- [Fact]
- public void DecodeStructuredModeMessage_DataBase64NonString()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_DataBase64NonString(bool useContext)
{
var obj = CreateMinimalValidJObject();
obj["data_base64"] = 10;
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
// data_base64 always ends up as bytes, regardless of content type.
[Theory]
- [InlineData(null)]
- [InlineData("application/json")]
- [InlineData("text/plain")]
- [InlineData("application/binary")]
- public void DecodeStructuredModeMessage_Base64(string contentType)
+ [InlineData(null, true)]
+ [InlineData(null, false)]
+ [InlineData("application/json", true)]
+ [InlineData("application/json", false)]
+ [InlineData("text/plain", true)]
+ [InlineData("text/plain", false)]
+ [InlineData("application/binary", true)]
+ [InlineData("application/binary", false)]
+ public void DecodeStructuredModeMessage_Base64(string contentType, bool useContext)
{
var obj = CreateMinimalValidJObject();
if (contentType is object)
@@ -768,27 +866,32 @@ public void DecodeStructuredModeMessage_Base64(string contentType)
obj["datacontenttype"] = contentType;
}
obj["data_base64"] = SampleBinaryDataBase64;
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
Assert.Equal(SampleBinaryData, cloudEvent.Data);
}
[Theory]
- [InlineData("text/plain")]
- [InlineData("image/png")]
- public void DecodeStructuredModeMessage_NonJsonContentType_JsonStringToken(string contentType)
+ [InlineData("text/plain", true)]
+ [InlineData("text/plain", false)]
+ [InlineData("image/png", true)]
+ [InlineData("image/png", false)]
+ public void DecodeStructuredModeMessage_NonJsonContentType_JsonStringToken(string contentType, bool useContext)
{
var obj = CreateMinimalValidJObject();
obj["datacontenttype"] = contentType;
obj["data"] = "some text";
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
Assert.Equal("some text", cloudEvent.Data);
}
[Theory]
- [InlineData(null)]
- [InlineData("application/json")]
- [InlineData("application/json; charset=utf-8")]
- public void DecodeStructuredModeMessage_JsonContentType_JsonStringToken(string contentType)
+ [InlineData(null, true)]
+ [InlineData(null, false)]
+ [InlineData("application/json", true)]
+ [InlineData("application/json", false)]
+ [InlineData("application/json; charset=utf-8", true)]
+ [InlineData("application/json; charset=utf-8", false)]
+ public void DecodeStructuredModeMessage_JsonContentType_JsonStringToken(string contentType, bool useContext)
{
var obj = CreateMinimalValidJObject();
if (contentType is object)
@@ -796,18 +899,22 @@ public void DecodeStructuredModeMessage_JsonContentType_JsonStringToken(string c
obj["datacontenttype"] = contentType;
}
obj["data"] = "text";
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
var element = (JsonElement) cloudEvent.Data!;
Assert.Equal(JsonValueKind.String, element.ValueKind);
Assert.Equal("text", element.GetString());
}
[Theory]
- [InlineData(null)]
- [InlineData("application/json")]
- [InlineData("application/xyz+json")]
- [InlineData("application/xyz+json; charset=utf-8")]
- public void DecodeStructuredModeMessage_JsonContentType_NonStringValue(string contentType)
+ [InlineData(null, true)]
+ [InlineData(null, false)]
+ [InlineData("application/json", true)]
+ [InlineData("application/json", false)]
+ [InlineData("application/xyz+json", true)]
+ [InlineData("application/xyz+json", false)]
+ [InlineData("application/xyz+json; charset=utf-8", true)]
+ [InlineData("application/xyz+json; charset=utf-8", false)]
+ public void DecodeStructuredModeMessage_JsonContentType_NonStringValue(string contentType, bool useContext)
{
var obj = CreateMinimalValidJObject();
if (contentType is object)
@@ -815,40 +922,46 @@ public void DecodeStructuredModeMessage_JsonContentType_NonStringValue(string co
obj["datacontenttype"] = contentType;
}
obj["data"] = 10;
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
var element = (JsonElement) cloudEvent.Data!;
Assert.Equal(JsonValueKind.Number, element.ValueKind);
Assert.Equal(10, element.GetInt32());
}
- [Fact]
- public void DecodeStructuredModeMessage_NonJsonContentType_NonStringValue()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_NonJsonContentType_NonStringValue(bool useContext)
{
var obj = CreateMinimalValidJObject();
obj["datacontenttype"] = "text/plain";
obj["data"] = 10;
- Assert.Throws(() => DecodeStructuredModeMessage(obj));
+ Assert.Throws(() => DecodeStructuredModeMessage(obj, useContext));
}
- [Fact]
- public void DecodeStructuredModeMessage_NullDataBase64Ignored()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_NullDataBase64Ignored(bool useContext)
{
var obj = CreateMinimalValidJObject();
obj["data_base64"] = Newtonsoft.Json.Linq.JValue.CreateNull();
obj["data"] = "some text";
obj["datacontenttype"] = "text/plain";
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
Assert.Equal("some text", cloudEvent.Data);
}
- [Fact]
- public void DecodeStructuredModeMessage_NullDataIgnored()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructuredModeMessage_NullDataIgnored(bool useContext)
{
var obj = CreateMinimalValidJObject();
obj["data_base64"] = SampleBinaryDataBase64;
obj["data"] = Newtonsoft.Json.Linq.JValue.CreateNull();
obj["datacontenttype"] = "application/binary";
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
Assert.Equal(SampleBinaryData, cloudEvent.Data);
}
@@ -911,46 +1024,56 @@ public void DecodeBinaryModeEventData_Binary()
Assert.Equal(bytes, data);
}
- [Fact]
- public void DecodeBatchMode_NotArray()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeBatchMode_NotArray(bool useContext)
{
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var data = Encoding.UTF8.GetBytes(CreateMinimalValidJObject().ToString());
Assert.Throws(() => formatter.DecodeBatchModeMessage(data, s_jsonCloudEventBatchContentType, extensionAttributes: null));
}
- [Fact]
- public void DecodeBatchMode_ArrayContainingNonObject()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeBatchMode_ArrayContainingNonObject(bool useContext)
{
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var array = new JArray { CreateMinimalValidJObject(), "text" };
var data = Encoding.UTF8.GetBytes(array.ToString());
Assert.Throws(() => formatter.DecodeBatchModeMessage(data, s_jsonCloudEventBatchContentType, extensionAttributes: null));
}
- [Fact]
- public void DecodeBatchMode_Empty()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeBatchMode_Empty(bool useContext)
{
- var cloudEvents = DecodeBatchModeMessage(new JArray());
+ var cloudEvents = DecodeBatchModeMessage(new JArray(), useContext);
Assert.Empty(cloudEvents);
}
- [Fact]
- public void DecodeBatchMode_Minimal()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeBatchMode_Minimal(bool useContext)
{
- var cloudEvents = DecodeBatchModeMessage(new JArray { CreateMinimalValidJObject() });
+ var cloudEvents = DecodeBatchModeMessage(new JArray { CreateMinimalValidJObject() }, useContext);
var cloudEvent = Assert.Single(cloudEvents);
Assert.Equal("event-type", cloudEvent.Type);
Assert.Equal("event-id", cloudEvent.Id);
Assert.Equal(new Uri("//event-source", UriKind.RelativeOrAbsolute), cloudEvent.Source);
}
- [Fact]
- public void DecodeBatchMode_Minimal_WithStream()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeBatchMode_Minimal_WithStream(bool useContext)
{
var array = new JArray { CreateMinimalValidJObject() };
var bytes = Encoding.UTF8.GetBytes(array.ToString());
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var cloudEvents = formatter.DecodeBatchModeMessage(new MemoryStream(bytes), s_jsonCloudEventBatchContentType, null);
var cloudEvent = Assert.Single(cloudEvents);
Assert.Equal("event-type", cloudEvent.Type);
@@ -959,8 +1082,10 @@ public void DecodeBatchMode_Minimal_WithStream()
}
// Just a single test for the code that parses asynchronously... the guts are all the same.
- [Fact]
- public async Task DecodeBatchModeMessageAsync_Minimal()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task DecodeBatchModeMessageAsync_Minimal(bool useContext)
{
var obj = new JObject
{
@@ -971,7 +1096,7 @@ public async Task DecodeBatchModeMessageAsync_Minimal()
};
var bytes = Encoding.UTF8.GetBytes(new JArray { obj }.ToString());
var stream = new MemoryStream(bytes);
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var cloudEvents = await formatter.DecodeBatchModeMessageAsync(stream, s_jsonCloudEventBatchContentType, null);
var cloudEvent = Assert.Single(cloudEvents);
Assert.Equal("test-type", cloudEvent.Type);
@@ -980,8 +1105,10 @@ public async Task DecodeBatchModeMessageAsync_Minimal()
}
- [Fact]
- public void DecodeBatchMode_Multiple()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeBatchMode_Multiple(bool useContext)
{
var array = new JArray
{
@@ -1002,7 +1129,7 @@ public void DecodeBatchMode_Multiple()
["source"] = "//event-source2"
},
};
- var cloudEvents = DecodeBatchModeMessage(array);
+ var cloudEvents = DecodeBatchModeMessage(array, useContext);
Assert.Equal(2, cloudEvents.Count);
var event1 = cloudEvents[0];
@@ -1069,8 +1196,10 @@ public void EncodeStructured_BinaryData_DefaultContentTypeIsNotImplied()
asserter.AssertProperties(obj, assertCount: true);
}
- [Fact]
- public void DecodeStructured_DefaultContentTypeToApplicationJson()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void DecodeStructured_DefaultContentTypeToApplicationJson(bool useContext)
{
var obj = new JObject
{
@@ -1080,7 +1209,7 @@ public void DecodeStructured_DefaultContentTypeToApplicationJson()
["source"] = SampleUriText,
["data"] = "some text"
};
- var cloudEvent = DecodeStructuredModeMessage(obj);
+ var cloudEvent = DecodeStructuredModeMessage(obj, useContext);
Assert.Equal("application/json", cloudEvent.DataContentType);
var jsonData = Assert.IsType(cloudEvent.Data);
Assert.Equal(JsonValueKind.String, jsonData.ValueKind);
@@ -1189,9 +1318,9 @@ internal static JsonElement ParseJson(ReadOnlyMemory data)
/// Convenience method to format a CloudEvent with the default JsonEventFormatter in
/// structured mode, then parse the result as a JObject.
///
- private static JsonElement EncodeAndParseStructured(CloudEvent cloudEvent)
+ private static JsonElement EncodeAndParseStructured(CloudEvent cloudEvent, bool useContext)
{
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
var encoded = formatter.EncodeStructuredModeMessage(cloudEvent, out _);
return ParseJson(encoded);
}
@@ -1200,10 +1329,10 @@ private static JsonElement EncodeAndParseStructured(CloudEvent cloudEvent)
/// Convenience method to serialize a JObject to bytes, then
/// decode it as a structured event with the default (System.Text.Json) JsonEventFormatter and no extension attributes.
///
- private static CloudEvent DecodeStructuredModeMessage(Newtonsoft.Json.Linq.JObject obj)
+ private static CloudEvent DecodeStructuredModeMessage(Newtonsoft.Json.Linq.JObject obj, bool useContext)
{
var bytes = Encoding.UTF8.GetBytes(obj.ToString());
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
return formatter.DecodeStructuredModeMessage(bytes, s_jsonCloudEventContentType, null);
}
@@ -1211,10 +1340,10 @@ private static CloudEvent DecodeStructuredModeMessage(Newtonsoft.Json.Linq.JObje
/// Convenience method to serialize a JArray to bytes, then
/// decode it as a structured event with the default (System.Text.Json) JsonEventFormatter and no extension attributes.
///
- private static IReadOnlyList DecodeBatchModeMessage(Newtonsoft.Json.Linq.JArray array)
+ private static IReadOnlyList DecodeBatchModeMessage(Newtonsoft.Json.Linq.JArray array, bool useContext)
{
var bytes = Encoding.UTF8.GetBytes(array.ToString());
- var formatter = new JsonEventFormatter();
+ var formatter = useContext ? new JsonEventFormatter(GeneratedJsonContext.Default) : new JsonEventFormatter();
return formatter.DecodeBatchModeMessage(bytes, s_jsonCloudEventBatchContentType, null);
}
diff --git a/test/Directory.Build.props b/test/Directory.Build.props
index 7f8813f..96ea893 100644
--- a/test/Directory.Build.props
+++ b/test/Directory.Build.props
@@ -14,5 +14,6 @@
False
+ 12.0