Skip to content

Add support for ASP.NET Core 3.0 to Amazon.Lambda.AspNetCoreServer #508

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

Closed
wants to merge 12 commits into from

Conversation

normj
Copy link
Member

@normj normj commented Aug 19, 2019

Issue #, if available:
#481

Description of changes:
Add support for ASP.NET Core 3.0 to Amazon.Lambda.AspNetCoreServer. .NET Core 3.0 will not be an LTS and so will not be supported in Lambda as a built in runtime. It is possible to use .NET Core 3.0 with the Amazon.Lambda.RuntimeSupport NuGet package and Lambda custom runtimes. Check out the following blog post on how to use it. https://aws.amazon.com/blogs/developer/announcing-amazon-lambda-runtimesupport/

For example on how to use Amazon.Lambda.RuntimeSupport with ASP.NET Core 3.0 check out this example. https://github.com/normj/LambdaNETCoreSamples The sample contains a prebuilt NuGet package of Amazon.Lambda.AspNetCoreServer with this PR in the CustomRuntimeAspNetCore30/nuget-cache directory.

Breaking Changes

This PR will be a major version bump as there will be breaking changes to that will affect .NET Core 2.1 ASP.NET Core Lambda function's as well. The breaking change only affect users that override any of the Post methods to customize serialization.

The cause of the breaking changes is Microsoft.AspNetCore.Hosting.Internal.HostingApplication.Context was exposed in some of the virtual methods to customize the serialization. Even though the object was public the ASP.NET team did put it in an Internal namespace and so this library should never have directly used it let alone expose it in some of the virtual methods. In ASP.NET Core 3.0 HostingApplication.Context was moved to Microsoft.AspNetCore.Hosting namespace and marked as internal.

Breaking Change List:

  • protected method CreateContext now returns back object
  • protected method ProcessRequest now passes in context as an object
  • protected virtual method PostCreateContext was removed
    • To customize HttpContext's User property override the PostMarshallHttpAuthenticationFeature method.
    • To customize the items in HttpContext's Items collection override PostMarshallItemsFeatureFeature method.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@davidfowl
Copy link

@Tratcher can you review and give feedback please

@normj
Copy link
Member Author

normj commented Aug 19, 2019

@davidfowl @Tratcher That would be greatly appreciated.

@@ -135,6 +102,40 @@ private protected override void InternalCustomResponseExceptionHandling(HostingA
/// <param name="lambdaContext"></param>
protected override void MarshallRequest(InvokeFeatures features, APIGatewayProxyRequest apiGatewayRequest, ILambdaContext lambdaContext)
{
{
var authFeatures = (IHttpAuthenticationFeature) features;

Choose a reason for hiding this comment

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

This is a weird style to work with the concrete InvokeFeatures type but keep downcasting to the individual features. It'd be cleaner if you removed the explicit implementation prefix. E.g. IHttpAuthenticationFeature.User { get; set; } -> User { get; set; }.

Alternatively, change the APIs to take the abstract IFeatureCollection and call Get<IHttpAuthenticationFeature>() when you want to work with a specific feature. This might not quite match your usage here as you are the one populating the initial values and you know exactly which features are implemented.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree it is weird but at this point I'm not ready to change the design. I actually think I got this from the ASP.NET Core repo back in the 1.0 days because I wouldn't have thought to do this way.

@@ -224,7 +228,7 @@ protected void Start()
/// Creates a <see cref="HostingApplication.Context"/> object using the <see cref="LambdaServer"/> field in the class.

Choose a reason for hiding this comment

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

The IServer check above could be done more effectively between Build and Start. If they didn't call UseApiGateway then Start is likely to fail for a variety of false positives (e.g. can't start the default Kestrel server).

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved the call to UseLambdaServer to after the point the end user could customize the IWebHostBuilder. This also pointed out that the comment should say UseLambdaServer since UseApiGateway is obsolete

@@ -45,6 +45,14 @@ protected ApplicationLoadBalancerFunction(StartupMode startupMode)
/// <inheritdoc/>
protected override void MarshallRequest(InvokeFeatures features, ApplicationLoadBalancerRequest lambdaRequest, ILambdaContext lambdaContext)
{
{
var requestFeatures = (IHttpAuthenticationFeature) features;

Choose a reason for hiding this comment

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

Is the downcast even required here? That should be implicit.

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed


{
var itemFeatures = (IItemsFeature) features;
itemFeatures.Items = new Dictionary<object, object>();

Choose a reason for hiding this comment

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

We use a customized dictionary that doesn't throw KeyNotFoundException for any missing elements. Much easier for developers to consume.
https://github.com/aspnet/AspNetCore/blob/ab02951b37ac0cb09f8f6c3ed0280b46d89b06e0/src/Http/Http/src/Internal/ItemsDictionary.cs#L23-L24

Copy link
Member Author

Choose a reason for hiding this comment

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

Since ItemsDictionary is an internal I have copied the code into this repo to give the same experience.

long? count,
CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException("SendFileAsync is not implemented for Serverless ASP.NET Core functions");

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, I have copied this default implementation.

throw new NotImplementedException("SendFileAsync is not implemented for Serverless ASP.NET Core functions");
}

Task IHttpResponseBodyFeature.StartAsync(CancellationToken cancellationToken = default(CancellationToken))

Choose a reason for hiding this comment

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

This should at least trigger OnStarting events.

Copy link
Member Author

Choose a reason for hiding this comment

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

OnStarting events are triggered in the AbstractAspNetCoreFunction.ProcessRequest method. The starting and complete events are a little weird in this context because they are only triggered before and after the response from ASP.NET Core is marshaled into the Lambda request. Nothing is sent to the client until the function is complete and the Lambda response is returned to either API Gateway or Application Load Balancer.

@normj
Copy link
Member Author

normj commented Oct 24, 2019

Manually merged into dev

@normj normj closed this Oct 24, 2019
@normj normj deleted the aspnetcore30-support branch December 19, 2019 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants