Example E1344
Visible to All Users

XAF - How to Change Connection to the Database at Runtime from the Login Form

Scenario

This example illustrates how to connect your application to a different database after the application start. Use this approach in a multi-tenant application where you need to associate every user or company with their own database. You can choose the user and the database during the login procedure. In this scenario, all databases have the same structure, but their predefined data sets may vary.

image

Alternative solutions: How to Implement a Multi-Tenant Application for Blazor and WinForms

Implementation Steps

  1. In the Solution Wizard, create a new XAF application and name it RuntimeDbChooser.
    • Use either of the available ORM libraries for data access: XPO or EF Core.
    • Select the Security module with the Authentication = Standard and Integrated Mode options.
  2. Copy the code that creates the predefined security users for each database from the RuntimeDbChooser.Module\DatabaseUpdate\Updater.xx file into the YourSolutionName.Module\DatabaseUpdate\Updater.xx file.
  3. Copy and include the RuntimeDbChooser.Module\BusinessObjects\CustomLogonParameters.xx file into the YourSolutionName.Module\BusinessObjects folder.
  4. For WinForms application only. Copy and include the RuntimeDbChooser.Module\ChangeDatabaseActiveDirectoryAuthentication.xx file into the YourSolutionName.Module project. For more information on this API, see the following article: How to: Use Custom Logon Parameters and Authentication.
  5. Copy and include the RuntimeDbChooser.Wxx\WxxApplicationEx.xx files into the YourSolutionName.Wxx project. Rename the RuntimeDbChooserWindowsFormsApplication, or RuntimeDbChooserAspNetApplication, or RuntimeDbChooserBlazorApplication to your WxxApplication descendant's name from the WxxApplication.xx file.
  6. Replace the line that instantiates your WinApplication descendant in the YourSolutionName.Win/Program.xx file with the CreateApplication method call as shown in the RuntimeDbChooser.Win/Program.xx file.
  7. Open the YourSolutionName.Web/WebApplication.xx file in the Application Designer. Select the Authentication Standard component and set its LogonParametersType property to RuntimeDbChooser.Module.BusinessObjects.CustomLogonParametersForStandardAuthentication.
  8. Replace the line that instantiates your BlazorApplication in the YourSolutionName.Blazor.Server/Startup.cs file and set the AddPasswordAuthentication.Options.LogonParametersType property to RuntimeDbChooser.Module.BusinessObjects.CustomLogonParametersForStandardAuthentication.
  9. Copy and include the CustomLogonController.cs file into the application project. Register this controller in the Application.CreateLogonController method override. The implementation of the controller in WinForms and ASP.NET WebForms applications differs from the implementation in Blazor Server applications.

Important Notes

  1. In this example, XAF Blazor applications load the available database names from the appsettings.json file.
  2. In WinForms and ASP.NET WebForms applications, the database names are hard-coded in the MSSqlServerChangeDatabaseHelper class and supplied to the DatabaseName  property editor using the PredefinedValues model option. To populate this list with database names that become available only at runtime (for example, the application reads the names from a configuration file or a database), consider the following options:
  3. For WinForms and ASP.NET WebForms, this XafApplication.ConnectionString-based implementation is designed for a simple scenario where the connection string doesn't store the user and password information. Otherwise, XAF removes the sensitive password information from the XafApplication.ConnectionString and you cannot rely on this API. In such scenarios, we recommend that you store the original connection string information in the CreateDefaultObjectSpaceProvider method of your XafApplication descendant (see the YourSolutionName.Wxx/WxxApplication.xx file) as demonstrated in the following example: XAF - How to generate a sequential number for a persistent object within a database transaction.
  4. For WinForms and ASP.NET WebForms, see the alternative solutions created by DevExpress MVPs Jose Columbie and Joche Ojeda here: XAF Blazor Change DB at runtime.

Files to Review

Common

WinForms

ASP.NET WebForms

Blazor Server

See Also

How to Implement a Multi-Tenant Application for Blazor and WinForms

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

XPO/ASP.NETCore/Blazor/RuntimeDbChooser.Module/DatabaseUpdate/Updater.cs
C#
using System; using System.Linq; using DevExpress.ExpressApp; using DevExpress.Data.Filtering; using DevExpress.Persistent.Base; using DevExpress.ExpressApp.Updating; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.SystemModule; using DevExpress.ExpressApp.Security.Strategy; using DevExpress.Xpo; using DevExpress.ExpressApp.Xpo; using DevExpress.Persistent.BaseImpl; using DevExpress.Persistent.BaseImpl.PermissionPolicy; using RuntimeDbChooser.Module.BusinessObjects; namespace RuntimeDbChooser.Module.DatabaseUpdate { // For more typical usage scenarios, be sure to check out https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Updating.ModuleUpdater public class Updater : ModuleUpdater { public Updater(IObjectSpace objectSpace, Version currentDBVersion) : base(objectSpace, currentDBVersion) { } public override void UpdateDatabaseAfterUpdateSchema() { base.UpdateDatabaseAfterUpdateSchema(); // If a user named 'Sam' doesn't exist in the database, create this user ApplicationUser userAdmin = ObjectSpace.FirstOrDefault<ApplicationUser>(u => u.UserName == "Admin"); if (userAdmin == null) { userAdmin = ObjectSpace.CreateObject<ApplicationUser>(); userAdmin.UserName = "Admin"; // Set a password if the standard authentication type is used userAdmin.SetPassword(""); // The UserLoginInfo object requires a user object Id (Oid). // Commit the user object to the database before you create a UserLoginInfo object. This will correctly initialize the user key property. ObjectSpace.CommitChanges(); //This line persists created object(s). ((ISecurityUserWithLoginInfo)userAdmin).CreateUserLoginInfo(SecurityDefaults.PasswordAuthentication, ObjectSpace.GetKeyValueAsString(userAdmin)); } // If a role with the Administrators name doesn't exist in the database, create this role PermissionPolicyRole adminRole = ObjectSpace.FindObject<PermissionPolicyRole>(new BinaryOperator("Name", "Administrators")); if(adminRole == null) { adminRole = ObjectSpace.CreateObject<PermissionPolicyRole>(); adminRole.Name = "Administrators"; } adminRole.IsAdministrative = true; userAdmin.Roles.Add(adminRole); if(ObjectSpace.Database.Contains("DB1")) { ApplicationUser sampleUser1 = ObjectSpace.FirstOrDefault<ApplicationUser>(u => u.UserName == "User1"); if (sampleUser1 == null) { sampleUser1 = ObjectSpace.CreateObject<ApplicationUser>(); sampleUser1.UserName = "User1"; // Set a password if the standard authentication type is used sampleUser1.SetPassword(""); // The UserLoginInfo object requires a user object Id (Oid). // Commit the user object to the database before you create a UserLoginInfo object. This will correctly initialize the user key property. ObjectSpace.CommitChanges(); //This line persists created object(s). ((ISecurityUserWithLoginInfo)sampleUser1).CreateUserLoginInfo(SecurityDefaults.PasswordAuthentication, ObjectSpace.GetKeyValueAsString(sampleUser1)); } PermissionPolicyRole defaultRole = CreateDefaultRole(); sampleUser1.Roles.Add(defaultRole); } if(ObjectSpace.Database.Contains("DB2")) { ApplicationUser sampleUser2 = ObjectSpace.FirstOrDefault<ApplicationUser>(u => u.UserName == "User2"); if (sampleUser2 == null) { sampleUser2 = ObjectSpace.CreateObject<ApplicationUser>(); sampleUser2.UserName = "User2"; // Set a password if the standard authentication type is used sampleUser2.SetPassword(""); // The UserLoginInfo object requires a user object Id (Oid). // Commit the user object to the database before you create a UserLoginInfo object. This will correctly initialize the user key property. ObjectSpace.CommitChanges(); //This line persists created object(s). ((ISecurityUserWithLoginInfo)sampleUser2).CreateUserLoginInfo(SecurityDefaults.PasswordAuthentication, ObjectSpace.GetKeyValueAsString(sampleUser2)); } PermissionPolicyRole defaultRole = CreateDefaultRole(); sampleUser2.Roles.Add(defaultRole); } ObjectSpace.CommitChanges(); } public override void UpdateDatabaseBeforeUpdateSchema() { base.UpdateDatabaseBeforeUpdateSchema(); } private PermissionPolicyRole CreateDefaultRole() { PermissionPolicyRole defaultRole = ObjectSpace.FindObject<PermissionPolicyRole>(new BinaryOperator("Name", "Default")); if(defaultRole == null) { defaultRole = ObjectSpace.CreateObject<PermissionPolicyRole>(); defaultRole.Name = "Default"; defaultRole.PermissionPolicy = SecurityPermissionPolicy.AllowAllByDefault; defaultRole.AddNavigationPermission("Application/NavigationItems/Items/Default/Items/PermissionPolicyRole_ListView", SecurityPermissionState.Deny); defaultRole.AddNavigationPermission("Application/NavigationItems/Items/Default/Items/PermissionPolicyUser_ListView", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyRole>(SecurityOperations.FullAccess, SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyUser>(SecurityOperations.FullAccess, SecurityPermissionState.Deny); defaultRole.AddObjectPermission<PermissionPolicyUser>(SecurityOperations.ReadOnlyAccess, "[Oid] = CurrentUserId()", SecurityPermissionState.Allow); defaultRole.AddMemberPermission<PermissionPolicyUser>(SecurityOperations.Write, "ChangePasswordOnFirstLogon", null, SecurityPermissionState.Allow); defaultRole.AddMemberPermission<PermissionPolicyUser>(SecurityOperations.Write, "StoredPassword", null, SecurityPermissionState.Allow); defaultRole.AddTypePermission<PermissionPolicyRole>(SecurityOperations.Read, SecurityPermissionState.Allow); defaultRole.AddTypePermission<PermissionPolicyTypePermissionObject>("Write;Delete;Create", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyMemberPermissionsObject>("Write;Delete;Create", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyObjectPermissionsObject>("Write;Delete;Create", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyNavigationPermissionObject>("Write;Delete;Create", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyActionPermissionObject>("Write;Delete;Create", SecurityPermissionState.Deny); } return defaultRole; } } }
EFCore/ASP.NETCore/Blazor/RuntimeDbChooser.Module/DatabaseUpdate/Updater.cs
C#
using System; using DevExpress.Data.Filtering; using DevExpress.ExpressApp; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.Updating; using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy; using RuntimeDbChooser.Module.BusinessObjects; namespace RuntimeDbChooser.Module.DatabaseUpdate; // For more typical usage scenarios, be sure to check out https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Updating.ModuleUpdater public class Updater : ModuleUpdater { public Updater(IObjectSpace objectSpace, Version currentDBVersion) : base(objectSpace, currentDBVersion) { } public override void UpdateDatabaseAfterUpdateSchema() { base.UpdateDatabaseAfterUpdateSchema(); // If a user named 'Sam' doesn't exist in the database, create this user ApplicationUser userAdmin = ObjectSpace.FirstOrDefault<ApplicationUser>(u => u.UserName == "Admin"); if(userAdmin == null) { userAdmin = ObjectSpace.CreateObject<ApplicationUser>(); userAdmin.UserName = "Admin"; // Set a password if the standard authentication type is used userAdmin.SetPassword(""); // The UserLoginInfo object requires a user object Id. // Commit the user object to the database before you create a UserLoginInfo object. This will correctly initialize the user key property. ObjectSpace.CommitChanges(); //This line persists created object(s). ((ISecurityUserWithLoginInfo)userAdmin).CreateUserLoginInfo(SecurityDefaults.PasswordAuthentication, ObjectSpace.GetKeyValueAsString(userAdmin)); } // If a role with the Administrators name doesn't exist in the database, create this role PermissionPolicyRole adminRole = ObjectSpace.FindObject<PermissionPolicyRole>(new BinaryOperator("Name", "Administrators")); if(adminRole == null) { adminRole = ObjectSpace.CreateObject<PermissionPolicyRole>(); adminRole.Name = "Administrators"; } adminRole.IsAdministrative = true; userAdmin.Roles.Add(adminRole); if(ObjectSpace.Database.Contains("DB1")) { ApplicationUser sampleUser1 = ObjectSpace.FirstOrDefault<ApplicationUser>(u => u.UserName == "User1"); if(sampleUser1 == null) { sampleUser1 = ObjectSpace.CreateObject<ApplicationUser>(); sampleUser1.UserName = "User1"; // Set a password if the standard authentication type is used sampleUser1.SetPassword(""); // The UserLoginInfo object requires a user object Id. // Commit the user object to the database before you create a UserLoginInfo object. This will correctly initialize the user key property. ObjectSpace.CommitChanges(); //This line persists created object(s). ((ISecurityUserWithLoginInfo)sampleUser1).CreateUserLoginInfo(SecurityDefaults.PasswordAuthentication, ObjectSpace.GetKeyValueAsString(sampleUser1)); } PermissionPolicyRole defaultRole = CreateDefaultRole(); sampleUser1.Roles.Add(defaultRole); } if(ObjectSpace.Database.Contains("DB2")) { ApplicationUser sampleUser2 = ObjectSpace.FirstOrDefault<ApplicationUser>(u => u.UserName == "User2"); if(sampleUser2 == null) { sampleUser2 = ObjectSpace.CreateObject<ApplicationUser>(); sampleUser2.UserName = "User2"; // Set a password if the standard authentication type is used sampleUser2.SetPassword(""); // The UserLoginInfo object requires a user object Id. // Commit the user object to the database before you create a UserLoginInfo object. This will correctly initialize the user key property. ObjectSpace.CommitChanges(); //This line persists created object(s). ((ISecurityUserWithLoginInfo)sampleUser2).CreateUserLoginInfo(SecurityDefaults.PasswordAuthentication, ObjectSpace.GetKeyValueAsString(sampleUser2)); } PermissionPolicyRole defaultRole = CreateDefaultRole(); sampleUser2.Roles.Add(defaultRole); } ObjectSpace.CommitChanges(); } public override void UpdateDatabaseBeforeUpdateSchema() { base.UpdateDatabaseBeforeUpdateSchema(); } private PermissionPolicyRole CreateDefaultRole() { PermissionPolicyRole defaultRole = ObjectSpace.FindObject<PermissionPolicyRole>(new BinaryOperator("Name", "Default")); if(defaultRole == null) { defaultRole = ObjectSpace.CreateObject<PermissionPolicyRole>(); defaultRole.Name = "Default"; defaultRole.PermissionPolicy = SecurityPermissionPolicy.AllowAllByDefault; defaultRole.AddNavigationPermission("Application/NavigationItems/Items/Default/Items/PermissionPolicyRole_ListView", SecurityPermissionState.Deny); defaultRole.AddNavigationPermission("Application/NavigationItems/Items/Default/Items/PermissionPolicyUser_ListView", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyRole>(SecurityOperations.FullAccess, SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyUser>(SecurityOperations.FullAccess, SecurityPermissionState.Deny); defaultRole.AddObjectPermission<PermissionPolicyUser>(SecurityOperations.ReadOnlyAccess, "[ID] = CurrentUserId()", SecurityPermissionState.Allow); defaultRole.AddMemberPermission<PermissionPolicyUser>(SecurityOperations.Write, "ChangePasswordOnFirstLogon", null, SecurityPermissionState.Allow); defaultRole.AddMemberPermission<PermissionPolicyUser>(SecurityOperations.Write, "StoredPassword", null, SecurityPermissionState.Allow); defaultRole.AddTypePermission<PermissionPolicyRole>(SecurityOperations.Read, SecurityPermissionState.Allow); defaultRole.AddTypePermission<PermissionPolicyTypePermissionObject>("Write;Delete;Create", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyMemberPermissionsObject>("Write;Delete;Create", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyObjectPermissionsObject>("Write;Delete;Create", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyNavigationPermissionObject>("Write;Delete;Create", SecurityPermissionState.Deny); defaultRole.AddTypePermission<PermissionPolicyActionPermissionObject>("Write;Delete;Create", SecurityPermissionState.Deny); } return defaultRole; } }
XPO/ASP.NETCore/Blazor/RuntimeDbChooser.Module/BusinessObjects/CustomLogonParameters.cs
C#
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Core; using DevExpress.ExpressApp.DC; using DevExpress.ExpressApp.Security; using DevExpress.Persistent.Base; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using RuntimeDbChooser.Services; using System; using System.Collections.Generic; using System.ComponentModel; namespace RuntimeDbChooser.Module.BusinessObjects; [DomainComponent] public class CustomLogonParametersForStandardAuthentication : AuthenticationStandardLogonParameters, IDatabaseNameParameter, IServiceProviderConsumer { IServiceProvider serviceProvider; private DataBaseNameHolder dataBaseNameObj; [DataSourceProperty(nameof(GetDataBaseNames), DataSourcePropertyIsNullMode.SelectAll)] public DataBaseNameHolder DatabaseName { get { return dataBaseNameObj; } set { dataBaseNameObj = value; } } IReadOnlyList<DataBaseNameHolder>? dataBaseNameObjs = null; [Browsable(false)] [JsonIgnore] public IReadOnlyList<DataBaseNameHolder> GetDataBaseNames { get { if(dataBaseNameObjs == null) { dataBaseNameObjs = new List<DataBaseNameHolder>(); IConnectionStringHelper connectionStringHelper = serviceProvider.GetRequiredService<IConnectionStringHelper>(); foreach(var dbname in connectionStringHelper.GetConnectionStringsMap().Keys) { ((List<DataBaseNameHolder>)dataBaseNameObjs).Add(new DataBaseNameHolder(dbname)); } } return dataBaseNameObjs; } } public void SetServiceProvider(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } } [DomainComponent] //set readonly using model editor //<DetailView Id = "DataBaseNameHolder_DetailView" AllowEdit="False" /> //CustomLogonController checks that the DataBaseNameHolder property is not null public class DataBaseNameHolder : NonPersistentLiteObject { public DataBaseNameHolder(string name) { Name = name; } public string Name { get; } }
EFCore/ASP.NETCore/Blazor/RuntimeDbChooser.Module/BusinessObjects/CustomLogonParameters.cs
C#
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Core; using DevExpress.ExpressApp.DC; using DevExpress.ExpressApp.Security; using DevExpress.Persistent.Base; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using RuntimeDbChooser.Services; using System; using System.Collections.Generic; using System.ComponentModel; namespace RuntimeDbChooser.Module.BusinessObjects; [DomainComponent] public class CustomLogonParametersForStandardAuthentication : AuthenticationStandardLogonParameters, IDatabaseNameParameter, IServiceProviderConsumer { private IServiceProvider serviceProvider; private DataBaseNameHolder dataBaseNameObj; private IReadOnlyList<DataBaseNameHolder>? dataBaseNameObjs = null; [DataSourceProperty(nameof(GetDataBaseNames), DataSourcePropertyIsNullMode.SelectAll)] public DataBaseNameHolder DatabaseName { get { return dataBaseNameObj; } set { dataBaseNameObj = value; } } [Browsable(false)] [JsonIgnore] public IReadOnlyList<DataBaseNameHolder> GetDataBaseNames { get { if(dataBaseNameObjs == null) { dataBaseNameObjs = new List<DataBaseNameHolder>(); IConnectionStringHelper connectionStringHelper = serviceProvider.GetRequiredService<IConnectionStringHelper>(); foreach(var dbname in connectionStringHelper.GetConnectionStringsMap().Keys) { ((List<DataBaseNameHolder>)dataBaseNameObjs).Add(new DataBaseNameHolder(dbname)); } } return dataBaseNameObjs; } } public void SetServiceProvider(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } } [DomainComponent] //set readonly using model editor //<DetailView Id = "DataBaseNameHolder_DetailView" AllowEdit="False" /> //CustomLogonController checks that the DataBaseNameHolder property is not null public class DataBaseNameHolder : NonPersistentLiteObject { public DataBaseNameHolder(string name) { Name = name; } public string Name { get; } }
XPO/NET_Framework/RuntimeDbChooser.Win/Program.cs
C#
using System; using System.Configuration; using System.Windows.Forms; using DevExpress.ExpressApp; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.Win; using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl; using DevExpress.XtraEditors; namespace RuntimeDbChooser.Win { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { DevExpress.ExpressApp.FrameworkSettings.DefaultSettingsCompatibilityMode = DevExpress.ExpressApp.FrameworkSettingsCompatibilityMode.Latest; #if EASYTEST DevExpress.ExpressApp.Win.EasyTest.EasyTestRemotingRegistration.Register(); #endif WindowsFormsSettings.LoadApplicationSettings(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); DevExpress.Utils.ToolTipController.DefaultController.ToolTipType = DevExpress.Utils.ToolTipType.SuperTip; EditModelPermission.AlwaysGranted = System.Diagnostics.Debugger.IsAttached; if(Tracing.GetFileLocationFromSettings() == DevExpress.Persistent.Base.FileLocation.CurrentUserApplicationDataFolder) { Tracing.LocalUserAppDataPath = Application.LocalUserAppDataPath; } Tracing.Initialize(); RuntimeDbChooserWindowsFormsApplication winApplication = new RuntimeDbChooserWindowsFormsApplication(); winApplication.GetSecurityStrategy().RegisterXPOAdapterProviders(); if(ConfigurationManager.ConnectionStrings["ConnectionString"] != null) { winApplication.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString; } #if EASYTEST if(ConfigurationManager.ConnectionStrings["EasyTestConnectionString"] != null) { winApplication.ConnectionString = ConfigurationManager.ConnectionStrings["EasyTestConnectionString"].ConnectionString; } #endif #if DEBUG if(System.Diagnostics.Debugger.IsAttached && winApplication.CheckCompatibilityType == CheckCompatibilityType.DatabaseSchema) { winApplication.DatabaseUpdateMode = DatabaseUpdateMode.UpdateDatabaseAlways; } #endif try { winApplication.Setup(); winApplication.Start(); } catch(Exception e) { winApplication.StopSplash(); winApplication.HandleException(e); } } } }
XPO/NET_Framework/RuntimeDbChooser.Win/WinApplication.cs
C#
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.Security.ClientServer; using DevExpress.ExpressApp.Win; using DevExpress.ExpressApp.Win.Utils; using DevExpress.ExpressApp.Xpo; using RuntimeDbChooser.Module.BusinessObjects; using System; using System.Collections.Generic; namespace RuntimeDbChooser.Win { // For more typical usage scenarios, be sure to check out https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Win.WinApplication._members public partial class RuntimeDbChooserWindowsFormsApplication : WinApplication { private static Dictionary<string, bool> isCompatibilityChecked = new Dictionary<string, bool>(); public RuntimeDbChooserWindowsFormsApplication() { InitializeComponent(); //ActiveDirectoryAuthentication //((SecurityStrategyComplex)Security).Authentication = new Module.ChangeDatabaseActiveDirectoryAuthentication(); //((SecurityStrategyComplex)Security).Authentication.UserType = typeof(Module.BusinessObjects.ApplicationUser); //((SecurityStrategyComplex)Security).Authentication.UserLoginInfoType = typeof(Module.BusinessObjects.ApplicationUserLoginInfo); SplashScreen = new DXSplashScreen(typeof(XafSplashScreen), new DefaultOverlayFormOptions()); } protected override LogonController CreateLogonController() { return CreateController<Controllers.CustomLogonController>(); } protected override bool IsCompatibilityChecked { get { return isCompatibilityChecked.ContainsKey(ConnectionString) ? isCompatibilityChecked[ConnectionString] : false; } set { isCompatibilityChecked[ConnectionString] = value; } } protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) { args.ObjectSpaceProviders.Add(new SecuredObjectSpaceProvider((SecurityStrategyComplex)Security, XPObjectSpaceProvider.GetDataStoreProvider(args.ConnectionString, args.Connection, false), false)); args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo, null)); } private void RuntimeDbChooserWindowsFormsApplication_CustomizeLanguagesList(object sender, CustomizeLanguagesListEventArgs e) { string userLanguageName = System.Threading.Thread.CurrentThread.CurrentUICulture.Name; if(userLanguageName != "en-US" && e.Languages.IndexOf(userLanguageName) == -1) { e.Languages.Add(userLanguageName); } } private void RuntimeDbChooserWindowsFormsApplication_DatabaseVersionMismatch(object sender, DevExpress.ExpressApp.DatabaseVersionMismatchEventArgs e) { #if EASYTEST e.Updater.Update(); e.Handled = true; #else if(System.Diagnostics.Debugger.IsAttached) { e.Updater.Update(); e.Handled = true; } else { string message = "The application cannot connect to the specified database, " + "because the database doesn't exist, its version is older " + "than that of the application or its schema does not match " + "the ORM data model structure. To avoid this error, use one " + "of the solutions from the https://www.devexpress.com/kb=T367835 KB Article."; if(e.CompatibilityError != null && e.CompatibilityError.Exception != null) { message += "\r\n\r\nInner exception: " + e.CompatibilityError.Exception.Message; } throw new InvalidOperationException(message); } #endif } } }
XPO/NET_Framework/RuntimeDbChooser.Win/Controllers/CustomLogonController.cs
C#
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Actions; using RuntimeDbChooser.Module.BusinessObjects; namespace RuntimeDbChooser.Win.Controllers { public class CustomLogonController : LogonController { protected override void Accept(SimpleActionExecuteEventArgs args) { string targetDataBaseName = ((IDatabaseNameParameter)Application.Security.LogonParameters).DatabaseName; string newConnectionString = MSSqlServerChangeDatabaseHelper.PatchConnectionString(targetDataBaseName, Application.ConnectionString); if(Application.ConnectionString != newConnectionString) { Application.ObjectSpaceProviderContainer?.Clear(); Application.ConnectionString = newConnectionString; } base.Accept(args); } } }
XPO/NET_Framework/RuntimeDbChooser.Web/WebApplication.cs
C#
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Security; using DevExpress.ExpressApp.Security.ClientServer; using DevExpress.ExpressApp.Web; using DevExpress.ExpressApp.Xpo; using System; using System.Collections.Concurrent; using System.Collections.Generic; namespace RuntimeDbChooser.Web { // For more typical usage scenarios, be sure to check out https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Web.WebApplication public partial class RuntimeDbChooserAspNetApplication : WebApplication { private static ConcurrentDictionary<string, bool> isCompatibilityChecked = new ConcurrentDictionary<string, bool>(); private static Dictionary<string, IXpoDataStoreProvider> xpoDataStoreProviderDictionary = new Dictionary<string, IXpoDataStoreProvider>(); private DevExpress.ExpressApp.SystemModule.SystemModule module1; private DevExpress.ExpressApp.Web.SystemModule.SystemAspNetModule module2; private RuntimeDbChooser.Module.RuntimeDbChooserModule module3; private RuntimeDbChooser.Module.Web.RuntimeDbChooserAspNetModule module4; private DevExpress.ExpressApp.Security.SecurityModule securityModule1; private DevExpress.ExpressApp.Security.SecurityStrategyComplex securityStrategyComplex1; private DevExpress.ExpressApp.Security.AuthenticationStandard authenticationStandard1; private DevExpress.ExpressApp.Validation.ValidationModule validationModule; private DevExpress.ExpressApp.Validation.Web.ValidationAspNetModule validationAspNetModule; public RuntimeDbChooserAspNetApplication() { InitializeComponent(); //ActiveDirectoryAuthentication //((SecurityStrategyComplex)Security).Authentication = new Module.ChangeDatabaseActiveDirectoryAuthentication(); //((SecurityStrategyComplex)Security).Authentication.UserType = typeof(Module.BusinessObjects.ApplicationUser); //((SecurityStrategyComplex)Security).Authentication.UserLoginInfoType = typeof(Module.BusinessObjects.ApplicationUserLoginInfo); } protected override LogonController CreateLogonController() { return CreateController<Controllers.CustomLogonController>(); } protected override bool IsCompatibilityChecked { get { return isCompatibilityChecked.ContainsKey(ConnectionString); } set { isCompatibilityChecked.TryAdd(ConnectionString, value); } } protected override IViewUrlManager CreateViewUrlManager() { return new ViewUrlManager(); } protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) { args.ObjectSpaceProvider = new SecuredObjectSpaceProvider((SecurityStrategyComplex)Security, GetDataStoreProvider(args.ConnectionString, args.Connection), true); args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo, null)); } private IXpoDataStoreProvider GetDataStoreProvider(string connectionString, System.Data.IDbConnection connection) { IXpoDataStoreProvider xpoDataStoreProvider; lock(xpoDataStoreProviderDictionary) { if(!xpoDataStoreProviderDictionary.TryGetValue(connectionString, out xpoDataStoreProvider)) { //TODO Minakov the enablePoolingInConnectionString parameter should be true. Change after IObjectSpace.DataBase fix xpoDataStoreProvider = XPObjectSpaceProvider.GetDataStoreProvider(connectionString, connection, false); xpoDataStoreProviderDictionary[connectionString] = xpoDataStoreProvider; } } return xpoDataStoreProvider; } private void RuntimeDbChooserAspNetApplication_DatabaseVersionMismatch(object sender, DevExpress.ExpressApp.DatabaseVersionMismatchEventArgs e) { #if EASYTEST e.Updater.Update(); e.Handled = true; #else if(System.Diagnostics.Debugger.IsAttached) { e.Updater.Update(); e.Handled = true; } else { string message = "The application cannot connect to the specified database, " + "because the database doesn't exist, its version is older " + "than that of the application or its schema does not match " + "the ORM data model structure. To avoid this error, use one " + "of the solutions from the https://www.devexpress.com/kb=T367835 KB Article."; if(e.CompatibilityError != null && e.CompatibilityError.Exception != null) { message += "\r\n\r\nInner exception: " + e.CompatibilityError.Exception.Message; } throw new InvalidOperationException(message); } #endif } private void InitializeComponent() { this.module1 = new DevExpress.ExpressApp.SystemModule.SystemModule(); this.module2 = new DevExpress.ExpressApp.Web.SystemModule.SystemAspNetModule(); this.module3 = new RuntimeDbChooser.Module.RuntimeDbChooserModule(); this.module4 = new RuntimeDbChooser.Module.Web.RuntimeDbChooserAspNetModule(); this.securityModule1 = new DevExpress.ExpressApp.Security.SecurityModule(); this.securityStrategyComplex1 = new DevExpress.ExpressApp.Security.SecurityStrategyComplex(); this.securityStrategyComplex1.SupportNavigationPermissionsForTypes = false; this.authenticationStandard1 = new DevExpress.ExpressApp.Security.AuthenticationStandard(); this.validationModule = new DevExpress.ExpressApp.Validation.ValidationModule(); this.validationAspNetModule = new DevExpress.ExpressApp.Validation.Web.ValidationAspNetModule(); ((System.ComponentModel.ISupportInitialize)(this)).BeginInit(); // // securityStrategyComplex1 // this.securityStrategyComplex1.Authentication = this.authenticationStandard1; this.securityStrategyComplex1.RoleType = typeof(DevExpress.Persistent.BaseImpl.PermissionPolicy.PermissionPolicyRole); this.securityStrategyComplex1.UserType = typeof(Module.BusinessObjects.ApplicationUser); // // securityModule1 // this.securityModule1.UserType = typeof(Module.BusinessObjects.ApplicationUser); // // authenticationStandard1 // this.authenticationStandard1.LogonParametersType = typeof(Module.BusinessObjects.CustomLogonParametersForStandardAuthentication); this.authenticationStandard1.UserType = typeof(Module.BusinessObjects.ApplicationUser); this.authenticationStandard1.UserLoginInfoType = typeof(Module.BusinessObjects.ApplicationUserLoginInfo); // // RuntimeDbChooserAspNetApplication // this.ApplicationName = "RuntimeDbChooser"; this.CheckCompatibilityType = DevExpress.ExpressApp.CheckCompatibilityType.DatabaseSchema; this.Modules.Add(this.module1); this.Modules.Add(this.module2); this.Modules.Add(this.module3); this.Modules.Add(this.module4); this.Modules.Add(this.securityModule1); this.Security = this.securityStrategyComplex1; this.Modules.Add(this.validationModule); this.Modules.Add(this.validationAspNetModule); this.DatabaseVersionMismatch += new System.EventHandler<DevExpress.ExpressApp.DatabaseVersionMismatchEventArgs>(this.RuntimeDbChooserAspNetApplication_DatabaseVersionMismatch); ((System.ComponentModel.ISupportInitialize)(this)).EndInit(); } } }
XPO/NET_Framework/RuntimeDbChooser.Web/Controllers/CustomLogonController.cs
C#
using DevExpress.ExpressApp.Actions; using DevExpress.ExpressApp.Web; using RuntimeDbChooser.Module.BusinessObjects; namespace RuntimeDbChooser.Web.Controllers { public class CustomLogonController : WebLogonController { protected override void Accept(SimpleActionExecuteEventArgs args) { string targetDataBaseName = ((IDatabaseNameParameter)Application.Security.LogonParameters).DatabaseName; string newConnectionString = MSSqlServerChangeDatabaseHelper.PatchConnectionString(targetDataBaseName, Application.ConnectionString); if(Application.ConnectionString != newConnectionString) { Application.ObjectSpaceProviderContainer?.Clear(); Application.ConnectionString = newConnectionString; } base.Accept(args); } } }
EFCore/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/Startup.cs
C#
using DevExpress.Blazor.Reporting; using DevExpress.ExpressApp.ApplicationBuilder; using DevExpress.ExpressApp.Blazor.ApplicationBuilder; using DevExpress.ExpressApp.Blazor.Services; using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Components.Server.Circuits; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using RuntimeDbChooser.Blazor.Server.Services; using RuntimeDbChooser.Module; using RuntimeDbChooser.Module.Blazor; using RuntimeDbChooser.Module.BusinessObjects; using RuntimeDbChooser.Services; namespace RuntimeDbChooser.Blazor.Server { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddSingleton(typeof(HubConnectionHandler<>), typeof(ProxyHubConnectionHandler<>)); services.AddRazorPages(); services.AddServerSideBlazor(); services.AddHttpContextAccessor(); services.AddScoped<CircuitHandler, CircuitHandlerProxy>(); services.AddXaf(Configuration, builder => { builder.UseApplication<RuntimeDbChooserBlazorApplication>(); builder.Modules .AddConditionalAppearance() .AddReports(options => { options.EnableInplaceReports = true; options.ReportDataType = typeof(DevExpress.Persistent.BaseImpl.EF.ReportDataV2); options.ReportStoreMode = DevExpress.ExpressApp.ReportsV2.ReportStoreModes.XML; }) .AddValidation() .Add<RuntimeDbChooserModule>() .Add<RuntimeDbChooserBlazorModule>(); builder.ObjectSpaceProviders .AddSecuredEFCore().WithDbContext<DemoDbContext>((serviceProvider, options) => { //Configure the connection string based on logon parameter values. var connectionStringProvider = serviceProvider.GetRequiredService<IConnectionStringProvider>(); string connectionString = connectionStringProvider.GetConnectionString(); options.UseSqlServer(connectionString); options.UseXafServiceProviderContainer(serviceProvider); options.UseLazyLoadingProxies(); options.UseChangeTrackingProxies(); }, ServiceLifetime.Transient) .AddNonPersistent(); builder.Security .UseIntegratedMode(options => { options.RoleType = typeof(PermissionPolicyRole); options.UserType = typeof(ApplicationUser); options.UserLoginInfoType = typeof(ApplicationUserLoginInfo); }) .AddPasswordAuthentication(options => { options.IsSupportChangePassword = true; options.LogonParametersType = typeof(CustomLogonParametersForStandardAuthentication); }); builder.AddBuildStep(application => { application.ApplicationName = "RuntimeDbChooser"; application.CheckCompatibilityType = DevExpress.ExpressApp.CheckCompatibilityType.DatabaseSchema; application.DatabaseVersionMismatch += (s, e) => { e.Updater.Update(); e.Handled = true; }; }); }); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => { options.LoginPath = "/LoginPage"; }); services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder( CookieAuthenticationDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .RequireXafAuthentication() .Build(); }); services.AddScoped<IConnectionStringProvider, ConnectionStringProvider>(); services.AddSingleton<IConnectionStringHelper, ConnectionStringHelper>(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if(env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseXaf(); app.UseDevExpressBlazorReporting(); app.UseEndpoints(endpoints => { endpoints.MapXafEndpoints(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); endpoints.MapControllers(); }); } } }
XPO/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/Startup.cs
C#
using DevExpress.Blazor.Reporting; using DevExpress.ExpressApp.ApplicationBuilder; using DevExpress.ExpressApp.Blazor.ApplicationBuilder; using DevExpress.ExpressApp.Blazor.Services; using DevExpress.ExpressApp.Security; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Components.Server.Circuits; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using RuntimeDbChooser.Blazor.Server.Services; using RuntimeDbChooser.Module; using RuntimeDbChooser.Module.Blazor; using RuntimeDbChooser.Module.BusinessObjects; using RuntimeDbChooser.Services; namespace RuntimeDbChooser.Blazor.Server { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddSingleton(typeof(HubConnectionHandler<>), typeof(ProxyHubConnectionHandler<>)); services.AddRazorPages(); services.AddServerSideBlazor(); services.AddHttpContextAccessor(); //services.AddSingleton<XpoDataStoreProviderAccessor>(); services.AddScoped<CircuitHandler, CircuitHandlerProxy>(); services.AddXaf(Configuration, builder => { builder.UseApplication<RuntimeDbChooserBlazorApplication>(); builder.Modules .AddConditionalAppearance() .AddReports() .AddValidation() .Add<RuntimeDbChooserModule>() .Add<RuntimeDbChooserBlazorModule>(); builder.ObjectSpaceProviders .AddSecuredXpo((serviceProvider, options) => { //Configure the connection string based on logon parameter values. options.ConnectionString = serviceProvider.GetRequiredService<IConnectionStringProvider>().GetConnectionString(); var useMemoryStore = false; options.EnablePoolingInConnectionString = !useMemoryStore; options.ThreadSafe = true; options.UseSharedDataStoreProvider = true; }) .AddNonPersistent(); builder.Security .UseIntegratedMode(options => { options.RoleType = typeof(DevExpress.Persistent.BaseImpl.PermissionPolicy.PermissionPolicyRole); options.UserType = typeof(ApplicationUser); options.UserLoginInfoType = typeof(ApplicationUserLoginInfo); options.UseXpoPermissionsCaching(); }) .AddPasswordAuthentication(options => { options.IsSupportChangePassword = true; options.LogonParametersType = typeof(CustomLogonParametersForStandardAuthentication); }); builder.AddBuildStep(application => { application.ApplicationName = "RuntimeDbChooser"; application.CheckCompatibilityType = DevExpress.ExpressApp.CheckCompatibilityType.DatabaseSchema; application.DatabaseVersionMismatch += (s, e) => { e.Updater.Update(); e.Handled = true; }; }); }); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => { options.LoginPath = "/LoginPage"; }); services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder( CookieAuthenticationDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .RequireXafAuthentication() .Build(); }); services.AddScoped<IConnectionStringProvider, ConnectionStringProvider>(); services.AddSingleton<IConnectionStringHelper, ConnectionStringHelper>(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if(env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseXaf(); app.UseDevExpressBlazorReporting(); app.UseEndpoints(endpoints => { endpoints.MapXafEndpoints(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); endpoints.MapControllers(); }); } } }
EFCore/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/BlazorApplication.cs
C#
using System.Collections.Concurrent; using DevExpress.ExpressApp; using DevExpress.ExpressApp.Blazor; using Microsoft.Extensions.DependencyInjection; using RuntimeDbChooser.Blazor.Server.Services; using RuntimeDbChooser.Services; namespace RuntimeDbChooser.Blazor.Server { public class RuntimeDbChooserBlazorApplication : BlazorApplication { private static ConcurrentDictionary<string, bool> isCompatibilityChecked = new ConcurrentDictionary<string, bool>(); protected override bool IsCompatibilityChecked { get => isCompatibilityChecked.ContainsKey(ServiceProvider.GetRequiredService<IConnectionStringProvider>().GetConnectionString()); set => isCompatibilityChecked.TryAdd(ServiceProvider.GetRequiredService<IConnectionStringProvider>().GetConnectionString(), value); } protected override void OnSetupStarted() { base.OnSetupStarted(); #if DEBUG if(System.Diagnostics.Debugger.IsAttached && CheckCompatibilityType == CheckCompatibilityType.DatabaseSchema) { DatabaseUpdateMode = DatabaseUpdateMode.UpdateDatabaseAlways; } #endif #if EASYTEST DatabaseUpdateMode = DatabaseUpdateMode.UpdateDatabaseAlways; #endif } protected override LogonController CreateLogonController() { return CreateController<Controllers.CustomLogonController>(); } } }
XPO/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/BlazorApplication.cs
C#
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Blazor; using Microsoft.Extensions.DependencyInjection; using RuntimeDbChooser.Blazor.Server.Services; using RuntimeDbChooser.Services; using System.Collections.Concurrent; namespace RuntimeDbChooser.Blazor.Server { public class RuntimeDbChooserBlazorApplication : BlazorApplication { private static ConcurrentDictionary<string, bool> isCompatibilityChecked = new ConcurrentDictionary<string, bool>(); protected override bool IsCompatibilityChecked { get => isCompatibilityChecked.ContainsKey(ServiceProvider.GetRequiredService<IConnectionStringProvider>().GetConnectionString()); set => isCompatibilityChecked.TryAdd(ServiceProvider.GetRequiredService<IConnectionStringProvider>().GetConnectionString(), value); } protected override void OnSetupStarted() { base.OnSetupStarted(); #if DEBUG if(System.Diagnostics.Debugger.IsAttached && CheckCompatibilityType == CheckCompatibilityType.DatabaseSchema) { DatabaseUpdateMode = DatabaseUpdateMode.UpdateDatabaseAlways; } #endif } protected override LogonController CreateLogonController() { return CreateController<Controllers.CustomLogonController>(); } } }
XPO/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/Services/XpoDataStoreProviderAccessor.cs
C#
//using DevExpress.ExpressApp.Xpo; //using System.Collections.Concurrent; //namespace RuntimeDbChooser.Blazor.Server.Services; //public class XpoDataStoreProviderAccessor { // private readonly ConcurrentDictionary<string, IXpoDataStoreProvider> xpoDataStoreProviderDictionary = new ConcurrentDictionary<string, IXpoDataStoreProvider>(); // public IXpoDataStoreProvider GetDataStoreProvider(string connectionString) { // return xpoDataStoreProviderDictionary.GetOrAdd(connectionString, CreateDataStoreProvider); // IXpoDataStoreProvider CreateDataStoreProvider(string connectionString) { // return XPObjectSpaceProvider.GetDataStoreProvider(connectionString, null, true); // } // } //}
EFCore/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/Services/ConnectionStringProvider.cs
C#
using DevExpress.ExpressApp.Security; using RuntimeDbChooser.Services; using System.Linq; namespace RuntimeDbChooser.Blazor.Server.Services; public class ConnectionStringProvider : IConnectionStringProvider { readonly ILogonParameterProvider logonParameterProvider; readonly IConnectionStringHelper connectionStringHelper; public ConnectionStringProvider(ILogonParameterProvider logonParameterProvider, IConnectionStringHelper connectionStringHelper) { this.logonParameterProvider = logonParameterProvider; this.connectionStringHelper = connectionStringHelper; } public string GetConnectionString() { //Configure the connection string based on logon parameter values. string? targetDataBaseName = logonParameterProvider.GetLogonParameters<IDatabaseNameParameter>().DatabaseName?.Name; if(targetDataBaseName != null) { return connectionStringHelper.GetConnectionStringsMap()[targetDataBaseName]; } return connectionStringHelper.GetConnectionStringsMap().Values.First(); } }
XPO/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/Services/ConnectionStringProvider.cs
C#
using DevExpress.ExpressApp.Security; using RuntimeDbChooser.Services; namespace RuntimeDbChooser.Blazor.Server.Services; public class ConnectionStringProvider : IConnectionStringProvider { readonly ILogonParameterProvider logonParameterProvider; readonly IConnectionStringHelper connectionStringHelper; public ConnectionStringProvider(ILogonParameterProvider logonParameterProvider, IConnectionStringHelper connectionStringHelper) { this.logonParameterProvider = logonParameterProvider; this.connectionStringHelper = connectionStringHelper; } public string GetConnectionString() { //Configure the connection string based on logon parameter values. string? targetDataBaseName = logonParameterProvider.GetLogonParameters<IDatabaseNameParameter>().DatabaseName?.Name; if(targetDataBaseName != null) { return connectionStringHelper.GetConnectionStringsMap()[targetDataBaseName]; } return "not set"; } }
EFCore/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/Services/ConnectionStringHelper.cs
C#
using Microsoft.Extensions.Configuration; using RuntimeDbChooser.Services; using System.Collections.Generic; namespace RuntimeDbChooser.Blazor.Server.Services; public class ConnectionStringHelper : IConnectionStringHelper { readonly IConfiguration configuration; public ConnectionStringHelper(IConfiguration configuration) { this.configuration = configuration; } public IDictionary<string, string> GetConnectionStringsMap() { Dictionary<string, string> connectionStrings = new Dictionary<string, string>(); var connectionsStr = configuration.GetSection("ConnectionStrings"); foreach(var conf in connectionsStr.GetChildren()) { connectionStrings.Add(conf.Key, conf.Value); } return connectionStrings; } }
XPO/ASP.NETCore/Blazor/RuntimeDbChooser.Blazor.Server/Services/ConnectionStringHelper.cs
C#
using Microsoft.Extensions.Configuration; using RuntimeDbChooser.Services; using System.Collections.Generic; namespace RuntimeDbChooser.Blazor.Server.Services; public class ConnectionStringHelper : IConnectionStringHelper { readonly IConfiguration configuration; public ConnectionStringHelper(IConfiguration configuration) { this.configuration = configuration; } public IDictionary<string, string> GetConnectionStringsMap() { Dictionary<string, string> connectionStrings = new Dictionary<string, string>(); var connectionsStr = configuration.GetSection("ConnectionStrings"); foreach(var conf in connectionsStr.GetChildren()) { connectionStrings.Add(conf.Key, conf.Value); } return connectionStrings; } }
EFCore/ASP.NETCore/Blazor/RuntimeDbChooser.Module/BusinessObjects/DbContext.cs
C#
using System; using DevExpress.ExpressApp.Design; using DevExpress.ExpressApp.EFCore.DesignTime; using DevExpress.ExpressApp.EFCore.Updating; using DevExpress.ExpressApp.Security; using DevExpress.Persistent.BaseImpl.EF; using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using RuntimeDbChooser.Services; namespace RuntimeDbChooser.Module.BusinessObjects; public class DbContextInitializer : DbContextTypesInfoInitializerBase { // This code allows our Model Editor to get relevant EF Core metadata at design time. // For details, please refer to https://supportcenter.devexpress.com/ticket/details/t933891. protected override DbContext CreateDbContext() { var optionsBuilder = new DbContextOptionsBuilder<DemoDbContext>() .UseSqlServer(@";") .UseChangeTrackingProxies() .UseLazyLoadingProxies(); return new DemoDbContext(optionsBuilder.Options, null); } } //This factory creates DbContext for design-time services. For example, it is required for database migration. public class EFCoreDemoDesignTimeDbContextFactory : IDesignTimeDbContextFactory<DemoDbContext> { public DemoDbContext CreateDbContext(string[] args) { throw new InvalidOperationException("Make sure that the database connection string and connection provider are correct. After that, uncomment the code below and remove this exception."); //var optionsBuilder = new DbContextOptionsBuilder<EFCoreDemoDbContext>(); //optionsBuilder.UseSqlServer(@"Integrated Security=SSPI;Pooling=false;MultipleActiveResultSets=true;Data Source=(localdb)\\mssqllocaldb;Initial Catalog=EFCoreDemo_v22.1;ConnectRetryCount=0;"); //optionsBuilder.UseChangeTrackingProxies(); //optionsBuilder.UseLazyLoadingProxies(); //return new EFCoreDemoDbContext(optionsBuilder.Options); } } [TypesInfoInitializer(typeof(DbContextInitializer))] public class DemoDbContext : DbContext { readonly IConnectionStringProvider connectionStringProvider; public DemoDbContext(DbContextOptions<DemoDbContext> options, IConnectionStringProvider connectionStringProvider) : base(options) { this.connectionStringProvider = connectionStringProvider; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasChangeTrackingStrategy(ChangeTrackingStrategy.ChangingAndChangedNotificationsWithOriginalValues); modelBuilder.Entity<MediaDataObject>().HasOne(md => md.MediaResource).WithOne().HasForeignKey<MediaResourceObject>(p => p.ID); modelBuilder.Entity<ApplicationUserLoginInfo>(b => { b.HasIndex(nameof(ISecurityUserLoginInfo.LoginProviderName), nameof(ISecurityUserLoginInfo.ProviderUserKey)).IsUnique(); }); } public DbSet<ApplicationUser> Users { get; set; } public DbSet<ApplicationUserLoginInfo> UserLoginInfos { get; set; } public DbSet<ModelDifference> ModelDifferences { get; set; } public DbSet<ModelDifferenceAspect> ModelDifferenceAspects { get; set; } public DbSet<PermissionPolicyRole> Roles { get; set; } public DbSet<ModuleInfo> ModulesInfo { get; set; } public DbSet<ReportDataV2> ReportData { get; set; } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.