Part 3 - Implement IDistributedCache for DynamoDB

Now we’re going to add our own implementation of IDistributedCache in order to store session data in DynamoDB rather than in memory, so that it will survive an instance or process failure, and be available to other applications. It’s also useful to share session state between multiple copies of the same web application, which can be enable by completing the optional lab exercise after completing this section.

Follow the steps below to add an implementation of IDistributedCache and wire it up:

The zipped file contains the following three files:  
• DynamoDbCache.cs  
• DynamoDbCacheOptions.cs  
• DynamoDbCacheServiceCollectionExtensions.cs

2. In the Visual Studio Solution Explorer, right-click your project and choose, Add New Folder. Name the new folder, “Session” (no quotes).

3. Still in Solution Explorer, right-click the new Session folder and choose, Open Folder in File Explorer to display the folder in Windows Explorer.

4. Copy the three files you extracted from the zipped file earlier into the Session folder. Verify that they show up in Solution Explorer.

5. Open the DynamoDbCache.cs file, and you will notice that some types (such as IAmazonDynamoDB) used in the DynamoDbCache class are underlined in red, because the assemblies they depend on aren’t added to our project yet.

6. Right-click your project in Solution Explorer and choose, “Manage NuGet Packages” to open the NuGet package pane.

7. Click the “Browse” tab, and search for, “AWSSDK.DynamoDBv2”. Select that package in the results list, then click the “Install” button in the details view on the right. Click “Accept” at the license prompt. See Figure 6.

Figure 6 - NuGet Package Manager with DynamoDBv2 Package

8. Follow the same steps to add the package AWSSDK.Extensions.NETCore.Setup.

9. After the AWSSDK.DynamoDBv2 package has installed, return to the code view of DynamoDbCache.cs. There should be no code warnings now as the dependencies are now present. If you still see code warnings, try rebuilding the project.

10. Review the code in each of the three files to see what it does:

A.    *DynamoDbCache.cs* This class implements the interface IDistributedCache. In the constructor, it instantiates a DynamoDB client, and a Table, and loads that Table with the table definition from DynamoDB. The constructor also reads options, if any, for the TTL field, table name, and session timeout.  

    The class implements methods for Get, Set, Remove, Refresh, and async versions of each of them also. In fact, the non-async versions (synchronous versions) merely wrap the async versions and wait for the result (if not void).  

    The method GetAsync shows how easy it is to read an item from DynamoDB using table.GetItemAsync(key) where key is the partition key of the item we're fetching.  

    It's important to remember that calls to Get/GetAsync, Set/SetAsync and the other methods are made by the Session middleware, not by our own code. The Session middleware base64-encodes the state bag (which is serialized as JSON) and passes it as byte arrays. In the SetAsync method, you can see we store that byte array as a single attribute, and add attributes for the partition key (we are using the session ID for this), the TTL, and a CreateDate (which may be useful for analytics or other purposes).  

    *Note: This is example code for use with this lab, and should not be considered production-ready. There is no error handling, testing, or other features required for production applications.*

B.  *DynamoDbCacheOptions.cs* This class provides a way to pass options from the Startup class, where we wire it up, to the actual DynamoDbCache class. This sample code for our lab has options for the table name, the TTL attribute, and the session timeout in minutes, with default values for each.

C.  *DynamoDbCacheServiceCollectionExtensions.cs* This class has a single extension method that we can call on the services collection in Startup to add a singleton instance of DynamoDbCache.

11. Open the Startup.cs file again, and find the ConfigureServices method.

12. Add the following code just before the call to services.AddSession. The code below which will add a singleton instance of DynamoDbCache to the services collection, as well as register the type IAmazonDynamoDB with the ASP.NET Core dependency injection middleware:

   services.AddDistributedDynamoDbCache(o => { o.TableName = "LabSessionState"; }); services.AddAWSService<IAmazonDynamoDB>();

13. Add the using statement, using Amazon.DynamoDBv2; to the top of the file.

14. Build and run the application again locally. Assuming your local AWS profile has permissions to read and write to the DynamoDB table LabSessionState, the view counter should work as before.

Note: If the services.AddAWSService line is underlined in red, ensure you have added the NuGet package from step 8 of this section.

15. In your browser, navigate back to the AWS DynamoDB console, and click on the table you created earlier, LabSessionState.

16. Click the “Items” tab to display the items in the table. If nothing appears, try clicking the refresh button:


17. You should see one item in the table, with attributes for SessionId, CreateDate, ExpiryType, Session, and TTL. Hover over the TTL attribute to see the translation to UTC and local times.

18. Click the item (click the SessionId value for the item) to display all the attributes and their values. See Figure 7 for an example.

Figure 7 - DynamoDB Item in Edit dialog

Note: You can use the base64 decode function at to see some of the contents of the “Session” attribute. You should be able to see “ViewCount”, along with unprintable characters from the byte array.

19. If you wait until after the time shown for the TTL attribute (step 17), and refresh the items list (after closing the edit dialog), the item will eventually disappear. This can take anywhere from a few seconds to an hour or more (typically a few minutes at most).

Congratulations, you have created a new ASP.NET Core MVC web application, added support for session state, and then implemented DynamoDB as the storage for that session state, and tested out the solution locally.

If you have time, you can complete the bonus section below to add support for distributed web applications.