Skip to content

Commit

Permalink
Add .NET 7, 8, trimming and AOT support
Browse files Browse the repository at this point in the history
Also fixed several nullability warnings.

Signed-off-by: Giovanni Bassi <[email protected]>
  • Loading branch information
giggio committed Nov 13, 2023
1 parent 6f48433 commit 6b24309
Show file tree
Hide file tree
Showing 36 changed files with 822 additions and 264 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Build

on:
workflow_dispatch:
push:
branches:
- main
Expand All @@ -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: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,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
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x

- name: Build
run: |
Expand Down
34 changes: 34 additions & 0 deletions CloudEvents.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\CloudNative.CloudEvents.AspNetCore\CloudNative.CloudEvents.AspNetCore.csproj" />
<ProjectReference Include="..\..\src\CloudNative.CloudEvents\CloudNative.CloudEvents.csproj" />
<ProjectReference Include="..\..\src\CloudNative.CloudEvents.SystemTextJson\CloudNative.CloudEvents.SystemTextJson.csproj" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<SelfContained>true</SelfContained>
<PublishAot>true</PublishAot>
<DebugType>None</DebugType>
<DebugSymbols>False</DebugSymbols>
</PropertyGroup>
</Project>
85 changes: 85 additions & 0 deletions samples/CloudNative.CloudEvents.MinApiSample/Program.cs
Original file line number Diff line number Diff line change
@@ -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<Message>(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<Message>(MyJsonContext.Default);
// required for receive2
public static async ValueTask<Event?> 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<Message>(MyJsonContext.Default);
// required for receive3
public static async ValueTask<Message?> BindAsync(HttpContext context)
{
var cloudEvent = await context.Request.ToCloudEventAsync(formatter);
return cloudEvent.Data is Message message ? message : null;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "api/events/generate",
"applicationUrl": "http://localhost:5002",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions samples/CloudNative.CloudEvents.MinApiSample/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
1 change: 1 addition & 0 deletions samples/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@

<!-- Never pack any sample projects -->
<IsPackable>False</IsPackable>
<LangVersion>12.0</LangVersion>
</PropertyGroup>
</Project>
19 changes: 19 additions & 0 deletions samples/HttpSendJson/HttpSendJson.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="docopt.net" Version="0.8.1" />
<ProjectReference Include="..\..\src\CloudNative.CloudEvents\CloudNative.CloudEvents.csproj" />
<ProjectReference Include="..\..\src\CloudNative.CloudEvents.SystemTextJson\CloudNative.CloudEvents.SystemTextJson.csproj" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<SelfContained>true</SelfContained>
<PublishAot>true</PublishAot>
<DebugType>None</DebugType>
<DebugSymbols>False</DebugSymbols>
</PropertyGroup>
</Project>
70 changes: 70 additions & 0 deletions samples/HttpSendJson/Program.cs
Original file line number Diff line number Diff line change
@@ -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<int> 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<ProgramArguments> CreateParserWithVersion() => CreateParser().WithVersion(Version);
}
24 changes: 22 additions & 2 deletions src/CloudNative.CloudEvents.Amqp/AmqpExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -249,4 +250,23 @@ private static ApplicationProperties MapHeaders(CloudEvent cloudEvent, string pr
return applicationProperties;
}
}
}
}

#if NETSTANDARD2_0
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class NotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;

/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}
}
#endif
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net7.0;net8.0</TargetFrameworks>
<Description>AMQP extensions for CloudNative.CloudEvents</Description>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
<PackageTags>cncf;cloudnative;cloudevents;events;amqp</PackageTags>
</PropertyGroup>
Expand Down
Loading

0 comments on commit 6b24309

Please sign in to comment.