How to Use LocalStack for Seamless AWS Development in .NET
LocalStack is a fully functional local AWS cloud stack that lets you emulate AWS services directly on your machine. Let's learn how to set up and run your .NET application locally on LocalStack.
Table of Contents
Testing against live AWS services can be costly, time-consuming, and sometimes impractical when building cloud-based applications.
This is where LocalStack comes in.
LocalStack is a fully functional local AWS cloud stack that lets you emulate AWS services directly on your machine.
In this article, you’ll learn how to:
- Set up and use LocalStack to simulate AWS services locally.
- Build a .NET application that interacts with DynamoDB, SQS, and Lambda.
- Configure LocalStack and integrate it into your development workflow.
- Test and debug your application locally without deploying it to AWS.
Let’s dive in!
Thanks to AWS for sponsoring this post in my .NET on AWS Series
What is LocalStack?
LocalStack is an open-source platform that provides a local environment for simulating over 80 AWS services, such as DynamoDB, SQS, and Lambda.
It allows developers to work on applications without needing an active AWS account or incurring infrastructure costs during development.
It enables faster, cost-effective development and testing by providing lightweight, in-memory implementations of cloud services. This allows developers to develop and validate cloud-native applications locally with minimal infrastructure overhead.
Setting Up LocalStack
The fastest way to get started with LocalStack is through the LocalStack CLI, which allows you to manage and start LocalStack from your command line. Ensure you have Docker installed before proceeding, as LocalStack runs inside a Docker container.
In addition to the CLI, there are several other options for managing your LocalStack instance:
- LocalStack Desktop: Provides a desktop interface for interacting with your LocalStack instance via a UI.
- LocalStack Docker Extension: Integrates with Docker Desktop, enabling you to manage LocalStack directly from the Docker interface.
- Docker Compose: Use Docker Compose to configure and start LocalStack with multiple services in a containerized setup.
- Docker CLI: Start and manage LocalStack directly using the Docker CLI.
- Helm: Deploy LocalStack within a Kubernetes cluster using Helm.
These options all run LocalStack inside a Docker container, offering flexibility in how you choose to manage your local environment.
Check out the documentation here to get set up.
Creating AWS Resources in LocalStack
LocalStack offers different ways you can create resources.
Most options that's available to create resources in AWS, also works with LocalStack.
Below, I show you how to create resources using the GUI and the CLI.
In a future post, we will explore how you can seamlessly provision resources using AWS CDK.
Creating Resources Using LocalStack GUI
The LocalStack GUI allows you to provision resources.
Let's use it to create our DynamoDB table.
Navigate to Resource Browser → DynamoDB and click 'Create' at the bottom of the UI.
This prompts you to enter the details of the table, such as name, keys, etc.
Clicking Submit creates the resource in your LocalStack instance.
Creating Resources Using LocalStack CLI
You can also create resources using the AWS CLI.
I am using the default LocalStack endpoint URL here which is localhost:4566
aws --endpoint-url=http://localhost:4566 sqs create-queue --queue-name 'weather-data'
Alternatively, you can install the LocalStack AWS CLI, which provides a wrapper over the AWS CLI.
The above command can now be simplified using the below.
awslocal sqs create-queue --queue-name 'weather-data'
This creates a SQS resource in your LocalStack instance.
Configuring .NET App to Connect To LocalStack
Now that we have a DynamoDB Table and an SQS instance on our LocalStack instance let's see how we can connect to this from our .NET application.
Based on your preferences, we can use a few options to set up our .NET application to talk to LocalStack resources.
Configuring .NET AWS Clients Individually
You can configure the .NET clients individually when registering them in the application container (or wherever you are instantiating it).
if (builder.Environment.IsDevelopment())
{
var localStackUrl = "http://localhost:4566";
var localStackRegion = "ap-southeast-2";
builder.Services.AddSingleton<IAmazonDynamoDB>(_ => new
AmazonDynamoDBClient(new AmazonDynamoDBConfig
{
ServiceURL = localStackUrl,
AuthenticationRegion = localStackRegion
}));
}
else
{
builder.Services.AddAWSService<IAmazonDynamoDB>();
}
The above code injects a different instance of AmazonDynamoDBClient
by overriding the ServiceURL
and the AuthenticationRegion
properties on the configuration object.
This ensures the app talks to the LocalStack instance of DynamoDB when running in a local development environment.
Configuring .NET AWS Client Globally using AWS Options
Configuring each of the clients individually can soon become messy and tedious.
Also, I wouldn't say I like this approach since it is a lot of conditional code based on the environment.
AWS provides an easier way to override the configurations at a global level, by overriding the AWS Options globally.
var options = builder.Configuration.GetAWSOptions();
options.DefaultClientConfig.ServiceURL = "http://localhost:4566";
options.DefaultClientConfig.AuthenticationRegion = "ap-southeast-2";
builder.Services.AddDefaultAWSOptions(options);
This is quickly done by getting the AWSOptions using the GetAWSOptions
call and then updating the ServiceURL
and AuthenticationRegion
properties on it and registering it back into the container.
Any .NET client registered into the container will now use this default AWS Options object when creating a client instance.
Configuring AWS Options using appsettings.json file
AWS also provides a way to override the AWS Options using the appsettings.json file.
You can use the below configuration to override the ServiceURL
and default region.
"AWS": {
"Region": "ap-southeast-2",
"ServiceURL": "http://localhost:4566",
"AuthenticationRegion": "ap-southeast-2"
}
Now, for LocalStack, I will add this configuration to my appsettings.Development.json
file. The configuration will only be applied when I run the app on my local development environment.
Deploying .NET Lambda Functions to LocalStack
You can deploy Lambda functions to the local stack using the GUI or the CLI.
First, we must ensure our lambda function is packaged into a deployable unit.
You can do this using the dotnet lambda CLI.
dotnet lambda package
To deploy the package Lambda Function to LocalStack we can use the aws CLI as below.
awslocal lambda create-function `
--function-name weatherforecast-service `
--runtime dotnet8 `
--zip-file "fileb://bin/Release/net8.0/WeatherForecast.Service.zip" `
--handler "WeatherForecast::WeatherForecast.Function::FunctionHandler" `
--role arn:aws:iam::000000000000:role/lambda-role
We must use the fileb://
format and provide the path to the Lambda artifact packaged in the previous step.
This deploys the Lambda Function to LocalStack.
Setting up SQS Trigger on LocalStack for Lambda Functions
To wire up Lambda Triggers, in this case every time a message comes into our SQS let's again use the LocalStack CLI.
awslocal lambda create-event-source-mapping `
--function-name weatherforecast-service `
--batch-size 10 `
--event-source-arn arn:aws:sqs:ap-southeast-2:000000000000:weather-data
Any time a new message comes to the weather-data
SQS queue it will automatically trigger our Lambda Function.
You can find the complete source code for this here.
Rahul Nath Newsletter
Join the newsletter to receive the latest updates in your inbox.