diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs
new file mode 100644
index 0000000..fbf22db
--- /dev/null
+++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TelegramBotBase.Builder;
+using TelegramBotBase.Builder.Interfaces;
+
+namespace TelegramBotBase.Extensions.Serializer.Database.MSSQL
+{
+ public static class BotBaseBuilderExtensions
+ {
+
+ ///
+ /// Uses an Microsoft SQL Server Database to save and restore sessions.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String ConnectionString, Type fallbackForm = null, String tablePrefix = "tgb_")
+ {
+ var serializer = new MSSQLSerializer(ConnectionString, tablePrefix, fallbackForm);
+
+ builder.UseSerialization(serializer);
+
+ return builder as BotBaseBuilder;
+ }
+
+
+ ///
+ /// Uses an Microsoft SQL Server Database to save and restore sessions.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String HostOrIP, String DatabaseName, String UserId, String Password, Type fallbackForm = null, String tablePrefix = "tgb_")
+ {
+ var connectionString = $"Server={HostOrIP}; Database={DatabaseName}; User Id={UserId}; Password={Password}; TrustServerCertificate=true;";
+
+ var serializer = new MSSQLSerializer(connectionString, tablePrefix, fallbackForm);
+
+ builder.UseSerialization(serializer);
+
+ return builder as BotBaseBuilder;
+ }
+
+ ///
+ /// Uses an Microsoft SQL Server Database with Windows Authentication to save and restore sessions.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String HostOrIP, String DatabaseName, bool IntegratedSecurity = true, Type fallbackForm = null, String tablePrefix = "tgb_")
+ {
+ if (!IntegratedSecurity)
+ throw new ArgumentOutOfRangeException();
+
+ var connectionString = $"Server={HostOrIP}; Database={DatabaseName}; Integrated Security=true; TrustServerCertificate=true;";
+
+ var serializer = new MSSQLSerializer(connectionString, tablePrefix, fallbackForm);
+
+ builder.UseSerialization(serializer);
+
+ return builder as BotBaseBuilder;
+ }
+ }
+}
diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs
new file mode 100644
index 0000000..5aca6e4
--- /dev/null
+++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs
@@ -0,0 +1,186 @@
+using TelegramBotBase.Interfaces;
+using TelegramBotBase.Builder.Interfaces;
+using System;
+using TelegramBotBase.Base;
+using TelegramBotBase.Args;
+using TelegramBotBase.Form;
+using Microsoft.Data.SqlClient;
+using System.Data;
+
+namespace TelegramBotBase.Extensions.Serializer.Database.MSSQL
+{
+ public class MSSQLSerializer : IStateMachine
+ {
+ public Type FallbackStateForm { get; set; }
+ public string ConnectionString { get; }
+ public String TablePrefix { get; set; }
+
+ ///
+ /// Will initialize the state machine.
+ ///
+ /// Path of the file and name where to save the session details.
+ /// Type of Form which will be saved instead of Form which has attribute declared. Needs to be subclass of .
+ /// Declares of the file could be overwritten.
+ public MSSQLSerializer(String ConnectionString, String tablePrefix = "tgb_", Type fallbackStateForm = null)
+ {
+ if (ConnectionString is null)
+ {
+ throw new ArgumentNullException(nameof(ConnectionString));
+ }
+
+ this.ConnectionString = ConnectionString;
+
+ this.TablePrefix = tablePrefix;
+
+ this.FallbackStateForm = fallbackStateForm;
+
+ if (this.FallbackStateForm != null && !this.FallbackStateForm.IsSubclassOf(typeof(FormBase)))
+ {
+ throw new ArgumentException("FallbackStateForm is not a subclass of FormBase");
+ }
+ }
+
+ public StateContainer LoadFormStates()
+ {
+ var sc = new StateContainer();
+
+ using (var connection = new SqlConnection(ConnectionString))
+ {
+ connection.Open();
+
+ var command = connection.CreateCommand();
+ command.CommandText = "SELECT deviceId, deviceTitle, FormUri, QualifiedName FROM " + TablePrefix + "devices_sessions";
+
+ var dataTable = new DataTable();
+ using (var dataAdapter = new SqlDataAdapter(command))
+ {
+ dataAdapter.Fill(dataTable);
+
+ foreach (DataRow r in dataTable.Rows)
+ {
+ var se = new StateEntry()
+ {
+ DeviceId = (long)r["deviceId"],
+ ChatTitle = r["deviceTitle"].ToString(),
+ FormUri = r["FormUri"].ToString(),
+ QualifiedName = r["QualifiedName"].ToString()
+ };
+
+ sc.States.Add(se);
+
+ if (se.DeviceId > 0)
+ {
+ sc.ChatIds.Add(se.DeviceId);
+ }
+ else
+ {
+ sc.GroupIds.Add(se.DeviceId);
+ }
+
+ var data_command = connection.CreateCommand();
+ data_command.CommandText = "SELECT [key], value, type FROM " + TablePrefix + "devices_sessions_data WHERE deviceId = @deviceId";
+ data_command.Parameters.Add(new SqlParameter("@deviceId", r["deviceId"]));
+
+ var data_table = new DataTable();
+ using (var dataAdapter2 = new SqlDataAdapter(data_command))
+ {
+ dataAdapter2.Fill(data_table);
+
+ foreach (DataRow r2 in data_table.Rows)
+ {
+ var key = r2["key"].ToString();
+ var type = Type.GetType(r2["type"].ToString());
+
+ var value = Newtonsoft.Json.JsonConvert.DeserializeObject(r2["value"].ToString(), type);
+
+ se.Values.Add(key, value);
+ }
+ }
+
+ }
+
+ }
+
+
+
+ connection.Close();
+ }
+
+ return sc;
+ }
+
+ public void SaveFormStates(SaveStatesEventArgs e)
+ {
+ var container = e.States;
+
+ using (var connection = new SqlConnection(ConnectionString))
+ {
+ connection.Open();
+
+ //Cleanup old Session data
+ var clear_command = connection.CreateCommand();
+
+ clear_command.CommandText = $"DELETE FROM {TablePrefix}devices_sessions_data";
+
+ clear_command.ExecuteNonQuery();
+
+ clear_command.CommandText = $"DELETE FROM {TablePrefix}devices_sessions";
+
+ clear_command.ExecuteNonQuery();
+
+ //Prepare new session commands
+ var session_command = connection.CreateCommand();
+ var data_command = connection.CreateCommand();
+
+ session_command.CommandText = "INSERT INTO " + TablePrefix + "devices_sessions (deviceId, deviceTitle, FormUri, QualifiedName) VALUES (@deviceId, @deviceTitle, @FormUri, @QualifiedName)";
+ session_command.Parameters.Add(new SqlParameter("@deviceId", ""));
+ session_command.Parameters.Add(new SqlParameter("@deviceTitle", ""));
+ session_command.Parameters.Add(new SqlParameter("@FormUri", ""));
+ session_command.Parameters.Add(new SqlParameter("@QualifiedName", ""));
+
+ data_command.CommandText = "INSERT INTO " + TablePrefix + "devices_sessions_data (deviceId, [key], value, type) VALUES (@deviceId, @key, @value, @type)";
+ data_command.Parameters.Add(new SqlParameter("@deviceId", ""));
+ data_command.Parameters.Add(new SqlParameter("@key", ""));
+ data_command.Parameters.Add(new SqlParameter("@value", ""));
+ data_command.Parameters.Add(new SqlParameter("@type", ""));
+
+ //Store session data in database
+ foreach (var state in container.States)
+ {
+ session_command.Parameters["@deviceId"].Value = state.DeviceId;
+ session_command.Parameters["@deviceTitle"].Value = state.ChatTitle ?? "";
+ session_command.Parameters["@FormUri"].Value = state.FormUri;
+ session_command.Parameters["@QualifiedName"].Value = state.QualifiedName;
+
+ session_command.ExecuteNonQuery();
+
+ foreach (var data in state.Values)
+ {
+ data_command.Parameters["@deviceId"].Value = state.DeviceId;
+ data_command.Parameters["@key"].Value = data.Key;
+
+ var type = data.Value.GetType();
+
+ if (type.IsPrimitive || type.Equals(typeof(string)))
+ {
+ data_command.Parameters["@value"].Value = data.Value;
+ }
+ else
+ {
+ data_command.Parameters["@value"].Value = Newtonsoft.Json.JsonConvert.SerializeObject(data.Value);
+ }
+
+ data_command.Parameters["@type"].Value = type.AssemblyQualifiedName;
+
+ data_command.ExecuteNonQuery();
+ }
+
+ }
+
+ connection.Close();
+ }
+
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md
new file mode 100644
index 0000000..565bc57
--- /dev/null
+++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md
@@ -0,0 +1,8 @@
+# TelegramBotBase.Extensions.Images
+
+[](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/)
+[](https://www.t.me/tgbotbase)
+
+
+[](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md)
+[](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL)
diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj
new file mode 100644
index 0000000..c8b7f27
--- /dev/null
+++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj
@@ -0,0 +1,25 @@
+
+
+
+ netstandard2.0;net5;netcoreapp3.1;net6
+ True
+ https://github.com/MajMcCloud/TelegramBotFramework
+ https://github.com/MajMcCloud/TelegramBotFramework
+ MIT
+ true
+ snupkg
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql
new file mode 100644
index 0000000..587eb4f
--- /dev/null
+++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql
@@ -0,0 +1,37 @@
+USE [telegram_bot]
+GO
+/****** Object: Table [dbo].[tgb_devices_sessions] Script Date: 30.06.2022 16:22:09 ******/
+SET ANSI_NULLS ON
+GO
+SET QUOTED_IDENTIFIER ON
+GO
+CREATE TABLE [dbo].[tgb_devices_sessions](
+ [deviceId] [bigint] NOT NULL,
+ [deviceTitle] [nvarchar](512) NOT NULL,
+ [FormUri] [nvarchar](512) NOT NULL,
+ [QualifiedName] [nvarchar](512) NOT NULL,
+ CONSTRAINT [PK_tgb_devices_sessions_1] PRIMARY KEY CLUSTERED
+(
+ [deviceId] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+/****** Object: Table [dbo].[tgb_devices_sessions_data] Script Date: 30.06.2022 16:22:09 ******/
+SET ANSI_NULLS ON
+GO
+SET QUOTED_IDENTIFIER ON
+GO
+CREATE TABLE [dbo].[tgb_devices_sessions_data](
+ [Id] [uniqueidentifier] NOT NULL,
+ [deviceId] [bigint] NOT NULL,
+ [key] [nvarchar](512) NOT NULL,
+ [value] [nvarchar](max) NOT NULL,
+ [type] [nvarchar](512) NOT NULL,
+ CONSTRAINT [PK_tgb_devices_session_data] PRIMARY KEY CLUSTERED
+(
+ [Id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[tgb_devices_sessions_data] ADD CONSTRAINT [DF_tgb_devices_session_data_Id] DEFAULT (newid()) FOR [Id]
+GO