using System; using System.Configuration; using System.Linq; using System.Web.Configuration; using System.Xml.Linq; using Umbraco.Core.Configuration; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core { /// /// The Umbraco Database context /// /// /// One per AppDomain, represents the Umbraco database /// public class DatabaseContext { private bool _configured; #region Singleton private static readonly Lazy lazy = new Lazy(() => new DatabaseContext()); /// /// Gets the current Database Context. /// public static DatabaseContext Current { get { return lazy.Value; } } private DatabaseContext() { } #endregion /// /// Gets the object for doing CRUD operations /// against custom tables that resides in the Umbraco database. /// /// /// This should not be used for CRUD operations or queries against the /// standard Umbraco tables! /// public Database Database { get { return DatabaseFactory.Current.Database; } } /// /// Boolean indicating whether the database has been configured /// public bool IsDatabaseConfigured { get { return _configured; } } /// /// Configure a ConnectionString for the embedded database. /// public void ConfigureDatabaseConnection() { var providerName = "System.Data.SqlServerCe.4.0"; var connectionString = "Datasource=|DataDirectory|Umbraco.sdf"; var appSettingsConnection = @"datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;data source=|DataDirectory|\Umbraco.sdf"; SaveConnectionString(connectionString, appSettingsConnection, providerName); Initialize(); } /// /// Configure a ConnectionString that has been entered manually. /// /// /// Please note that we currently assume that the 'System.Data.SqlClient' provider can be used. /// /// public void ConfigureDatabaseConnection(string connectionString) { SaveConnectionString(connectionString, connectionString, string.Empty); Initialize(); } /// /// Configures a ConnectionString for the Umbraco database based on the passed in properties from the installer. /// /// Name or address of the database server /// Name of the database /// Database Username /// Database Password /// Type of the provider to be used (Sql, Sql Azure, Sql Ce, MySql) public void ConfigureDatabaseConnection(string server, string databaseName, string user, string password, string databaseProvider) { string connectionString; string appSettingsConnection; string providerName = "System.Data.SqlClient"; if(databaseProvider.ToLower().Contains("mysql")) { providerName = "MySql.Data.MySqlClient"; connectionString = string.Format("Server={0}; Database={1};Uid={2};Pwd={3}", server, databaseName, user, password); appSettingsConnection = connectionString; } else if(databaseProvider.ToLower().Contains("azure")) { connectionString = string.Format("Server=tcp:{0}.database.windows.net;Database={1};User ID={2}@{0};Password={3}", server, databaseName, user, password); appSettingsConnection = connectionString; } else { connectionString = string.Format("server={0};database={1};user id={2};password={3}", server, databaseName, user, password); appSettingsConnection = connectionString; } SaveConnectionString(connectionString, appSettingsConnection, providerName); Initialize(); } /// /// Saves the connection string as a proper .net ConnectionString and the legacy AppSettings key/value. /// /// /// /// private void SaveConnectionString(string connectionString, string appSettingsConnection, string providerName) { //Set the connection string for the new datalayer var connectionStringSettings = string.IsNullOrEmpty(providerName) ? new ConnectionStringSettings(GlobalSettings.UmbracoConnectionName, connectionString) : new ConnectionStringSettings(GlobalSettings.UmbracoConnectionName, connectionString, providerName); //Set the connection string in appsettings used in the legacy datalayer GlobalSettings.DbDsn = appSettingsConnection; //ConfigurationManager.ConnectionStrings.Add(conectionString); var webConfig = new WebConfigurationFileMap(); var vDir = GlobalSettings.FullpathToRoot; foreach (VirtualDirectoryMapping v in webConfig.VirtualDirectories) { if (v.IsAppRoot) { vDir = v.PhysicalDirectory; } } string fileName = String.Concat(vDir, "web.config"); var xml = XDocument.Load(fileName); var connectionstrings = xml.Root.Descendants("connectionStrings").Single(); // Update connectionString if it exists, or else create a new appSetting for the given key and value var setting = connectionstrings.Descendants("add").FirstOrDefault(s => s.Attribute("name").Value == GlobalSettings.UmbracoConnectionName); if (setting == null) connectionstrings.Add(new XElement("add", new XAttribute("name", GlobalSettings.UmbracoConnectionName), new XAttribute("connectionString", connectionStringSettings), new XAttribute("providerName", providerName))); else { setting.Attribute("connectionString").Value = connectionString; } xml.Save(fileName); ConfigurationManager.RefreshSection("connectionStrings"); } /// /// Internal method to initialize the database configuration. /// /// /// If an Umbraco connectionstring exists the database can be configured on app startup, /// but if its a new install the entry doesn't exist and the db cannot be configured. /// So for new installs the Initialize() method should be called after the connectionstring /// has been added to the web.config. /// internal void Initialize() { if (ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName] != null) { var providerName = "System.Data.SqlClient"; if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName)) providerName = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName; if (providerName.StartsWith("MySql")) { SyntaxConfig.SqlSyntaxProvider = MySqlSyntax.Provider; } else if (providerName.Contains("SqlServerCe")) { SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; } else { SyntaxConfig.SqlSyntaxProvider = SqlServerSyntax.Provider; } _configured = true; } else { _configured = false; } } } }