Running Serverless ASP.NET Core Web APIs with Amazon Lambda

Running Serverless ASP.NET Core Web APIs with Amazon LambdaMore Info

During our recent AWS re:Invent presentation on .NET Core support for AWS Lambda, we showcased an exciting demonstration of running an ASP.NET Core Web API using Lambda. This was accomplished using the NuGet package Amazon.Lambda.AspNetCoreServer, which is currently in preview, alongside Amazon API Gateway. We are pleased to announce the release of a new AWS Serverless blueprint that you can find in Visual Studio or through our Yeoman generator, which simplifies the process of setting up an ASP.NET Core Web API project as a Lambda project.

How Does It Function?

In a typical deployment of an ASP.NET Core application, either IIS or NGINX serves as the front end, forwarding requests to the Kestrel web server. Kestrel then marshals these requests into the ASP.NET Core hosting framework.

When transforming an ASP.NET Core application into an AWS Serverless application, API Gateway takes the place of IIS, while Kestrel is substituted with a Lambda function from the Amazon.Lambda.AspNetCoreServer package that manages the request routing into the ASP.NET Core hosting framework.

The Blueprint

The blueprint generates a project that closely resembles a typical .NET Core ASP.NET Core Web Application created with the Web API template. The notable difference is that instead of the Program.cs file containing a Main function to bootstrap the ASP.NET Core framework, the blueprint includes LambdaEntryPoint.cs, which performs the same task.

public class LambdaEntryPoint : Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
{
    protected override void Init(IWebHostBuilder builder)
    {
        builder
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup()
            .UseApiGateway();
    }
}

The Lambda function utilizes the base class. The function handler is defined in the AWS CloudFormation template named serverless.template, which follows the format ::.LambdaEntryPoint::FunctionHandlerAsync. The blueprint also includes LocalEntryPoint.cs, which functions similarly to the original Program.cs file, allowing you to develop and run your application locally before deploying it to Lambda.

The project structure retains the standard files typical of an ASP.NET Core application, featuring two Web API controllers: the example ValuesController and an S3ProxyController that illustrates using HTTP GET, PUT, and DELETE requests with the AWS SDK for .NET to interact with an Amazon S3 bucket. The S3 bucket name is sourced from the Configuration object, allowing you to configure it within the appsettings.json for local development.

{
  "AppS3Bucket": "ExampleBucketName"
}

The Configuration object is established using environment variables.

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}

Upon deployment, the serverless.template is utilized to create the S3 bucket and pass its name to the Lambda function as an environment variable.

...
"Get" : {
  "Type" : "AWS::Serverless::Function",
  "Properties": {
    "Handler": "AspNetCoreWithLambda::AspNetCoreWithLambda.LambdaEntryPoint::FunctionHandlerAsync",
    "Runtime": "dotnetcore1.0",
    "CodeUri": "",
    "MemorySize": 256,
    "Timeout": 30,
    "Role": null,
    "Policies": [ "AWSLambdaFullAccess" ],
    "Environment" : {
      "Variables" : {
        "AppS3Bucket" : { "Fn::If" : ["CreateS3Bucket", {"Ref":"Bucket"}, { "Ref" : "BucketName" } ] }
      }
    },
    "Events": {
      "PutResource": {
        "Type": "Api",
        "Properties": {
          "Path": "/{proxy+}",
          "Method": "ANY"
        }
      }
    }
  }
},
...

Logging

ASP.NET Core features a new logging framework. To facilitate integration with this framework, we have released the NuGet package Amazon.Lambda.Logging.AspNetCore. This logging provider allows any code utilizing the ILogger interface to send log messages to the respective Amazon CloudWatch log group for the Lambda function. In cases where it is executed outside a Lambda function, log messages are output to the console.

The blueprint enables this provider in Startup.cs, where other services are configured.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddLambdaLogger(Configuration.GetLambdaLoggerOptions());
    app.UseMvc();
}

The following snippet illustrates the call to GetLambdaLoggerOptions from the Configuration object, which retrieves settings for what messages are logged to CloudWatch Logs. The appsettings.json file in the blueprint is configured to log messages from classes within the Microsoft namespace at the informational level and above; for all other messages, it logs debug-level messages and higher.

{
  "Lambda.Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft": "Information"
    }
  },
  ...
}

For further information regarding this package, refer to their GitHub repository.

Deployment

Deploying the ASP.NET Core Web API follows the same process outlined in our previous post about AWS Serverless projects.

Once deployed, a single Lambda function and an API Gateway REST API are established to direct all requests to the Lambda function. The function utilizes the ASP.NET Core framework to route to the appropriate Web API controller. You can validate the deployment by accessing the two controllers via the AWS Serverless URL available in the CloudFormation stack view.

<aws-serverless-url>/api/values – Example controller
<aws-serverless-url>/api/s3proxy – S3 Proxy controller.

We are thrilled about the potential of running ASP.NET Core applications on AWS Lambda. The ability to run the ASP.NET Core framework on Lambda opens up numerous opportunities. The Amazon.Lambda.AspNetCoreServer package is still in preview as we explore these opportunities. I highly encourage .NET developers to review this blueprint and the Amazon.Lambda.AspNetCoreServer package and to share feedback on our GitHub repository, or visit this excellent resource for more information.

For further insights on this topic, check out this authoritative source.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *