-
Notifications
You must be signed in to change notification settings - Fork 499
Support API Gateway websocket api via LambdaServer #1804
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
Merged
Merged
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
25c0c33
Support API Gateway websocket api via LambdaServer
wiowou 1f5717a
Merge pull request #2229 from aws/dev
philasmar ad0ebab
update permissions (#2231) (#2232)
GarrettBeatty 1dbfbf2
Merge branch 'dev'
aws-sdk-dotnet-automation a4310dc
Merge branch 'dev'
aws-sdk-dotnet-automation 0548eb3
Dev (#2248)
GarrettBeatty 3f6de4a
Merge branch 'dev'
aws-sdk-dotnet-automation fd18ef2
Merge pull request #2258 from aws/dev
philasmar 6e7c60b
Merge branch 'dev'
aws-sdk-dotnet-automation 15145bf
Merge branch 'dev'
aws-sdk-dotnet-automation bc0c745
Merge branch 'dev'
aws-sdk-dotnet-automation 281133d
Merge branch 'dev'
aws-sdk-dotnet-automation e61e9a5
Merge branch 'dev'
aws-sdk-dotnet-automation 3af4abf
Merge branch 'dev'
aws-sdk-dotnet-automation c28fcfa
Merge branch 'dev'
aws-sdk-dotnet-automation f3cf8cc
Merge pull request #2296 from aws/dev
philasmar dc91547
Merge pull request #2307 from aws/dev
philasmar a5b74f6
Merge branch 'dev'
aws-sdk-dotnet-automation 52d0de4
Merge branch 'dev'
aws-sdk-dotnet-automation cb78042
Merge branch 'dev'
aws-sdk-dotnet-automation 64a47bb
Merge branch 'dev'
aws-sdk-dotnet-automation e9d0d74
Merge branch 'dev'
aws-sdk-dotnet-automation caea55b
Merge pull request #2334 from aws/dev
philasmar 5820339
Merge branch 'dev'
aws-sdk-dotnet-automation ffa4585
Merge branch 'dev'
aws-sdk-dotnet-automation 35b2e8f
Merge branch 'dev'
aws-sdk-dotnet-automation c63d743
Merge branch 'dev'
aws-sdk-dotnet-automation dfbb7ac
Merge branch 'dev'
aws-sdk-dotnet-automation 5de51e0
Merge branch 'dev'
aws-sdk-dotnet-automation 40cdd7f
pr fixes: api gateway websocket api
4c22317
fixed merge conflict. Logical changes remain
0fc8136
fix lambda runtime support server
5ad44ab
simplify calls
acd15d7
pr fixes: api gateway websocket api
89a6b33
Merge branch 'dev' into websocket
GarrettBeatty 26b9cd0
Fix websocket Hosting wiring and simplify MinimalApi
GarrettBeatty 05ae11c
Add autover change file for websocket support
GarrettBeatty File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "Projects": [ | ||
| { | ||
| "Name": "Amazon.Lambda.AspNetCoreServer", | ||
| "Type": "Minor", | ||
| "ChangelogMessages": [ | ||
| "Add APIGatewayWebsocketApiProxyFunction (and TStartup variant) so API Gateway WebSocket APIs can be hosted via LambdaServer (DI, controllers). WebSocket events are dispatched as POST requests whose path is the RouteKey, allowing controller actions like [HttpPost(\"$default\")] to handle them.", | ||
| "Expose ParseHttpPath, ParseHttpMethod, and AddMissingRequestHeaders as protected virtual hooks on APIGatewayProxyFunction so subclasses can customize how the API Gateway request is mapped onto the ASP.NET Core request feature." | ||
| ] | ||
| }, | ||
| { | ||
| "Name": "Amazon.Lambda.AspNetCoreServer.Hosting", | ||
| "Type": "Minor", | ||
| "ChangelogMessages": [ | ||
| "Add LambdaEventSource.WebsocketApi so AddAWSLambdaHosting can wire ASP.NET Core minimal APIs and controllers up to API Gateway WebSocket events." | ||
| ] | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -464,4 +464,70 @@ protected override void PostMarshallItemsFeatureFeature(IItemsFeature aspNetCore | |
| } | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// IServer for handling Lambda events from an API Gateway Websocket API. | ||
| /// </summary> | ||
| public class APIGatewayWebsocketApiLambdaRuntimeSupportServer : APIGatewayRestApiLambdaRuntimeSupportServer | ||
| { | ||
| /// <summary> | ||
| /// Create instances | ||
| /// </summary> | ||
| /// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param> | ||
| public APIGatewayWebsocketApiLambdaRuntimeSupportServer(IServiceProvider serviceProvider) | ||
| : base(serviceProvider) | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates HandlerWrapper for processing events from API Gateway Websocket API | ||
| /// </summary> | ||
| /// <param name="serviceProvider"></param> | ||
| /// <returns></returns> | ||
| protected override HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider) | ||
| { | ||
| var handler = new APIGatewayWebsocketMinimalApi(serviceProvider); | ||
| #pragma warning disable CA2252 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we need this?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 46dc956#diff-dec0ad4ae2f92f72fd5cabb763659b9a222002446a2e7fb9c77120d231c18d88R363 from the response streaming pr |
||
| var hostingOptions = serviceProvider.GetService<HostingOptions>(); | ||
| handler.EnableResponseStreaming = hostingOptions?.EnableResponseStreaming ?? false; | ||
| #pragma warning restore CA2252 | ||
| Func<APIGatewayEvents.APIGatewayProxyRequest, ILambdaContext, Task<APIGatewayEvents.APIGatewayProxyResponse>> bufferedHandler = handler.FunctionHandlerAsync; | ||
| return HandlerWrapper.GetHandlerWrapper(bufferedHandler, Serializer); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// MinimalApi variant of APIGatewayWebsocketApiProxyFunction. Reuses the REST API MinimalApi plumbing | ||
| /// (snapshot collectors, hosting options, PostMarshall callbacks) and applies the websocket-specific | ||
| /// request transformations on top. | ||
| /// </summary> | ||
| public class APIGatewayWebsocketMinimalApi : APIGatewayRestApiLambdaRuntimeSupportServer.APIGatewayRestApiMinimalApi | ||
| { | ||
| /// <summary> | ||
| /// Create instances | ||
| /// </summary> | ||
| /// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param> | ||
| public APIGatewayWebsocketMinimalApi(IServiceProvider serviceProvider) | ||
| : base(serviceProvider) | ||
| { | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| protected override string ParseHttpPath(APIGatewayEvents.APIGatewayProxyRequest apiGatewayRequest) | ||
| => "/" + System.Net.WebUtility.UrlDecode(apiGatewayRequest.RequestContext.RouteKey ?? string.Empty); | ||
|
|
||
| /// <inheritdoc/> | ||
| protected override string ParseHttpMethod(APIGatewayEvents.APIGatewayProxyRequest apiGatewayRequest) => "POST"; | ||
|
|
||
| /// <inheritdoc/> | ||
| protected override Microsoft.AspNetCore.Http.IHeaderDictionary AddMissingRequestHeaders(APIGatewayEvents.APIGatewayProxyRequest apiGatewayRequest, Microsoft.AspNetCore.Http.IHeaderDictionary headers) | ||
| { | ||
| headers = base.AddMissingRequestHeaders(apiGatewayRequest, headers); | ||
| if (!headers.ContainsKey("Content-Type")) | ||
| { | ||
| headers["Content-Type"] = "application/json"; | ||
| } | ||
| return headers; | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
Libraries/src/Amazon.Lambda.AspNetCoreServer/APIGatewayWebsocketApiProxyFunction.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| using System; | ||
|
|
||
| using Microsoft.AspNetCore.Http; | ||
|
|
||
| using Amazon.Lambda.APIGatewayEvents; | ||
| using Amazon.Lambda.AspNetCoreServer.Internal; | ||
|
|
||
| namespace Amazon.Lambda.AspNetCoreServer | ||
| { | ||
| /// <summary> | ||
| /// Base class for ASP.NET Core Lambda functions invoked by API Gateway Websocket APIs. | ||
| /// | ||
| /// Websocket events are surfaced as POST requests whose path is the RouteKey, so the same Lambda | ||
| /// should be referenced by every websocket route that has a matching ASP.NET Core controller route | ||
| /// (e.g. <c>[HttpPost("$default")]</c>, <c>[HttpPost("$connect")]</c>) for the ASP.NET Core IServer | ||
| /// to successfully dispatch requests. | ||
| /// </summary> | ||
| public abstract class APIGatewayWebsocketApiProxyFunction : APIGatewayProxyFunction | ||
| { | ||
| /// <summary> | ||
| /// Default constructor. The ASP.NET Core framework is initialized as part of construction. | ||
| /// </summary> | ||
| protected APIGatewayWebsocketApiProxyFunction() | ||
| : base() | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Constructor that lets the caller defer ASP.NET Core framework initialization until the first request. | ||
| /// </summary> | ||
| /// <param name="startupMode">Configures when the ASP.NET Core framework is initialized.</param> | ||
| protected APIGatewayWebsocketApiProxyFunction(StartupMode startupMode) | ||
| : base(startupMode) | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Constructor used by Amazon.Lambda.AspNetCoreServer.Hosting to support ASP.NET Core projects using the Minimal API style. | ||
| /// </summary> | ||
| /// <param name="hostedServices">The service provider built by the ASP.NET Core host.</param> | ||
| protected APIGatewayWebsocketApiProxyFunction(IServiceProvider hostedServices) | ||
| : base(hostedServices) | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Maps the websocket event to a request path of <c>/{RouteKey}</c> so ASP.NET Core can dispatch to a controller | ||
| /// route declared with <c>[HttpPost("{RouteKey}")]</c>. | ||
| /// </summary> | ||
| protected override string ParseHttpPath(APIGatewayProxyRequest apiGatewayRequest) | ||
| { | ||
| return "/" + Utilities.DecodeResourcePath(apiGatewayRequest.RequestContext.RouteKey); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Always returns <c>POST</c> for websocket events. Combined with <see cref="ParseHttpPath"/>, this lets the same | ||
| /// Lambda route every websocket event into an ASP.NET Core controller action. | ||
| /// </summary> | ||
| protected override string ParseHttpMethod(APIGatewayProxyRequest apiGatewayRequest) | ||
| { | ||
| return "POST"; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Adds a default <c>Content-Type</c> of <c>application/json</c> when API Gateway did not supply one. | ||
| /// Websocket message payloads are typically JSON, but the gateway does not set headers automatically. | ||
| /// </summary> | ||
| protected override IHeaderDictionary AddMissingRequestHeaders(APIGatewayProxyRequest apiGatewayRequest, IHeaderDictionary headers) | ||
| { | ||
| headers = base.AddMissingRequestHeaders(apiGatewayRequest, headers); | ||
| if (!headers.ContainsKey("Content-Type")) | ||
| { | ||
| headers["Content-Type"] = "application/json"; | ||
| } | ||
| return headers; | ||
| } | ||
| } | ||
| } |
36 changes: 36 additions & 0 deletions
36
...aries/src/Amazon.Lambda.AspNetCoreServer/APIGatewayWebsocketApiProxyFunction{TStartup}.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| using Microsoft.AspNetCore.Hosting; | ||
| using System.Diagnostics.CodeAnalysis; | ||
|
|
||
| namespace Amazon.Lambda.AspNetCoreServer | ||
| { | ||
| /// <summary> | ||
| /// Strongly-typed variant of <see cref="APIGatewayWebsocketApiProxyFunction"/> that wires up an ASP.NET Core Startup class. | ||
| /// The Lambda function handler should point at the inherited <c>FunctionHandlerAsync</c> method. | ||
| /// </summary> | ||
|
wiowou marked this conversation as resolved.
|
||
| /// <typeparam name ="TStartup">The type containing the startup methods for the application.</typeparam> | ||
| public abstract class APIGatewayWebsocketApiProxyFunction<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors)] TStartup> : APIGatewayWebsocketApiProxyFunction where TStartup : class | ||
| { | ||
| /// <summary> | ||
| /// Default constructor. The ASP.NET Core framework is initialized as part of construction. | ||
| /// </summary> | ||
| protected APIGatewayWebsocketApiProxyFunction() | ||
| : base() | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Constructor that lets the caller defer ASP.NET Core framework initialization until the first request. | ||
| /// </summary> | ||
|
GarrettBeatty marked this conversation as resolved.
|
||
| /// <param name="startupMode">Configures when the ASP.NET Core framework is initialized.</param> | ||
| protected APIGatewayWebsocketApiProxyFunction(StartupMode startupMode) | ||
| : base(startupMode) | ||
| { | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| protected override void Init(IWebHostBuilder builder) | ||
| { | ||
| builder.UseStartup<TStartup>(); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.