Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for .NET 8 and Native AOT for ASP.NET Core bridge libraries. #1668

Merged
merged 2 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,25 @@

<PropertyGroup>
<Description>Package for running ASP.NET Core applications using the Minimal API style as a AWS Lambda function.</Description>
<TargetFramework>net6.0</TargetFramework>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.6.1</Version>
<Version>1.7.0</Version>
<PackageReadmeFile>README.md</PackageReadmeFile>
<AssemblyName>Amazon.Lambda.AspNetCoreServer.Hosting</AssemblyName>
<PackageId>Amazon.Lambda.AspNetCoreServer.Hosting</PackageId>

<WarningsAsErrors>IL2104,IL2026,IL2067,IL2075</WarningsAsErrors>
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\"/>
</ItemGroup>

<ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Amazon.Lambda.Core\Amazon.Lambda.Core.csproj" />
<ProjectReference Include="..\Amazon.Lambda.APIGatewayEvents\Amazon.Lambda.APIGatewayEvents.csproj" />
<ProjectReference Include="..\Amazon.Lambda.AspNetCoreServer\Amazon.Lambda.AspNetCoreServer.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using Amazon.Lambda.Core;
using Amazon.Lambda.Serialization.SystemTextJson;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System.Text.Json.Serialization;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Extensions.DependencyInjection
{
Expand Down Expand Up @@ -40,6 +42,7 @@ public static class ServiceCollectionExtensions
/// <param name="services"></param>
/// <param name="eventSource"></param>
/// <returns></returns>
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("For Native AOT the overload passing in a SourceGeneratorLambdaJsonSerializer instance must be used to avoid reflection with JSON serialization.")]
public static IServiceCollection AddAWSLambdaHosting(this IServiceCollection services, LambdaEventSource eventSource)
{
// Not running in Lambda so exit and let Kestrel be the web server
Expand All @@ -54,30 +57,61 @@ public static IServiceCollection AddAWSLambdaHosting(this IServiceCollection ser
/// <param name="eventSource"></param>
/// <param name="configure"></param>
/// <returns></returns>
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("For Native AOT the overload passing in a SourceGeneratorLambdaJsonSerializer instance must be used to avoid reflection with JSON serialization.")]
public static IServiceCollection AddAWSLambdaHosting(this IServiceCollection services, LambdaEventSource eventSource, Action<HostingOptions>? configure = null)
{
if (TryLambdaSetup(services, eventSource, configure, out var hostingOptions))
{
services.TryAddSingleton<ILambdaSerializer>(hostingOptions!.Serializer ?? new DefaultLambdaJsonSerializer());
}

return services;
}

/// <summary>
/// Add the ability to run the ASP.NET Core Lambda function in AWS Lambda. If the project is not running in Lambda
/// this method will do nothing allowing the normal Kestrel webserver to host the application.
/// </summary>
/// <param name="services"></param>
/// <param name="eventSource"></param>
/// <param name="serializer"></param>
/// <param name="configure"></param>
/// <returns></returns>
public static IServiceCollection AddAWSLambdaHosting<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(this IServiceCollection services, LambdaEventSource eventSource, SourceGeneratorLambdaJsonSerializer<T> serializer, Action<HostingOptions>? configure = null)
where T : JsonSerializerContext
{
if(TryLambdaSetup(services, eventSource, configure, out var hostingOptions))
{
services.TryAddSingleton<ILambdaSerializer>(serializer ?? hostingOptions!.Serializer);
}

return services;
}

private static bool TryLambdaSetup(IServiceCollection services, LambdaEventSource eventSource, Action<HostingOptions>? configure, out HostingOptions? hostingOptions)
{
hostingOptions = null;

// Not running in Lambda so exit and let Kestrel be the web server
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("AWS_LAMBDA_FUNCTION_NAME")))
return services;
return false;

hostingOptions = new HostingOptions();

var hostingOptions = new HostingOptions();

if (configure != null)
configure.Invoke(hostingOptions);

services.TryAddSingleton<ILambdaSerializer>(hostingOptions.Serializer ?? new DefaultLambdaJsonSerializer());

var serverType = eventSource switch
{
LambdaEventSource.HttpApi => typeof(APIGatewayHttpApiV2LambdaRuntimeSupportServer),
LambdaEventSource.RestApi => typeof(APIGatewayRestApiLambdaRuntimeSupportServer),
LambdaEventSource.ApplicationLoadBalancer => typeof(ApplicationLoadBalancerLambdaRuntimeSupportServer),
_ => throw new ArgumentException($"Event source type {eventSource} unknown")
};

Utilities.EnsureLambdaServerRegistered(services, serverType);
return services;

return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Text;

using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
Expand All @@ -13,7 +12,6 @@
using Amazon.Lambda.AspNetCoreServer.Internal;
using Microsoft.AspNetCore.Http.Features.Authentication;
using System.Globalization;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Hosting;
using System.Diagnostics.CodeAnalysis;

namespace Amazon.Lambda.AspNetCoreServer
{
Expand All @@ -8,7 +9,7 @@ namespace Amazon.Lambda.AspNetCoreServer
/// the Lambda function will point to this base class FunctionHandlerAsync method.
/// </summary>
/// <typeparam name ="TStartup">The type containing the startup methods for the application.</typeparam>
public abstract class APIGatewayHttpApiV2ProxyFunction<TStartup> : APIGatewayHttpApiV2ProxyFunction where TStartup : class
public abstract class APIGatewayHttpApiV2ProxyFunction<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors)] TStartup> : APIGatewayHttpApiV2ProxyFunction where TStartup : class
{
/// <summary>
/// Default Constructor. The ASP.NET Core Framework will be initialized as part of the construction.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Hosting;
using System.Diagnostics.CodeAnalysis;

namespace Amazon.Lambda.AspNetCoreServer
{
Expand All @@ -8,7 +9,7 @@ namespace Amazon.Lambda.AspNetCoreServer
/// the Lambda function will point to this base class FunctionHandlerAsync method.
/// </summary>
/// <typeparam name ="TStartup">The type containing the startup methods for the application.</typeparam>
public abstract class APIGatewayProxyFunction<TStartup> : APIGatewayProxyFunction where TStartup : class
public abstract class APIGatewayProxyFunction<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors)] TStartup> : APIGatewayProxyFunction where TStartup : class
{
/// <summary>
/// Default Constructor. The ASP.NET Core Framework will be initialized as part of the construction.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,60 +206,6 @@ public void RegisterResponseContentEncodingForContentEncoding(string contentEnco
/// <param name="builder"></param>
protected virtual void Init(IWebHostBuilder builder) { }

/// <summary>
/// Creates the IWebHostBuilder similar to WebHost.CreateDefaultBuilder but replacing the registration of the Kestrel web server with a
/// registration for Lambda.
/// </summary>
/// <returns></returns>
[Obsolete("Functions should migrate to CreateHostBuilder and use IHostBuilder to setup their ASP.NET Core application. In a future major version update of this library support for IWebHostBuilder will be removed for non .NET Core 2.1 Lambda functions.")]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This obsolete method was deleted because it was here to support .NET Core 2.1. The message even said we would delete in the future. The future is now.

protected virtual IWebHostBuilder CreateWebHostBuilder()
{
var builder = new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

if (env.IsDevelopment())
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true);
}
}

config.AddEnvironmentVariables();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));

if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("LAMBDA_TASK_ROOT")))
{
logging.AddConsole();
logging.AddDebug();
}
else
{
logging.AddLambdaLogger(hostingContext.Configuration, "Logging");
}
})
.UseDefaultServiceProvider((hostingContext, options) =>
{
options.ValidateScopes = hostingContext.HostingEnvironment.IsDevelopment();
});

Init(builder);

// Swap out Kestrel as the webserver and use our implementation of IServer
builder.UseLambdaServer();

return builder;
}

/// <summary>
/// Method to initialize the host builder before starting the host. In a typical Web API this is similar to the main function.
Expand Down Expand Up @@ -317,34 +263,17 @@ private protected bool IsStarted
/// </summary>
protected void Start()
{
// For .NET Core 3.1 and above use the IHostBuilder instead of IWebHostBuilder used in .NET Core 2.1. If the user overrode CreateWebHostBuilder
// then fallback to the original .NET Core 2.1 behavior.
if (this.GetType().GetMethod("CreateWebHostBuilder", BindingFlags.NonPublic | BindingFlags.Instance).DeclaringType.FullName.StartsWith("Amazon.Lambda.AspNetCoreServer.AbstractAspNetCoreFunction"))
{
var builder = CreateHostBuilder();
builder.ConfigureServices(services =>
{
Utilities.EnsureLambdaServerRegistered(services);
});

var host = builder.Build();
PostCreateHost(host);

host.Start();
this._hostServices = host.Services;
}
else
var builder = CreateHostBuilder();
builder.ConfigureServices(services =>
{
#pragma warning disable 618
var builder = CreateWebHostBuilder();
#pragma warning restore 618
Utilities.EnsureLambdaServerRegistered(services);
});

var host = builder.Build();
PostCreateWebHost(host);
var host = builder.Build();
PostCreateHost(host);

host.Start();
this._hostServices = host.Services;
}
host.Start();
this._hostServices = host.Services;

