diff --git a/Bot.Builder.Community.sln b/Bot.Builder.Community.sln
index 0e3583bc..6cec3361 100644
--- a/Bot.Builder.Community.sln
+++ b/Bot.Builder.Community.sln
@@ -183,6 +183,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot.Builder.Community.Adapt
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot.Builder.Community.Adapters.Facebook.Tests", "tests\Bot.Builder.Community.Adapters.Facebook.Tests\Bot.Builder.Community.Adapters.Facebook.Tests.csproj", "{8201DC48-763A-4534-9E51-466E15DF01D8}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bot.Builder.Community.Storage.MongoDB", "libraries\Bot.Builder.Community.Storage.MongoDB\Bot.Builder.Community.Storage.MongoDB.csproj", "{74BE0FA2-3C6D-4807-8C73-CF87E898276C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - NuGet Packages|Any CPU = Debug - NuGet Packages|Any CPU
@@ -805,6 +807,14 @@ Global
{8201DC48-763A-4534-9E51-466E15DF01D8}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{8201DC48-763A-4534-9E51-466E15DF01D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8201DC48-763A-4534-9E51-466E15DF01D8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C}.Documentation|Any CPU.Build.0 = Debug|Any CPU
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -893,6 +903,7 @@ Global
{428AD1B4-DF58-4D21-9C19-AB4AB6001A90} = {840D4038-9AB8-4750-9FFE-365386CE47E2}
{3348B9A5-E3CE-4AF8-B059-8B4D7971C25A} = {840D4038-9AB8-4750-9FFE-365386CE47E2}
{8201DC48-763A-4534-9E51-466E15DF01D8} = {840D4038-9AB8-4750-9FFE-365386CE47E2}
+ {74BE0FA2-3C6D-4807-8C73-CF87E898276C} = {DC62D60A-2EA2-4DB1-B1BA-C8F38D3940B3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9FE3B75E-BA2B-45BC-BBF0-DDA8BA10C4F0}
diff --git a/libraries/Bot.Builder.Community.Storage.MongoDB/Bot.Builder.Community.Storage.MongoDB.csproj b/libraries/Bot.Builder.Community.Storage.MongoDB/Bot.Builder.Community.Storage.MongoDB.csproj
new file mode 100644
index 00000000..af2f8177
--- /dev/null
+++ b/libraries/Bot.Builder.Community.Storage.MongoDB/Bot.Builder.Community.Storage.MongoDB.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
diff --git a/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorage.cs b/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorage.cs
new file mode 100644
index 00000000..7a654a20
--- /dev/null
+++ b/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorage.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Bot.Builder;
+using Microsoft.Extensions.Options;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver;
+using Newtonsoft.Json.Linq;
+
+namespace Bot.Builder.Community.Storage.MongoDB
+{
+ public class MongoDbStorage: IStorage
+ {
+ private readonly MongoDbStorageOptions _options;
+ private readonly MongoClient _mongoClient;
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// MongoDb options class.
+ public MongoDbStorage(MongoDbStorageOptions options)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (string.IsNullOrEmpty(options.ConnectionString))
+ {
+ throw new ArgumentNullException(nameof(options.ConnectionString));
+ }
+
+ _options = options;
+
+ _mongoClient = new MongoClient(options.ConnectionString);
+
+ }
+
+ ///
+ /// Reads storage items from storage.
+ ///
+ /// keys of the objects to read.
+ /// A cancellation token that can be used by other objects
+ /// or threads to receive notice of cancellation.
+ /// A task that represents the work queued to execute.
+ /// If the activities are successfully sent, the task result contains
+ /// the items read, indexed by key.
+ ///
+ ///
+ public async Task> ReadAsync(string[] keys, CancellationToken cancellationToken = new CancellationToken())
+ {
+ var filter = Builders.Filter
+ .In(o => o.Id, keys);
+
+ var result = await GetCollection().Find(filter).ToListAsync(cancellationToken: cancellationToken);
+
+ return result.ToDictionary(x => x.Id, x => x.Data);
+ }
+
+ ///
+ /// Writes storage items to storage.
+ ///
+ /// The items to write, indexed by key.
+ /// A cancellation token that can be used by other objects
+ /// or threads to receive notice of cancellation.
+ /// A task that represents the work queued to execute.
+ ///
+ ///
+ public async Task WriteAsync(IDictionary changes, CancellationToken cancellationToken = new CancellationToken())
+ {
+ var collection = GetCollection();
+ foreach (var change in changes)
+ {
+ var filter = Builders.Filter.Eq(o => o.Id, change.Key);
+ var update = Builders.Update.Set(o => o.Data, change.Value);
+ var options = new UpdateOptions { IsUpsert = true };
+ await collection.UpdateOneAsync(filter, update, options, cancellationToken);
+ }
+ }
+
+ ///
+ /// Writes storage items to storage.
+ ///
+ /// The items to write, indexed by key.
+ /// A cancellation token that can be used by other objects
+ /// or threads to receive notice of cancellation.
+ /// A task that represents the work queued to execute.
+ ///
+ ///
+ public Task DeleteAsync(string[] keys, CancellationToken cancellationToken = new CancellationToken())
+ {
+
+ var filter = Builders.Filter
+ .In(restaurant => restaurant.Id, keys);
+
+ return GetCollection().DeleteManyAsync(filter, cancellationToken);
+ }
+
+ private IMongoCollection GetCollection()
+ {
+ var database = _mongoClient.GetDatabase(_options.DatabaseName);
+ var collection = database.GetCollection(_options.CollectionName);
+ return collection;
+ }
+ private class StorageEntry
+ {
+ public string Id { get; set; }
+ public object Data { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorageOptions.cs b/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorageOptions.cs
new file mode 100644
index 00000000..e5ccbccd
--- /dev/null
+++ b/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorageOptions.cs
@@ -0,0 +1,39 @@
+namespace Bot.Builder.Community.Storage.MongoDB
+{
+ ///
+ /// Represents the MongoDB storage configuration options.
+ ///
+ ///
+ /// This class is used to configure the settings for connecting to a MongoDB instance, specifying the database and collection to be used for storage.
+ ///
+ public class MongoDbStorageOptions
+ {
+ ///
+ /// Gets or sets the connection string for the MongoDB instance.
+ ///
+ /// The connection string.
+ ///
+ /// The connection string is used to specify the location and authentication details for the MongoDB instance.
+ ///
+ public string ConnectionString { get; set; }
+
+ ///
+ /// Gets or sets the name of the database to be used for storage.
+ ///
+ /// The name of the database.
+ ///
+ /// The database name is used to determine which database within the MongoDB instance should be used for storing data.
+ ///
+ public string DatabaseName { get; set; }
+
+ ///
+ /// Gets or sets the name of the collection to be used for storage.
+ ///
+ /// The name of the collection. Defaults to "StateData".
+ ///
+ /// The collection name is used to determine which collection within the specified database should be used for storing data. If not specified, the default value is "StateData".
+ ///
+ public string CollectionName { get; set; } = "StateData";
+ }
+
+}
\ No newline at end of file
diff --git a/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorageSettings.cs b/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorageSettings.cs
new file mode 100644
index 00000000..12da8384
--- /dev/null
+++ b/libraries/Bot.Builder.Community.Storage.MongoDB/MongoDbStorageSettings.cs
@@ -0,0 +1,87 @@
+using System;
+using Microsoft.Extensions.Configuration;
+
+namespace Bot.Builder.Community.Storage.MongoDB
+{
+ public class MongoDbStorageSettings
+ {
+ public Type[] AllowedTypes { get; private set; }
+
+ public MongoDbStorageOptions Options { get; private set; }
+
+ ///
+ /// Registers the specified types for MongoDB storage.
+ ///
+ /// An array of objects to be registered for storage.
+ /// The current instance, allowing method calls to be chained.
+ ///
+ /// This method sets the property with the provided types. It is useful for configuring the MongoDB storage settings with the desired types that need to be stored in the database.
+ ///
+
+ public MongoDbStorageSettings RegisterTypes(params Type[] types)
+ {
+ AllowedTypes = types;
+ return this;
+ }
+
+ ///
+ /// Configures the using the provided .
+ ///
+ /// The to bind the options to.
+ /// The current instance, allowing method calls to be chained.
+ ///
+ /// This method creates a new instance of and binds the provided configuration section to it. The resulting options are then used to configure the MongoDB storage settings.
+ ///
+ ///
+ /// ...
+ /// "ConnectionString": "...",
+ /// "DatabaseName": "...",
+ /// "CollectionName": "...",
+ /// ...
+ ///
+ public MongoDbStorageSettings ConfigureOptions(IConfigurationSection configuration)
+ {
+ Options = new MongoDbStorageOptions();
+ configuration.Bind(Options);
+ return this;
+ }
+
+ ///
+ /// Configures the using the provided instance.
+ ///
+ /// The instance to use for configuration.
+ /// The current instance, allowing method calls to be chained.
+ ///
+ /// This method sets the property with the provided instance. It is useful for configuring the MongoDB storage settings using a preconfigured options object.
+ ///
+ public MongoDbStorageSettings ConfigureOptions(MongoDbStorageOptions options)
+ {
+ Options = options;
+ return this;
+ }
+
+ ///
+ /// Configures the using the provided connection string, database name, and optionally, collection name.
+ ///
+ /// The connection string for the MongoDB instance.
+ /// The name of the database to be used for storage.
+ /// The optional name of the collection to be used for storage (default is null).
+ /// The current instance, allowing method calls to be chained.
+ ///
+ /// This method creates a new instance of and sets the provided connection string, database name, and collection name (if provided). The resulting options are then used to configure the MongoDB storage settings.
+ ///
+ public MongoDbStorageSettings ConfigureOptions(
+ string connectionString,
+ string databaseName,
+ string collectionName = null)
+ {
+ Options = new MongoDbStorageOptions
+ {
+ ConnectionString = connectionString,
+ DatabaseName = databaseName,
+ CollectionName = collectionName
+ };
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries/Bot.Builder.Community.Storage.MongoDB/Readme.md b/libraries/Bot.Builder.Community.Storage.MongoDB/Readme.md
new file mode 100644
index 00000000..32cc3f75
--- /dev/null
+++ b/libraries/Bot.Builder.Community.Storage.MongoDB/Readme.md
@@ -0,0 +1,46 @@
+# MongoDB Storage Integration
+
+This functionality enables seamless integration of MongoDB storage into your existing project. With this integration, you can easily store and retrieve data using MongoDB as your backend storage system.
+
+## Features
+- Robust and scalable MongoDB storage solution
+- Easy configuration and registration of MongoDB storage using extension methods
+- Support for custom serialization of allowed types
+
+## Getting Started
+
+To get started, follow these steps:
+
+1. Install the required package `Bot.Builder.Community.Storage.MongoDB` for your project
+
+
+2. Add the following using statements to your project:
+```csharp
+using Bot.Builder.Community.Storage.MongoDB;
+```
+
+3. In the ConfigureServices method of your Startup.cs file, add the following code to configure and register MongoDB storage:
+```csharp
+services.AddMongoDbStorage(settings =>
+{
+ settings.ConfigureOptions(Configuration.GetSection("MongoDb"));
+ settings.RegisterTypes(
+ typeof(YourType1),
+ typeof(YourType2)
+ );
+});
+```
+Replace YourType with the type(s) you want to store in
+
+4. Update your appsettings.json file to include the MongoDB configuration settings:
+
+```json
+{
+ "MongoDb": {
+ "ConnectionString": "your_connection_string",
+ "Database": "your_database_name",
+ "Collection": "your_collection_name"
+ }
+}
+```
+Replace your_connection_string, your_database_name, and your_collection_name with the appropriate values for your MongoDB instance.
\ No newline at end of file
diff --git a/libraries/Bot.Builder.Community.Storage.MongoDB/ServiceCollectionExtensions.cs b/libraries/Bot.Builder.Community.Storage.MongoDB/ServiceCollectionExtensions.cs
new file mode 100644
index 00000000..6f7bf5ee
--- /dev/null
+++ b/libraries/Bot.Builder.Community.Storage.MongoDB/ServiceCollectionExtensions.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Linq;
+using Microsoft.Bot.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace Bot.Builder.Community.Storage.MongoDB
+{
+ public static class ServiceCollectionExtensions
+ {
+ ///
+ /// Adds and configures MongoDB storage support
+ ///
+ /// The to add the storage to.
+ /// A delegate to configure the .
+ /// The of the storage context (default is ).
+ /// The same instance so that multiple calls can be chained.
+ /// Thrown when no types are found to scan or when the connection string or database name is not provided.
+ ///
+ /// This extension method configures MongoDB storage support for the specified service collection. It requires the caller to provide at least one type to scan and a valid connection string and database name.
+ ///
+ public static IServiceCollection AddMongoDbStorage(this IServiceCollection services,
+ Action settings,
+ ServiceLifetime contextLifetime = ServiceLifetime.Singleton)
+ {
+ var config = new MongoDbStorageSettings();
+
+ settings.Invoke(config);
+
+ if (!config.AllowedTypes.Any())
+ {
+ throw new ArgumentException("No types found to scan. Supply at least one type");
+ }
+
+ if (config.Options == null
+ || string.IsNullOrEmpty(config.Options.ConnectionString)
+ || string.IsNullOrEmpty(config.Options.DatabaseName)
+ )
+ {
+ throw new ArgumentException("No connection string or database name found.");
+ }
+
+ var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) || config.AllowedTypes.Contains(type));
+
+ BsonSerializer.RegisterSerializer(objectSerializer);
+
+ services.TryAdd(new ServiceDescriptor(typeof(IStorage), provider => new MongoDbStorage(config.Options), contextLifetime));
+
+ return services;
+ }
+ }
+}
\ No newline at end of file