v10: Use ForceCreateDatabase during unattended install and extend GetUmbracoConnectionString extension methods (#12397)
* Add extension methods to get the Umbraco connection string/provider name from configuration * Added tests for configuration extension methods. * Fix issue with InstallMissingDatabase and ForceCreateDatabase * Fix comments * Revert casing change in GenerateConnectionString * Re-add AddOptions (without config binding) to fix test * Update src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs Co-authored-by: Ronald Barendse <ronald@barend.se> * Update src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs * Update src/Umbraco.Infrastructure/Runtime/RuntimeState.cs * Whitespace and documentation updates * Add DatabaseProviderMetadataExtensions * Filter before ordering * Replace DataDirectory placeholder when setting connection string Co-authored-by: Andy Butland <abutland73@gmail.com> Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
@@ -6,16 +6,18 @@ using Umbraco.Extensions;
|
||||
namespace Umbraco.Cms.Core.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Configures ConnectionStrings.
|
||||
/// Configures the <see cref="ConnectionStrings" /> named option.
|
||||
/// </summary>
|
||||
public class ConfigureConnectionStrings : IConfigureNamedOptions<ConnectionStrings>
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConfigureConnectionStrings"/> class.
|
||||
/// Initializes a new instance of the <see cref="ConfigureConnectionStrings" /> class.
|
||||
/// </summary>
|
||||
public ConfigureConnectionStrings(IConfiguration configuration) => _configuration = configuration;
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public ConfigureConnectionStrings(IConfiguration configuration)
|
||||
=> _configuration = configuration;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(ConnectionStrings options) => Configure(Options.DefaultName, options);
|
||||
@@ -35,7 +37,7 @@ public class ConfigureConnectionStrings : IConfigureNamedOptions<ConnectionStrin
|
||||
}
|
||||
|
||||
options.Name = name;
|
||||
options.ConnectionString = _configuration.GetConnectionString(name);
|
||||
options.ProviderName = _configuration.GetConnectionString($"{name}{ConnectionStrings.ProviderNamePostfix}") ?? ConnectionStrings.DefaultProviderName;
|
||||
options.ConnectionString = _configuration.GetUmbracoConnectionString(name, out string? providerName);
|
||||
options.ProviderName = providerName ?? ConnectionStrings.DefaultProviderName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Configuration.Models;
|
||||
|
||||
[UmbracoOptions("ConnectionStrings")]
|
||||
public class ConnectionStrings
|
||||
/// <summary>
|
||||
/// Represents a single connection string.
|
||||
/// </summary>
|
||||
public class ConnectionStrings // TODO: Rename to [Umbraco]ConnectionString (since v10 this only contains a single connection string)
|
||||
{
|
||||
private string? _connectionString;
|
||||
|
||||
@@ -15,20 +17,42 @@ public class ConnectionStrings
|
||||
/// <summary>
|
||||
/// The DataDirectory placeholder.
|
||||
/// </summary>
|
||||
public const string DataDirectoryPlaceholder = "|DataDirectory|";
|
||||
public const string DataDirectoryPlaceholder = ConfigurationExtensions.DataDirectoryPlaceholder;
|
||||
|
||||
/// <summary>
|
||||
/// The postfix used to identify a connection strings provider setting.
|
||||
/// </summary>
|
||||
public const string ProviderNamePostfix = "_ProviderName";
|
||||
public const string ProviderNamePostfix = ConfigurationExtensions.ProviderNamePostfix;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name.
|
||||
/// </value>
|
||||
[Obsolete("This property will be removed in Umbraco 12, because this class is now using named options.")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the connection string.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The connection string.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// When set, the <see cref="DataDirectoryPlaceholder"/> will be replaced with the actual physical path.
|
||||
/// </remarks>
|
||||
public string? ConnectionString
|
||||
{
|
||||
get => _connectionString;
|
||||
set => _connectionString = value?.ReplaceDataDirectoryPlaceholder();
|
||||
set => _connectionString = ConfigurationExtensions.ReplaceDataDirectoryPlaceholder(value);
|
||||
}
|
||||
|
||||
public string? ProviderName { get; set; } = DefaultProviderName;
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the provider.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name of the provider.
|
||||
/// </value>
|
||||
public string? ProviderName { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Cms.Core
|
||||
namespace Umbraco.Cms.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
@@ -62,7 +62,9 @@
|
||||
|
||||
public const string UmbracoDefaultDatabaseName = "Umbraco";
|
||||
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";public const string DefaultUmbracoPath = "~/umbraco";
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";
|
||||
|
||||
public const string DefaultUmbracoPath = "~/umbraco";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -9,105 +7,101 @@ using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Configuration.Models.Validation;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.DependencyInjection
|
||||
namespace Umbraco.Cms.Core.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IUmbracoBuilder" />
|
||||
/// </summary>
|
||||
public static partial class UmbracoBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IUmbracoBuilder"/>
|
||||
/// </summary>
|
||||
public static partial class UmbracoBuilderExtensions
|
||||
private static IUmbracoBuilder AddUmbracoOptions<TOptions>(this IUmbracoBuilder builder, Action<OptionsBuilder<TOptions>>? configure = null)
|
||||
where TOptions : class
|
||||
{
|
||||
|
||||
private static IUmbracoBuilder AddUmbracoOptions<TOptions>(this IUmbracoBuilder builder, Action<OptionsBuilder<TOptions>>? configure = null)
|
||||
where TOptions : class
|
||||
var umbracoOptionsAttribute = typeof(TOptions).GetCustomAttribute<UmbracoOptionsAttribute>();
|
||||
if (umbracoOptionsAttribute is null)
|
||||
{
|
||||
var umbracoOptionsAttribute = typeof(TOptions).GetCustomAttribute<UmbracoOptionsAttribute>();
|
||||
if (umbracoOptionsAttribute is null)
|
||||
throw new ArgumentException($"{typeof(TOptions)} do not have the UmbracoOptionsAttribute.");
|
||||
}
|
||||
|
||||
var optionsBuilder = builder.Services.AddOptions<TOptions>()
|
||||
.Bind(
|
||||
builder.Config.GetSection(umbracoOptionsAttribute.ConfigurationKey),
|
||||
o => o.BindNonPublicProperties = umbracoOptionsAttribute.BindNonPublicProperties)
|
||||
.ValidateDataAnnotations();
|
||||
|
||||
configure?.Invoke(optionsBuilder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Umbraco configuration services and options
|
||||
/// </summary>
|
||||
public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder)
|
||||
{
|
||||
// Register configuration validators.
|
||||
builder.Services.AddSingleton<IValidateOptions<ContentSettings>, ContentSettingsValidator>();
|
||||
builder.Services.AddSingleton<IValidateOptions<GlobalSettings>, GlobalSettingsValidator>();
|
||||
builder.Services.AddSingleton<IValidateOptions<HealthChecksSettings>, HealthChecksSettingsValidator>();
|
||||
builder.Services.AddSingleton<IValidateOptions<RequestHandlerSettings>, RequestHandlerSettingsValidator>();
|
||||
builder.Services.AddSingleton<IValidateOptions<UnattendedSettings>, UnattendedSettingsValidator>();
|
||||
|
||||
// Register configuration sections.
|
||||
builder
|
||||
.AddUmbracoOptions<ModelsBuilderSettings>()
|
||||
.AddUmbracoOptions<ActiveDirectorySettings>()
|
||||
.AddUmbracoOptions<ContentSettings>()
|
||||
.AddUmbracoOptions<CoreDebugSettings>()
|
||||
.AddUmbracoOptions<ExceptionFilterSettings>()
|
||||
.AddUmbracoOptions<GlobalSettings>(optionsBuilder => optionsBuilder.PostConfigure(options =>
|
||||
{
|
||||
throw new ArgumentException($"{typeof(TOptions)} do not have the UmbracoOptionsAttribute.");
|
||||
}
|
||||
|
||||
var optionsBuilder = builder.Services.AddOptions<TOptions>()
|
||||
.Bind(
|
||||
builder.Config.GetSection(umbracoOptionsAttribute.ConfigurationKey),
|
||||
o => o.BindNonPublicProperties = umbracoOptionsAttribute.BindNonPublicProperties
|
||||
)
|
||||
.ValidateDataAnnotations();
|
||||
|
||||
configure?.Invoke(optionsBuilder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Umbraco configuration services and options
|
||||
/// </summary>
|
||||
public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder)
|
||||
{
|
||||
// Register configuration validators.
|
||||
builder.Services.AddSingleton<IValidateOptions<ContentSettings>, ContentSettingsValidator>();
|
||||
builder.Services.AddSingleton<IValidateOptions<GlobalSettings>, GlobalSettingsValidator>();
|
||||
builder.Services.AddSingleton<IValidateOptions<HealthChecksSettings>, HealthChecksSettingsValidator>();
|
||||
builder.Services.AddSingleton<IValidateOptions<RequestHandlerSettings>, RequestHandlerSettingsValidator>();
|
||||
builder.Services.AddSingleton<IValidateOptions<UnattendedSettings>, UnattendedSettingsValidator>();
|
||||
|
||||
// Register configuration sections.
|
||||
builder
|
||||
.AddUmbracoOptions<ModelsBuilderSettings>()
|
||||
.AddUmbracoOptions<ConnectionStrings>()
|
||||
.AddUmbracoOptions<ActiveDirectorySettings>()
|
||||
.AddUmbracoOptions<ContentSettings>()
|
||||
.AddUmbracoOptions<CoreDebugSettings>()
|
||||
.AddUmbracoOptions<ExceptionFilterSettings>()
|
||||
.AddUmbracoOptions<GlobalSettings>(optionsBuilder => optionsBuilder.PostConfigure(options =>
|
||||
if (string.IsNullOrEmpty(options.UmbracoMediaPhysicalRootPath))
|
||||
{
|
||||
if (string.IsNullOrEmpty(options.UmbracoMediaPhysicalRootPath))
|
||||
{
|
||||
options.UmbracoMediaPhysicalRootPath = options.UmbracoMediaPath;
|
||||
}
|
||||
}))
|
||||
.AddUmbracoOptions<HealthChecksSettings>()
|
||||
.AddUmbracoOptions<HostingSettings>()
|
||||
.AddUmbracoOptions<ImagingSettings>()
|
||||
.AddUmbracoOptions<IndexCreatorSettings>()
|
||||
.AddUmbracoOptions<KeepAliveSettings>()
|
||||
.AddUmbracoOptions<LoggingSettings>()
|
||||
.AddUmbracoOptions<MemberPasswordConfigurationSettings>()
|
||||
.AddUmbracoOptions<NuCacheSettings>()
|
||||
.AddUmbracoOptions<RequestHandlerSettings>()
|
||||
.AddUmbracoOptions<RuntimeSettings>()
|
||||
.AddUmbracoOptions<SecuritySettings>()
|
||||
.AddUmbracoOptions<TourSettings>()
|
||||
.AddUmbracoOptions<TypeFinderSettings>()
|
||||
.AddUmbracoOptions<UserPasswordConfigurationSettings>()
|
||||
.AddUmbracoOptions<WebRoutingSettings>()
|
||||
.AddUmbracoOptions<UmbracoPluginSettings>()
|
||||
.AddUmbracoOptions<UnattendedSettings>()
|
||||
.AddUmbracoOptions<RichTextEditorSettings>()
|
||||
.AddUmbracoOptions<BasicAuthSettings>()
|
||||
.AddUmbracoOptions<RuntimeMinificationSettings>()
|
||||
.AddUmbracoOptions<LegacyPasswordMigrationSettings>()
|
||||
.AddUmbracoOptions<PackageMigrationSettings>()
|
||||
.AddUmbracoOptions<ContentDashboardSettings>()
|
||||
.AddUmbracoOptions<HelpPageSettings>();
|
||||
options.UmbracoMediaPhysicalRootPath = options.UmbracoMediaPath;
|
||||
}
|
||||
}))
|
||||
.AddUmbracoOptions<HealthChecksSettings>()
|
||||
.AddUmbracoOptions<HostingSettings>()
|
||||
.AddUmbracoOptions<ImagingSettings>()
|
||||
.AddUmbracoOptions<IndexCreatorSettings>()
|
||||
.AddUmbracoOptions<KeepAliveSettings>()
|
||||
.AddUmbracoOptions<LoggingSettings>()
|
||||
.AddUmbracoOptions<MemberPasswordConfigurationSettings>()
|
||||
.AddUmbracoOptions<NuCacheSettings>()
|
||||
.AddUmbracoOptions<RequestHandlerSettings>()
|
||||
.AddUmbracoOptions<RuntimeSettings>()
|
||||
.AddUmbracoOptions<SecuritySettings>()
|
||||
.AddUmbracoOptions<TourSettings>()
|
||||
.AddUmbracoOptions<TypeFinderSettings>()
|
||||
.AddUmbracoOptions<UserPasswordConfigurationSettings>()
|
||||
.AddUmbracoOptions<WebRoutingSettings>()
|
||||
.AddUmbracoOptions<UmbracoPluginSettings>()
|
||||
.AddUmbracoOptions<UnattendedSettings>()
|
||||
.AddUmbracoOptions<RichTextEditorSettings>()
|
||||
.AddUmbracoOptions<BasicAuthSettings>()
|
||||
.AddUmbracoOptions<RuntimeMinificationSettings>()
|
||||
.AddUmbracoOptions<LegacyPasswordMigrationSettings>()
|
||||
.AddUmbracoOptions<PackageMigrationSettings>()
|
||||
.AddUmbracoOptions<ContentDashboardSettings>()
|
||||
.AddUmbracoOptions<HelpPageSettings>();
|
||||
|
||||
builder.Services.AddSingleton<IConfigureOptions<ConnectionStrings>, ConfigureConnectionStrings>();
|
||||
builder.Services.AddSingleton<IConfigureOptions<ConnectionStrings>, ConfigureConnectionStrings>();
|
||||
|
||||
builder.Services.Configure<InstallDefaultDataSettings>(
|
||||
Constants.Configuration.NamedOptions.InstallDefaultData.Languages,
|
||||
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.Languages}"));
|
||||
builder.Services.Configure<InstallDefaultDataSettings>(
|
||||
Constants.Configuration.NamedOptions.InstallDefaultData.DataTypes,
|
||||
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.DataTypes}"));
|
||||
builder.Services.Configure<InstallDefaultDataSettings>(
|
||||
Constants.Configuration.NamedOptions.InstallDefaultData.MediaTypes,
|
||||
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.MediaTypes}"));
|
||||
builder.Services.Configure<InstallDefaultDataSettings>(
|
||||
Constants.Configuration.NamedOptions.InstallDefaultData.MemberTypes,
|
||||
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.MemberTypes}"));
|
||||
builder.Services.Configure<InstallDefaultDataSettings>(
|
||||
Constants.Configuration.NamedOptions.InstallDefaultData.Languages,
|
||||
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.Languages}"));
|
||||
builder.Services.Configure<InstallDefaultDataSettings>(
|
||||
Constants.Configuration.NamedOptions.InstallDefaultData.DataTypes,
|
||||
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.DataTypes}"));
|
||||
builder.Services.Configure<InstallDefaultDataSettings>(
|
||||
Constants.Configuration.NamedOptions.InstallDefaultData.MediaTypes,
|
||||
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.MediaTypes}"));
|
||||
builder.Services.Configure<InstallDefaultDataSettings>(
|
||||
Constants.Configuration.NamedOptions.InstallDefaultData.MemberTypes,
|
||||
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.MemberTypes}"));
|
||||
|
||||
builder.Services.Configure<RequestHandlerSettings>(options => options.MergeReplacements(builder.Config));
|
||||
builder.Services.Configure<RequestHandlerSettings>(options => options.MergeReplacements(builder.Config));
|
||||
|
||||
return builder;
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
103
src/Umbraco.Core/Extensions/ConfigurationExtensions.cs
Normal file
103
src/Umbraco.Core/Extensions/ConfigurationExtensions.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for configuration.
|
||||
/// </summary>
|
||||
public static class ConfigurationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// The DataDirectory name.
|
||||
/// </summary>
|
||||
internal const string DataDirectoryName = "DataDirectory";
|
||||
|
||||
/// <summary>
|
||||
/// The DataDirectory placeholder.
|
||||
/// </summary>
|
||||
internal const string DataDirectoryPlaceholder = "|DataDirectory|";
|
||||
|
||||
/// <summary>
|
||||
/// The postfix used to identify a connection string provider setting.
|
||||
/// </summary>
|
||||
internal const string ProviderNamePostfix = "_ProviderName";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the provider name for the connection string name (shorthand for <c>GetSection("ConnectionStrings")[name + "_ProviderName"]</c>).
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="name">The connection string key.</param>
|
||||
/// <returns>
|
||||
/// The provider name.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This uses the same convention as the <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0#connection-string-prefixes">Configuration API for connection string environment variables</a>.
|
||||
/// </remarks>
|
||||
public static string? GetConnectionStringProviderName(this IConfiguration configuration, string name)
|
||||
=> configuration.GetConnectionString(name + ProviderNamePostfix);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Umbraco connection string (shorthand for <c>GetSection("ConnectionStrings")[name]</c> and replacing the <c>|DataDirectory|</c> placeholder).
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="name">The connection string key.</param>
|
||||
/// <returns>
|
||||
/// The Umbraco connection string.
|
||||
/// </returns>
|
||||
public static string? GetUmbracoConnectionString(this IConfiguration configuration, string name = Constants.System.UmbracoConnectionName)
|
||||
=> configuration.GetUmbracoConnectionString(name, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Umbraco connection string and provider name (shorthand for <c>GetSection("ConnectionStrings")[Constants.System.UmbracoConnectionName]</c> and replacing the <c>|DataDirectory|</c> placeholder).
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="providerName">The provider name.</param>
|
||||
/// <returns>
|
||||
/// The Umbraco connection string.
|
||||
/// </returns>
|
||||
public static string? GetUmbracoConnectionString(this IConfiguration configuration, out string? providerName)
|
||||
=> configuration.GetUmbracoConnectionString(Constants.System.UmbracoConnectionName, out providerName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Umbraco connection string and provider name (shorthand for <c>GetSection("ConnectionStrings")[name]</c> and replacing the <c>|DataDirectory|</c> placeholder).
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="providerName">The provider name.</param>
|
||||
/// <returns>
|
||||
/// The Umbraco connection string.
|
||||
/// </returns>
|
||||
public static string? GetUmbracoConnectionString(this IConfiguration configuration, string name, out string? providerName)
|
||||
{
|
||||
string? connectionString = configuration.GetConnectionString(name);
|
||||
if (!string.IsNullOrEmpty(connectionString))
|
||||
{
|
||||
// Replace data directory
|
||||
connectionString = ReplaceDataDirectoryPlaceholder(connectionString);
|
||||
|
||||
// Get provider name
|
||||
providerName = configuration.GetConnectionStringProviderName(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
providerName = null;
|
||||
}
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
internal static string? ReplaceDataDirectoryPlaceholder(string? connectionString)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(connectionString))
|
||||
{
|
||||
string? dataDirectory = AppDomain.CurrentDomain.GetData(DataDirectoryName)?.ToString();
|
||||
if (!string.IsNullOrEmpty(dataDirectory))
|
||||
{
|
||||
return connectionString.Replace(DataDirectoryPlaceholder, dataDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,24 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for a connection string.
|
||||
/// </summary>
|
||||
public static class ConnectionStringExtensions
|
||||
{
|
||||
public static class ConnectionStringExtensions
|
||||
{
|
||||
public static bool IsConnectionStringConfigured(this ConnectionStrings connectionString)
|
||||
=> connectionString != null &&
|
||||
!string.IsNullOrWhiteSpace(connectionString.ConnectionString) &&
|
||||
!string.IsNullOrWhiteSpace(connectionString.ProviderName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a connection string from configuration with placeholders replaced.
|
||||
/// </summary>
|
||||
public static string? GetUmbracoConnectionString(
|
||||
this IConfiguration configuration,
|
||||
string connectionStringName = Constants.System.UmbracoConnectionName) =>
|
||||
configuration.GetConnectionString(connectionStringName).ReplaceDataDirectoryPlaceholder();
|
||||
|
||||
/// <summary>
|
||||
/// Replaces instances of the |DataDirectory| placeholder in a string with the value of AppDomain DataDirectory.
|
||||
/// </summary>
|
||||
public static string? ReplaceDataDirectoryPlaceholder(this string input)
|
||||
{
|
||||
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
||||
return input?.Replace(ConnectionStrings.DataDirectoryPlaceholder, dataDirectory);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the connection string is configured (set to a non-empty value).
|
||||
/// </summary>
|
||||
/// <param name="connectionString">The connection string.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the connection string is configured; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsConnectionStringConfigured(this ConnectionStrings connectionString)
|
||||
=> connectionString != null &&
|
||||
!string.IsNullOrWhiteSpace(connectionString.ConnectionString) &&
|
||||
!string.IsNullOrWhiteSpace(connectionString.ProviderName);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
@@ -13,9 +9,7 @@ using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Install.InstallSteps
|
||||
{
|
||||
[InstallSetupStep(InstallationType.NewInstall,
|
||||
"DatabaseConfigure", "database", 10, "Setting up a database, so Umbraco has a place to store your website",
|
||||
PerformsAppRestart = true)]
|
||||
[InstallSetupStep(InstallationType.NewInstall, "DatabaseConfigure", "database", 10, "Setting up a database, so Umbraco has a place to store your website", PerformsAppRestart = true)]
|
||||
public class DatabaseConfigureStep : InstallSetupStep<DatabaseModel>
|
||||
{
|
||||
private readonly DatabaseBuilder _databaseBuilder;
|
||||
@@ -45,44 +39,33 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps
|
||||
return Task.FromResult<InstallSetupResult?>(null);
|
||||
}
|
||||
|
||||
public override object ViewModel
|
||||
public override object ViewModel => new
|
||||
{
|
||||
get
|
||||
{
|
||||
var options = _databaseProviderMetadata
|
||||
.Where(x => x.IsAvailable)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToList();
|
||||
databases = _databaseProviderMetadata.GetAvailable().ToList()
|
||||
};
|
||||
|
||||
return new
|
||||
{
|
||||
databases = options
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override string View => ShouldDisplayView() ? base.View : "";
|
||||
public override string View => ShouldDisplayView() ? base.View : string.Empty;
|
||||
|
||||
public override bool RequiresExecution(DatabaseModel model) => ShouldDisplayView();
|
||||
|
||||
private bool ShouldDisplayView()
|
||||
{
|
||||
//If the connection string is already present in web.config we don't need to show the settings page and we jump to installing/upgrading.
|
||||
// If the connection string is already present in web.config we don't need to show the settings page and we jump to installing/upgrading.
|
||||
var databaseSettings = _connectionStrings.Get(Core.Constants.System.UmbracoConnectionName);
|
||||
|
||||
if (databaseSettings.IsConnectionStringConfigured())
|
||||
{
|
||||
try
|
||||
{
|
||||
//Since a connection string was present we verify the db can connect and query
|
||||
_ = _databaseBuilder.ValidateSchema();
|
||||
// Since a connection string was present we verify the db can connect and query
|
||||
_databaseBuilder.ValidateSchema();
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Something went wrong, could not connect so probably need to reconfigure
|
||||
_logger.LogError(ex, "An error occurred, reconfiguring...");
|
||||
//something went wrong, could not connect so probably need to reconfigure
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
@@ -118,10 +113,7 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps
|
||||
{
|
||||
get
|
||||
{
|
||||
var quickInstallSettings = _databaseProviderMetadata
|
||||
.Where(x => x.SupportsQuickInstall)
|
||||
.Where(x => x.IsAvailable)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
var quickInstallSettings = _databaseProviderMetadata.GetAvailable(true)
|
||||
.Select(x => new
|
||||
{
|
||||
displayName = x.DisplayName,
|
||||
|
||||
@@ -69,10 +69,10 @@ namespace Umbraco.Cms.Infrastructure.Install
|
||||
break;
|
||||
case RuntimeLevelReason.UpgradePackageMigrations:
|
||||
{
|
||||
if (!_runtimeState.StartupState.TryGetValue(RuntimeState.PendingPacakgeMigrationsStateKey, out var pm)
|
||||
if (!_runtimeState.StartupState.TryGetValue(RuntimeState.PendingPackageMigrationsStateKey, out var pm)
|
||||
|| pm is not IReadOnlyList<string> pendingMigrations)
|
||||
{
|
||||
throw new InvalidOperationException($"The required key {RuntimeState.PendingPacakgeMigrationsStateKey} does not exist in startup state");
|
||||
throw new InvalidOperationException($"The required key {RuntimeState.PendingPackageMigrationsStateKey} does not exist in startup state");
|
||||
}
|
||||
|
||||
if (pendingMigrations.Count == 0)
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
@@ -139,20 +136,15 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install
|
||||
// if the database model is null then we will attempt quick install.
|
||||
if (databaseSettings == null)
|
||||
{
|
||||
providerMeta = _databaseProviderMetadata
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.Where(x => x.SupportsQuickInstall)
|
||||
.FirstOrDefault(x => x.IsAvailable);
|
||||
|
||||
providerMeta = _databaseProviderMetadata.GetAvailable(true).FirstOrDefault();
|
||||
databaseSettings = new DatabaseModel
|
||||
{
|
||||
DatabaseName = providerMeta?.DefaultDatabaseName!,
|
||||
DatabaseName = providerMeta?.DefaultDatabaseName!
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
providerMeta = _databaseProviderMetadata
|
||||
.FirstOrDefault(x => x.Id == databaseSettings.DatabaseProviderMetadataId);
|
||||
providerMeta = _databaseProviderMetadata.FirstOrDefault(x => x.Id == databaseSettings.DatabaseProviderMetadataId);
|
||||
}
|
||||
|
||||
if (providerMeta == null)
|
||||
@@ -177,7 +169,6 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void Configure(string connectionString, string? providerName, bool installMissingDatabase)
|
||||
{
|
||||
// Update existing connection string
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
using Umbraco.Cms.Core.Install.Models;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IDatabaseProviderMetadata" />.
|
||||
/// </summary>
|
||||
public static class DatabaseProviderMetadataExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the available database provider metadata.
|
||||
/// </summary>
|
||||
/// <param name="databaseProviderMetadata">The database provider metadata.</param>
|
||||
/// <param name="onlyQuickInstall">If set to <c>true</c> only returns providers that support quick install.</param>
|
||||
/// <returns>
|
||||
/// The available database provider metadata.
|
||||
/// </returns>
|
||||
public static IEnumerable<IDatabaseProviderMetadata> GetAvailable(this IEnumerable<IDatabaseProviderMetadata> databaseProviderMetadata, bool onlyQuickInstall = false)
|
||||
=> databaseProviderMetadata.Where(x => (!onlyQuickInstall || x.SupportsQuickInstall) && x.IsAvailable).OrderBy(x => x.SortOrder);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a database can be created for the specified provider name while ignoring the value of <see cref="GlobalSettings.InstallMissingDatabase" />.
|
||||
/// </summary>
|
||||
/// <param name="databaseProviderMetadata">The database provider metadata.</param>
|
||||
/// <param name="providerName">The name of the provider.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if a database can be created for the specified provider name; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool CanForceCreateDatabase(this IEnumerable<IDatabaseProviderMetadata> databaseProviderMetadata, string? providerName)
|
||||
=> databaseProviderMetadata.FirstOrDefault(x => x.ProviderName == providerName)?.ForceCreateDatabase == true;
|
||||
|
||||
/// <summary>
|
||||
/// Generates the connection string.
|
||||
/// </summary>
|
||||
/// <param name="databaseProviderMetadata">The database provider metadata.</param>
|
||||
/// <param name="databaseName">The name of the database, uses the default database name when <c>null</c>.</param>
|
||||
/// <param name="server">The server.</param>
|
||||
/// <param name="login">The login.</param>
|
||||
/// <param name="password">The password.</param>
|
||||
/// <param name="integratedAuth">Indicates whether integrated authentication should be used (when supported by the provider).</param>
|
||||
/// <returns>
|
||||
/// The generated connection string.
|
||||
/// </returns>
|
||||
public static string? GenerateConnectionString(this IDatabaseProviderMetadata databaseProviderMetadata, string? databaseName = null, string? server = null, string? login = null, string? password = null, bool? integratedAuth = null)
|
||||
=> databaseProviderMetadata.GenerateConnectionString(new DatabaseModel()
|
||||
{
|
||||
DatabaseProviderMetadataId = databaseProviderMetadata.Id,
|
||||
ProviderName = databaseProviderMetadata.ProviderName,
|
||||
DatabaseName = databaseName ?? databaseProviderMetadata.DefaultDatabaseName,
|
||||
Server = server ?? string.Empty,
|
||||
Login = login ?? string.Empty,
|
||||
Password = password ?? string.Empty,
|
||||
IntegratedAuth = integratedAuth == true && databaseProviderMetadata.SupportsIntegratedAuthentication
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -14,7 +11,6 @@ using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Migrations.Upgrade;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
{
|
||||
@@ -24,7 +20,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
/// </summary>
|
||||
public class RuntimeState : IRuntimeState
|
||||
{
|
||||
internal const string PendingPacakgeMigrationsStateKey = "PendingPackageMigrations";
|
||||
internal const string PendingPackageMigrationsStateKey = "PendingPackageMigrations";
|
||||
|
||||
private readonly IOptions<GlobalSettings> _globalSettings = null!;
|
||||
private readonly IOptions<UnattendedSettings> _unattendedSettings = null!;
|
||||
private readonly IUmbracoVersion _umbracoVersion = null!;
|
||||
@@ -33,6 +30,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
private readonly PendingPackageMigrations _packageMigrationState = null!;
|
||||
private readonly Dictionary<string, object> _startupState = new Dictionary<string, object>();
|
||||
private readonly IConflictingRouteService _conflictingRouteService = null!;
|
||||
private readonly IEnumerable<IDatabaseProviderMetadata> _databaseProviderMetadata = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The initial <see cref="RuntimeState"/>
|
||||
@@ -41,17 +39,17 @@ namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
public static RuntimeState Booting() => new RuntimeState() { Level = RuntimeLevel.Boot };
|
||||
|
||||
private RuntimeState()
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
public RuntimeState(
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IOptions<UnattendedSettings> unattendedSettings,
|
||||
IUmbracoVersion umbracoVersion,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
ILogger<RuntimeState> logger,
|
||||
PendingPackageMigrations packageMigrationState,
|
||||
IConflictingRouteService conflictingRouteService)
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IOptions<UnattendedSettings> unattendedSettings,
|
||||
IUmbracoVersion umbracoVersion,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
ILogger<RuntimeState> logger,
|
||||
PendingPackageMigrations packageMigrationState,
|
||||
IConflictingRouteService conflictingRouteService,
|
||||
IEnumerable<IDatabaseProviderMetadata> databaseProviderMetadata)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_unattendedSettings = unattendedSettings;
|
||||
@@ -60,8 +58,29 @@ namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
_logger = logger;
|
||||
_packageMigrationState = packageMigrationState;
|
||||
_conflictingRouteService = conflictingRouteService;
|
||||
_databaseProviderMetadata = databaseProviderMetadata;
|
||||
}
|
||||
|
||||
[Obsolete("Use ctor with all params. This will be removed in Umbraco 12")]
|
||||
public RuntimeState(
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IOptions<UnattendedSettings> unattendedSettings,
|
||||
IUmbracoVersion umbracoVersion,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
ILogger<RuntimeState> logger,
|
||||
PendingPackageMigrations packageMigrationState,
|
||||
IConflictingRouteService conflictingRouteService)
|
||||
: this(
|
||||
globalSettings,
|
||||
unattendedSettings,
|
||||
umbracoVersion,
|
||||
databaseFactory,
|
||||
logger,
|
||||
packageMigrationState,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IConflictingRouteService>(),
|
||||
StaticServiceProvider.Instance.GetServices<IDatabaseProviderMetadata>())
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RuntimeState"/> class.
|
||||
/// </summary>
|
||||
@@ -81,8 +100,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
logger,
|
||||
packageMigrationState,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IConflictingRouteService>())
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Version Version => _umbracoVersion.Version;
|
||||
@@ -143,7 +161,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
// cannot connect to configured database, this is bad, fail
|
||||
_logger.LogDebug("Could not connect to database.");
|
||||
|
||||
if (_globalSettings.Value.InstallMissingDatabase || CanAutoInstallMissingDatabase(_databaseFactory))
|
||||
if (_globalSettings.Value.InstallMissingDatabase || _databaseProviderMetadata.CanForceCreateDatabase(_databaseFactory.ProviderName))
|
||||
{
|
||||
// ok to install on a configured but missing database
|
||||
Level = RuntimeLevel.Install;
|
||||
@@ -257,7 +275,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
IReadOnlyList<string> packagesRequiringMigration = _packageMigrationState.GetPendingPackageMigrations(keyValues);
|
||||
if (packagesRequiringMigration.Count > 0)
|
||||
{
|
||||
_startupState[PendingPacakgeMigrationsStateKey] = packagesRequiringMigration;
|
||||
_startupState[PendingPackageMigrationsStateKey] = packagesRequiringMigration;
|
||||
|
||||
return UmbracoDatabaseState.NeedsPackageMigration;
|
||||
}
|
||||
@@ -311,8 +329,5 @@ namespace Umbraco.Cms.Infrastructure.Runtime
|
||||
|
||||
return canConnect;
|
||||
}
|
||||
|
||||
private bool CanAutoInstallMissingDatabase(IUmbracoDatabaseFactory databaseFactory)
|
||||
=> databaseFactory.ConnectionString?.InvariantContains("(localdb)") == true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Tests.UnitTests.AutoFixture;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Configuration.Models
|
||||
{
|
||||
[TestFixture]
|
||||
public class ConnectionStringsTests
|
||||
{
|
||||
[Test]
|
||||
public void ProviderName_WhenNotExplicitlySet_HasDefaultSet()
|
||||
{
|
||||
var sut = new ConnectionStrings();
|
||||
Assert.That(sut.ProviderName, Is.EqualTo(ConnectionStrings.DefaultProviderName));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public void ConnectionString_WhenSetterCalled_ReplacesDataDirectoryPlaceholder(string aDataDirectory)
|
||||
{
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", aDataDirectory);
|
||||
|
||||
var sut = new ConnectionStrings
|
||||
{
|
||||
ConnectionString = $"{ConnectionStrings.DataDirectoryPlaceholder}/foo"
|
||||
};
|
||||
Assert.That(sut.ConnectionString, Contains.Substring($"{aDataDirectory}/foo"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Tests.UnitTests.AutoFixture;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Configuration;
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Configuration;
|
||||
|
||||
[TestFixture]
|
||||
public class ConfigureConnectionStringsTests
|
||||
@@ -27,7 +27,7 @@ public class ConfigureConnectionStringsTests
|
||||
var configuration = configurationBuilder.Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddOptions<ConnectionStrings>().Bind(configuration.GetSection("ConnectionStrings"));
|
||||
services.AddOptions();
|
||||
services.AddSingleton<IConfigureOptions<ConnectionStrings>, ConfigureConnectionStrings>();
|
||||
services.AddSingleton<IConfiguration>(configuration);
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Extensions
|
||||
{
|
||||
[TestFixture]
|
||||
public class ConfigurationExtensionsTests
|
||||
{
|
||||
private const string DataDirectory = @"C:\Data";
|
||||
|
||||
[Test]
|
||||
public void CanParseSqlServerConnectionString()
|
||||
{
|
||||
const string ConfiguredConnectionString = @"Server=.\SQLEXPRESS;Database=UmbracoCms;Integrated Security=true";
|
||||
|
||||
Mock<IConfiguration> mockedConfig = CreateConfig(ConfiguredConnectionString);
|
||||
|
||||
string connectionString = mockedConfig.Object.GetUmbracoConnectionString(out string providerName);
|
||||
|
||||
AssertResults(
|
||||
ConfiguredConnectionString,
|
||||
"Microsoft.Data.SqlClient",
|
||||
connectionString,
|
||||
providerName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseLocalDbConnectionString()
|
||||
{
|
||||
const string ConfiguredConnectionString = @"Server=(LocalDb)\MyInstance;Integrated Security=true;";
|
||||
|
||||
Mock<IConfiguration> mockedConfig = CreateConfig(ConfiguredConnectionString);
|
||||
|
||||
string connectionString = mockedConfig.Object.GetUmbracoConnectionString(out string providerName);
|
||||
|
||||
AssertResults(
|
||||
ConfiguredConnectionString,
|
||||
"Microsoft.Data.SqlClient",
|
||||
connectionString,
|
||||
providerName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseLocalDbConnectionStringWithDataDirectory()
|
||||
{
|
||||
const string ConfiguredConnectionString = @"Data Source=(LocalDb)\MyInstance;Initial Catalog=UmbracoDb;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\Umbraco.mdf";
|
||||
|
||||
Mock<IConfiguration> mockedConfig = CreateConfig(ConfiguredConnectionString);
|
||||
SetDataDirectory();
|
||||
|
||||
string connectionString = mockedConfig.Object.GetUmbracoConnectionString(out string providerName);
|
||||
|
||||
AssertResults(
|
||||
@"Data Source=(LocalDb)\MyInstance;Initial Catalog=UmbracoDb;Integrated Security=SSPI;AttachDBFilename=C:\Data\Umbraco.mdf",
|
||||
"Microsoft.Data.SqlClient",
|
||||
connectionString,
|
||||
providerName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseSQLiteConnectionStringWithDataDirectory()
|
||||
{
|
||||
const string ConfiguredConnectionString = "Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True";
|
||||
const string ConfiguredProviderName = "Microsoft.Data.SQLite";
|
||||
|
||||
Mock<IConfiguration> mockedConfig = CreateConfig(ConfiguredConnectionString, ConfiguredProviderName);
|
||||
SetDataDirectory();
|
||||
|
||||
string connectionString = mockedConfig.Object.GetUmbracoConnectionString(out string providerName);
|
||||
|
||||
AssertResults(
|
||||
@"Data Source=C:\Data/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True",
|
||||
"Microsoft.Data.SQLite",
|
||||
connectionString,
|
||||
providerName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseConnectionStringWithNamedProvider()
|
||||
{
|
||||
const string ConfiguredConnectionString = @"Server=.\SQLEXPRESS;Database=UmbracoCms;Integrated Security=true";
|
||||
const string ConfiguredProviderName = "MyProvider";
|
||||
|
||||
Mock<IConfiguration> mockedConfig = CreateConfig(ConfiguredConnectionString, ConfiguredProviderName);
|
||||
|
||||
string connectionString = mockedConfig.Object.GetUmbracoConnectionString(out string providerName);
|
||||
|
||||
AssertResults(
|
||||
ConfiguredConnectionString,
|
||||
ConfiguredProviderName,
|
||||
connectionString,
|
||||
providerName);
|
||||
}
|
||||
|
||||
private static Mock<IConfiguration> CreateConfig(string configuredConnectionString, string configuredProviderName = ConnectionStrings.DefaultProviderName)
|
||||
{
|
||||
var mockConfigSection = new Mock<IConfigurationSection>();
|
||||
mockConfigSection
|
||||
.SetupGet(m => m[It.Is<string>(s => s == Constants.System.UmbracoConnectionName)])
|
||||
.Returns(configuredConnectionString);
|
||||
mockConfigSection
|
||||
.SetupGet(m => m[It.Is<string>(s => s == $"{Constants.System.UmbracoConnectionName}{ConnectionStrings.ProviderNamePostfix}")])
|
||||
.Returns(configuredProviderName);
|
||||
|
||||
var mockedConfig = new Mock<IConfiguration>();
|
||||
mockedConfig
|
||||
.Setup(a => a.GetSection(It.Is<string>(s => s == "ConnectionStrings")))
|
||||
.Returns(mockConfigSection.Object);
|
||||
|
||||
return mockedConfig;
|
||||
}
|
||||
|
||||
private static void SetDataDirectory() =>
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", DataDirectory);
|
||||
|
||||
private static void AssertResults(string expectedConnectionString, string expectedProviderName, string connectionString, string providerName)
|
||||
{
|
||||
Assert.AreEqual(expectedConnectionString, connectionString);
|
||||
Assert.AreEqual(expectedProviderName, providerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user