_server = this._hostServices.GetService(typeof(Microsoft.AspNetCore.Hosting.Server.IServer)) as LambdaServer;
if (_server == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@

<PropertyGroup>
<Description>Amazon.Lambda.AspNetCoreServer makes it easy to run ASP.NET Core Web API applications as AWS Lambda functions.</Description>
<TargetFrameworks>netcoreapp3.1;net6.0</TargetFrameworks>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<AssemblyTitle>Amazon.Lambda.AspNetCoreServer</AssemblyTitle>
<VersionPrefix>8.1.1</VersionPrefix>
<VersionPrefix>9.0.0</VersionPrefix>
<AssemblyName>Amazon.Lambda.AspNetCoreServer</AssemblyName>
<PackageId>Amazon.Lambda.AspNetCoreServer</PackageId>
<PackageTags>AWS;Amazon;Lambda;aspnetcore</PackageTags>
<LangVersion>Latest</LangVersion>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReadmeFile>README.md</PackageReadmeFile>

<WarningsAsErrorsA>IL2026,IL2067,IL2075,IL2091</WarningsAsErrorsA>
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzerA>true</EnableTrimAnalyzerA>
</PropertyGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Amazon.Lambda.ApplicationLoadBalancerEvents\Amazon.Lambda.ApplicationLoadBalancerEvents.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Hosting;
using System.Diagnostics.CodeAnalysis;

namespace Amazon.Lambda.AspNetCoreServer
{
Expand All @@ -8,7 +9,7 @@ namespace Amazon.Lambda.AspNetCoreServer
/// the Lambda function will point to this base class FunctionHandlerAsync method.
/// </summary>
/// <typeparam name ="TStartup">The type containing the startup methods for the application.</typeparam>
public abstract class ApplicationLoadBalancerFunction<TStartup> : ApplicationLoadBalancerFunction where TStartup : class
public abstract class ApplicationLoadBalancerFunction<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors)] TStartup> : ApplicationLoadBalancerFunction where TStartup : class
{
/// <summary>
/// Default Constructor. The ASP.NET Core Framework will be initialized as part of the construction.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System.Threading;
using System.Threading.Tasks;
using Amazon.Lambda.APIGatewayEvents;
using System.Diagnostics.CodeAnalysis;

namespace Amazon.Lambda.AspNetCoreServer.Internal
{
Expand All @@ -22,12 +23,21 @@ namespace Amazon.Lambda.AspNetCoreServer.Internal
/// </summary>
public static class Utilities
{
/// <summary>
/// Method to make sure the Lambda implementation is the only registered implementaiton of IServer for ASP.NET Core runtime.
normj marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <param name="services"></param>
public static void EnsureLambdaServerRegistered(IServiceCollection services)
{
EnsureLambdaServerRegistered(services, typeof(LambdaServer));
}

public static void EnsureLambdaServerRegistered(IServiceCollection services, Type serverType)
/// <summary>
/// Method to make sure the Lambda implementation is the only registered implementaiton of IServer for ASP.NET Core runtime.
normj marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <param name="services"></param>
/// <param name="serverType"></param>
public static void EnsureLambdaServerRegistered(IServiceCollection services, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type serverType)
{
IList<ServiceDescriptor> toRemove = new List<ServiceDescriptor>();
var serviceDescriptions = services.Where(x => x.ServiceType == typeof(IServer));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<AssemblyName>Amazon.Lambda.Serialization.SystemTextJson</AssemblyName>
<PackageId>Amazon.Lambda.Serialization.SystemTextJson</PackageId>
<PackageTags>AWS;Amazon;Lambda</PackageTags>
<VersionPrefix>2.4.0</VersionPrefix>
<VersionPrefix>2.4.1</VersionPrefix>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public SourceGeneratorLambdaJsonSerializer(Action<JsonSerializerOptions> customi
/// <param name="jsonSerializerContext"></param>
/// <param name="customizer"></param>
/// <param name="jsonWriterCustomizer"></param>
[Obsolete("The method is marked obsolete because the jsonSerializerContext parameter is unlikely to be created with the required JsonSerializerOptions for Lambda serialization. This will trigger confusing NullReferenceException.")]
normj marked this conversation as resolved.
Show resolved Hide resolved
public SourceGeneratorLambdaJsonSerializer(TSGContext jsonSerializerContext, Action<JsonSerializerOptions> customizer = null, Action<JsonWriterOptions> jsonWriterCustomizer = null)
: base(jsonWriterCustomizer)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<AssemblyName>Amazon.Lambda.AspNetCoreServer.Test</AssemblyName>
<OutputType>Library</OutputType>
<PackageId>Amazon.Lambda.AspNetCoreServer.Test</PackageId>
Expand Down
Loading
Loading