For a recent set of .NET Core based microservices I have found myself using AWS DynamoDB as a data store. I recently discovered that AWS provides (and have done for 5 years!) a local version of DynamoDB which is perfect for testing applications offline and without the need to set up actual DynamoDB tables in the cloud. This can reduce the complexity of local development and reduce the costs associated with spinning up development DynamoDB tables. Recently, AWS added a Docker image that makes running DynamoDB locally really straightforward.
In this post, I will demonstrate how to get started with the local AWS DynamoDB Docker image and a basic ASP.NET Core application which can be conditionally configured to use the local version when in development.
AWS DynamoDB Docker Image
NOTE: You will require Docker to be installed and running locally on your development machine in order to follow along!
The first step is to pull the DynamoDB Docker image down to your development machine. This can be done by running the docker pull amazon/dynamodb-local command. After a short time, you should see the pull command complete successfully…
Now that we have the image available we can start a container instance using the docker run -p 8000:8000 amazon/dynamodb-local command…
This will start a container using the image that we previously pulled down. We have chosen to publish port 8000 from the container to our host machine on its port 8000. If this conflicts with other applications on your machine, you can specify a different host port number.
If you prefer to run the container without the interactive output then I suggest running in detached mode by adding the -d argument….
docker run -p 8000:8000 -d amazon/dynamodb-local.
As this point, we have a local instance of DynamoDB running in a container, available on our host machine on port 8000.
Utilising the local DynamoDB from an ASP.NET Core application
Next, we’re going to create a basic application to test the local DynamoDB instance. I’ve included the full sample on GitHub as a starting point. This sample was created using the basic ASP.NET Core API template available as part of the SDK.
NOTE: The sample does not include production-ready code. I’ve put together a very basic API application that allows us to write, read and delete from DynamoDB. Those actions are based on the AWS .NET Core SDK samples. The key thing I want to demonstrate is not how to read, write and delete from DynamoDB, but more specifically, how to include some configuration to enable the use of the local DynamoDB container when in development.
Adding NuGet packages
After creating a default project from the API template, we need to add two NuGet packages to our project. You can do this via the command line, NuGet package manager or by editing the csproj file directly.
We need to bring in the AWSSDK.DynamoDBv2 and AWSSDK.Extensions.NETCore.Setup packages.
AWSSDK.DynamoDBv2 adds the necessary support to interact with DynamoDB via the AWS .NET SDK. The AWSSDK.Extensions.NETCore.Setup package includes extension methods to support the configuration and registration of the AWS services with the Microsoft dependency injection container used in .NET Core applications.
After registering these, our project file looks something like this…
Next, we’ll add some configuration values to our appsettings.json file. These will support both the default AWS SDK behaviour as well as options to control running the application against the local DynamoDB container…
Here we’ve added an AWS section which includes the AWS region we wish to use. This will be used by the AWS SDK when running against the actual AWS DynamoDB service. We also have a DynamoDB section which defines a setting to control whether the local DynamoDB is used. By default we’re going to set this to false for now.
In order to support using the local DynamoDB when in development we’ll override the configuration values using an appsettings.Development.json file…
By default, ASP.NET Core loads the configuration for applications from a predetermined sequence of sources. In our case, when the application starts under the development environment (the default when debugging from Visual Studio) it will override previous configuration values using the settings from this additional JSON file. Here we have set the “LocalMode” to true and included a service URL for the local DynamoDB instance. We’ve specified the value as “http://localhost:8000” but if you chose to run the container on a different host port, you can update this accordingly.
Register the DynamoDB Services
Inside our Startup class, we now need to register the DynamoDB service. We’re going to do this conditionally, based on the configuration. The code for our ConfigureServices method looks like this…
First, we get the DynamoDb section from the application configuration. When running under the development environment (which will be the case when debugging with Visual Studio) the final values will be those that we set in our appsettings.Development.json file.
We then access the value of the “LocalMode” setting so that we can conditionally register the AWS DyanmoDB service.
If the LocalMode is true, we will manually register a service for the IAmazonDynamoDB interface. Here we use the overload that lets us provide an implementation factory that will return the actual implementation. In our case, we create an AmazonDynamoDBConfig instance, passing in the LocalServiceUrl from configuration. We then create and return the AmazonDynamoDBClient using that configuration. We have registered this as a singleton so this code will run once when the service is first needed.
If the LocalMode is false, instead we will use the AWS SDK helper method to add the service by calling AddAWSService. This is available because we included the AWSSDK.Extensions.NETCore.Setup package.
Reading, Writing and Deleting from DynamoDB
Now that we have the IAmazonDynamoDB registered in our application we can require it to be injected by the Microsoft dependency injection whenever we wish to work with AWS DynamoDB. In development, we’ll be given an implementation which will talk to the local DynamoDB running in Docker. In all other cases, it will attempt to reach the live AWS DynamoDB service. In the latter case, the AWS SDK will handle the authentication to reach the service. I haven’t described it here but you will need to have configured the credentials in one of the predefined locations for the .NET SDK to be able to connect to AWS.
I won’t show the specific code used to work with DynamoDB in this post, as it’s beyond the scope of what I want to demonstrate. In short; you can inject the IAmazonDynamoDB into a controller, for example, to provide your actions access to DynamoDB via the SDK. If you want to see this code (note, this is not production ready code) you can view the ValuesController in my sample.
Running the Sample
At this point, we can start our sample and debug it via Visual Studio. Our development appsettings will take effect and the application will start with the SDK configured to use the local DynamoDB Docker container.
My complete sample includes some basic actions that can be used to read, write and delete from the DynamoDB. If you’re running the sample for the first time, you’ll need to call the Initialise action (by issuing a GET request to the /api/values/init endpoint) to create the required table. Again, this is not a production ready sample but it is enough to demonstrate using the configured SDK to access either the local or the real DynamoDb service.
In this post, we’ve explored how we can easily use Docker to spin up a local instance of DynamoDB on our development machine. We then created a basic ASP.NET Core application which used configuration to determine whether to connect to the actual AWS service, or whether to use the local instance running inside a Docker container. This is controlled by registering the appropriately configured SDK service with the Microsoft dependency injection container. After the service is registered, the actual code used to work with AWS DynamoDB via the SDK requires no further changes.