diff --git a/DNN Platform/DotNetNuke.Abstractions/ISerializationManager.cs b/DNN Platform/DotNetNuke.Abstractions/ISerializationManager.cs new file mode 100644 index 00000000000..d3818b20387 --- /dev/null +++ b/DNN Platform/DotNetNuke.Abstractions/ISerializationManager.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Abstractions +{ + using System; + using System.Reflection; + + /// + /// The Serialization Manager provides APIs for serializing + /// and deserializing objects to and from strings. + /// + public interface ISerializationManager + { + /// Serialize the value. + /// The type of value to serialize. + /// The value to serialize. + /// The serialized to a . + string SerializeValue(T value); + + /// Serialize the value. + /// The type of value to serialize. + /// The value to serialize. + /// The name of a type implementing DotNetNuke.Entities.Modules.Settings.ISettingsSerializer{T} to use in serializing the value. + /// The serialized to a . + string SerializeValue(T value, string serializer); + + /// + /// Serialize the property. + /// + /// The type to serialize. + /// The object to serialize. + /// The property info. + /// A serialized string. + string SerializeProperty(T myObject, PropertyInfo property); + + /// + /// Serialize the property. + /// + /// The type to serialize. + /// The object to serialize.. + /// The property info. + /// The name of a type implementing DotNetNuke.Entities.Modules.Settings.ISettingsSerializer{T} to use in serializing the property. + /// A serialized string. + string SerializeProperty(T myObject, PropertyInfo property, string serializer); + + /// Deserializes the string value. + /// The type the string should be deserialized into. + /// The serialized string. + /// The value deserialized into the given type. + /// The could not be deserialized into the given type. + T DeserializeValue(string value); + + /// Deserializes the string value. + /// The type the string should be deserialized into. + /// The serialized string. + /// The name of a type implementing DotNetNuke.Entities.Modules.Settings.ISettingsSerializer{T} to use in deserializing the property. + /// The value deserialized into the given type. + /// The could not be deserialized into the given type. + T DeserializeValue(string value, string serializer); + + /// + /// Deserializes the string property. + /// + /// The object the string should be deserialized into. + /// The object. + /// The property info.. + /// The serialized string. + /// The could not be deserialized into the given type. + void DeserializeProperty(T myObject, PropertyInfo property, string propertyValue) + where T : class, new(); + + /// + /// Deserializes the string property. + /// + /// The object the string should be deserialized into. + /// The object.. + /// The property info.. + /// The serialized string. + /// The name of a type implementing DotNetNuke.Entities.Modules.Settings.ISettingsSerializer{T} to use in deserializing the property. + /// The could not be deserialized into the given type. + void DeserializeProperty(T myObject, PropertyInfo property, string propertyValue, string serializer) + where T : class, new(); + } +} diff --git a/DNN Platform/Library/DotNetNuke.Library.csproj b/DNN Platform/Library/DotNetNuke.Library.csproj index 21cf53e7309..7855cce63c9 100644 --- a/DNN Platform/Library/DotNetNuke.Library.csproj +++ b/DNN Platform/Library/DotNetNuke.Library.csproj @@ -220,7 +220,7 @@ - + @@ -255,6 +255,7 @@ + diff --git a/DNN Platform/Library/Entities/Modules/Settings/SerializationController.cs b/DNN Platform/Library/Entities/Modules/Settings/SerializationController.cs deleted file mode 100644 index c267566b018..00000000000 --- a/DNN Platform/Library/Entities/Modules/Settings/SerializationController.cs +++ /dev/null @@ -1,193 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information -using DotNetNuke.Services.Exceptions; -using System; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; - -namespace DotNetNuke.Entities.Modules.Settings -{ - public class SerializationController - { - public static string SerializeProperty(T myObject, PropertyInfo property) - { - return SerializeProperty(myObject, property, null); - } - public static string SerializeProperty(T myObject, PropertyInfo property, string serializer) - { - var settingValue = property.GetValue(myObject, null) ?? string.Empty; - string settingValueAsString = null; - if (!string.IsNullOrEmpty(serializer)) - { - settingValueAsString = (string)CallSerializerMethod(serializer, property.PropertyType, settingValue, nameof(ISettingsSerializer.Serialize)); - } - if (settingValueAsString == null) - { - settingValueAsString = GetSettingValueAsString(settingValue); - } - return settingValueAsString; - } - - public static void DeserializeProperty(T myObject, PropertyInfo property, string propertyValue) where T : class, new() - { - DeserializeProperty(myObject, property, propertyValue, null); - } - public static void DeserializeProperty(T myObject, PropertyInfo property, string propertyValue, string serializer) where T : class, new() - { - try - { - var valueType = propertyValue.GetType(); - var propertyType = property.PropertyType; - if (propertyType.GetGenericArguments().Any() && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - // Nullable type - propertyType = propertyType.GetGenericArguments()[0]; - if (string.IsNullOrEmpty(propertyValue)) - { - property.SetValue(myObject, null, null); - return; - } - } - - if (propertyType == valueType) - { - // The property and settingsValue have the same type - no conversion needed - just update! - property.SetValue(myObject, propertyValue, null); - return; - } - - if (!string.IsNullOrEmpty(serializer)) - { - var deserializedValue = CallSerializerMethod(serializer, property.PropertyType, propertyValue, nameof(ISettingsSerializer.Deserialize)); - property.SetValue(myObject, deserializedValue, null); - return; - } - - if (propertyType.BaseType == typeof(Enum)) - { - // The property is an enum. Determine if the enum value is persisted as string or numeric. - if (Regex.IsMatch(propertyValue, "^\\d+$")) - { - // The enum value is a number - property.SetValue(myObject, Enum.ToObject(propertyType, Convert.ToInt32(propertyValue, CultureInfo.InvariantCulture)), null); - } - else - { - try - { - property.SetValue(myObject, Enum.Parse(propertyType, propertyValue, true), null); - } - catch (ArgumentException exception) - { - // Just log the exception. Use the default. - Exceptions.LogException(exception); - } - } - - return; - } - - TimeSpan timeSpanValue; - if (propertyType.IsAssignableFrom(typeof(TimeSpan)) && TimeSpan.TryParse(propertyValue, CultureInfo.InvariantCulture, out timeSpanValue)) - { - property.SetValue(myObject, timeSpanValue); - return; - } - - DateTime dateTimeValue; - if (propertyType.IsAssignableFrom(typeof(DateTime)) && DateTime.TryParse(propertyValue, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTimeValue)) - { - property.SetValue(myObject, dateTimeValue); - return; - } - - if (propertyType.GetInterface(typeof(IConvertible).FullName) != null) - { - propertyValue = ChangeFormatForBooleansIfNeeded(propertyType, propertyValue); - property.SetValue(myObject, Convert.ChangeType(propertyValue, propertyType, CultureInfo.InvariantCulture), null); - return; - } - - var converter = TypeDescriptor.GetConverter(propertyType); - if (converter.IsValid(propertyValue)) - { - converter.ConvertFromInvariantString(propertyValue); - } - } - catch (Exception exception) - { - // TODO: Localize exception - throw new InvalidCastException(string.Format(CultureInfo.CurrentUICulture, "Could not cast {0} to property {1} of type {2}", - propertyValue, - property.Name, - property.PropertyType), exception); - } - } - - private static string GetSettingValueAsString(object settingValue) - { - var dateTimeValue = settingValue as DateTime?; - if (dateTimeValue != null) - { - return dateTimeValue.Value.ToString("o", CultureInfo.InvariantCulture); - } - - var timeSpanValue = settingValue as TimeSpan?; - if (timeSpanValue != null) - { - return timeSpanValue.Value.ToString("c", CultureInfo.InvariantCulture); - } - - return Convert.ToString(settingValue, CultureInfo.InvariantCulture); - } - - private static string ChangeFormatForBooleansIfNeeded(Type propertyType, string propertyValue) - { - if (!propertyType.Name.Equals("Boolean")) - { - return propertyValue; - } - - bool boolValue; - if (bool.TryParse(propertyValue, out boolValue)) - { - return propertyValue; - } - - if (propertyValue.Equals("1")) - { - return bool.TrueString; - } - if (propertyValue.Equals("0")) - { - return bool.FalseString; - } - - return propertyValue; - } - - private static object CallSerializerMethod(string serializerTypeName, Type typeArgument, object value, string methodName) - { - var serializerType = Framework.Reflection.CreateType(serializerTypeName, true); - if (serializerType == null) - { - return null; - } - - var serializer = Framework.Reflection.CreateInstance(serializerType); - if (serializer == null) - { - return null; - } - - var serializerInterfaceType = typeof(ISettingsSerializer<>).MakeGenericType(typeArgument); - var method = serializerInterfaceType.GetMethod(methodName); - return method.Invoke(serializer, new[] { value, }); - } - - } -} diff --git a/DNN Platform/Library/Entities/Modules/Settings/SerializationManager.cs b/DNN Platform/Library/Entities/Modules/Settings/SerializationManager.cs new file mode 100644 index 00000000000..9cd7cc532fd --- /dev/null +++ b/DNN Platform/Library/Entities/Modules/Settings/SerializationManager.cs @@ -0,0 +1,236 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Entities.Modules.Settings +{ + using System; + using System.ComponentModel; + using System.Globalization; + using System.Linq; + using System.Reflection; + using System.Text.RegularExpressions; + + using DotNetNuke.Abstractions; + using DotNetNuke.Services.Exceptions; + + /// + public class SerializationManager : ISerializationManager + { + /// + string ISerializationManager.SerializeValue(T value) => + this.SerializeValue(value, null, typeof(T)); + + /// + string ISerializationManager.SerializeValue(T value, string serializer) => + this.SerializeValue(value, serializer, typeof(T)); + + /// + string ISerializationManager.SerializeProperty(T myObject, PropertyInfo property) => + ((ISerializationManager)this).SerializeProperty(myObject, property, null); + + /// + string ISerializationManager.SerializeProperty(T myObject, PropertyInfo property, string serializer) + { + var settingValue = property.GetValue(myObject, null) ?? string.Empty; + return this.SerializeValue(settingValue, serializer, property.PropertyType); + } + + /// + public T DeserializeValue(string value) => ((ISerializationManager)this).DeserializeValue(value, null); + + /// + public T DeserializeValue(string value, string serializer) + { + return (T)this.DeserializeValue(value, serializer, typeof(T)); + } + + /// + void ISerializationManager.DeserializeProperty(T myObject, PropertyInfo property, string propertyValue) => + ((ISerializationManager)this).DeserializeProperty(myObject, property, propertyValue, null); + + /// + void ISerializationManager.DeserializeProperty(T myObject, PropertyInfo property, string propertyValue, string serializer) + { + try + { + var propertyType = property.PropertyType; + var deserializedValue = this.DeserializeValue(propertyValue, serializer, propertyType); + property.SetValue(myObject, deserializedValue, null); + } + catch (Exception exception) + { + // TODO: Localize exception + var message = string.Format( + CultureInfo.CurrentUICulture, + "Could not cast {0} to property {1} of type {2}", + propertyValue, + property.Name, + property.PropertyType); + throw new InvalidCastException(message, exception); + } + } + + private string SerializeValue(T value, string serializer, Type valueType) + { + string settingValueAsString = null; + if (!string.IsNullOrEmpty(serializer)) + { + settingValueAsString = (string)this.CallSerializerMethod(serializer, valueType, value, nameof(ISettingsSerializer.Serialize)); + } + + if (settingValueAsString == null) + { + settingValueAsString = this.GetSettingValueAsString(value); + } + + return settingValueAsString; + } + + private object DeserializeValue( + string propertyValue, + string serializer, + Type destinationType) + { + if (destinationType.GetGenericArguments().Any() + && destinationType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + // Nullable type + destinationType = destinationType.GetGenericArguments()[0]; + if (string.IsNullOrEmpty(propertyValue)) + { + return null; + } + } + + if (destinationType == propertyValue.GetType()) + { + // The property and settingsValue have the same type - no conversion needed - just update! + return propertyValue; + } + + if (!string.IsNullOrEmpty(serializer)) + { + return this.CallSerializerMethod( + serializer, + destinationType, + propertyValue, + nameof(ISettingsSerializer.Deserialize)); + } + + if (destinationType.BaseType == typeof(Enum)) + { + // The property is an enum. Determine if the enum value is persisted as string or numeric. + if (Regex.IsMatch(propertyValue, "^\\d+$")) + { + // The enum value is a number + return Enum.ToObject(destinationType, Convert.ToInt32(propertyValue, CultureInfo.InvariantCulture)); + } + + try + { + return Enum.Parse(destinationType, propertyValue, true); + } + catch (ArgumentException exception) + { + // Just log the exception. Use the default. + Exceptions.LogException(exception); + } + + return 0; + } + + if (destinationType.IsAssignableFrom(typeof(TimeSpan)) + && TimeSpan.TryParse(propertyValue, CultureInfo.InvariantCulture, out var timeSpanValue)) + { + return timeSpanValue; + } + + if (destinationType.IsAssignableFrom(typeof(DateTime)) + && DateTime.TryParse( + propertyValue, + CultureInfo.InvariantCulture, + DateTimeStyles.RoundtripKind, + out var dateTimeValue)) + { + return dateTimeValue; + } + + if (destinationType.GetInterface(typeof(IConvertible).FullName) != null) + { + propertyValue = this.ChangeFormatForBooleansIfNeeded(destinationType, propertyValue); + return Convert.ChangeType(propertyValue, destinationType, CultureInfo.InvariantCulture); + } + + var converter = TypeDescriptor.GetConverter(destinationType); + if (converter.IsValid(propertyValue)) + { + return converter.ConvertFromInvariantString(propertyValue); + } + + // TODO: Localize exception + throw new InvalidCastException($"Could not cast {propertyValue} to {destinationType}"); + } + + private string GetSettingValueAsString(T settingValue) + { + var dateTimeValue = settingValue as DateTime?; + if (dateTimeValue != null) + { + return dateTimeValue.Value.ToString("o", CultureInfo.InvariantCulture); + } + + var timeSpanValue = settingValue as TimeSpan?; + if (timeSpanValue != null) + { + return timeSpanValue.Value.ToString("c", CultureInfo.InvariantCulture); + } + + return Convert.ToString(settingValue, CultureInfo.InvariantCulture); + } + + private string ChangeFormatForBooleansIfNeeded(Type propertyType, string propertyValue) + { + if (!propertyType.Name.Equals("Boolean")) + { + return propertyValue; + } + + if (bool.TryParse(propertyValue, out _)) + { + return propertyValue; + } + + if (propertyValue.Equals("1")) + { + return bool.TrueString; + } + + if (propertyValue.Equals("0")) + { + return bool.FalseString; + } + + return propertyValue; + } + + private object CallSerializerMethod(string serializerTypeName, Type typeArgument, object value, string methodName) + { + var serializerType = Framework.Reflection.CreateType(serializerTypeName, true); + if (serializerType == null) + { + return null; + } + + var serializer = Framework.Reflection.CreateInstance(serializerType); + if (serializer == null) + { + return null; + } + + var serializerInterfaceType = typeof(ISettingsSerializer<>).MakeGenericType(typeArgument); + var method = serializerInterfaceType.GetMethod(methodName); + return method?.Invoke(serializer, new[] { value, }); + } + } +} diff --git a/DNN Platform/Library/Entities/Modules/Settings/SettingsRepository.cs b/DNN Platform/Library/Entities/Modules/Settings/SettingsRepository.cs index 367e23e4b3f..579b0959bb0 100644 --- a/DNN Platform/Library/Entities/Modules/Settings/SettingsRepository.cs +++ b/DNN Platform/Library/Entities/Modules/Settings/SettingsRepository.cs @@ -9,19 +9,23 @@ namespace DotNetNuke.Entities.Modules.Settings using System.Reflection; using System.Web.Caching; + using DotNetNuke.Abstractions; using DotNetNuke.Collections; using DotNetNuke.Common; using DotNetNuke.Common.Utilities; using DotNetNuke.Entities.Controllers; using DotNetNuke.Entities.Portals; using DotNetNuke.Services.Cache; + using Microsoft.Extensions.DependencyInjection; /// - public abstract class SettingsRepository : ISettingsRepository - where T : class, new() + public abstract class SettingsRepository : ISettingsRepository where T : class, new() { private readonly IModuleController moduleController; + private static ISerializationManager SerializationManager => + Globals.DependencyProvider.GetRequiredService(); + /// /// Initializes a new instance of the class. /// @@ -196,7 +200,7 @@ private T Load(CacheItemArgs args) /// Thrown if string value cannot be deserialized to desired type. private void DeserializeProperty(T settings, PropertyInfo property, ParameterAttributeBase attribute, string propertyValue) { - SerializationController.DeserializeProperty(settings, property, propertyValue, attribute.Serializer); + SerializationManager.DeserializeProperty(settings, property, propertyValue, attribute.Serializer); } } } diff --git a/DNN Platform/Library/Obsolete/SerializationController.cs b/DNN Platform/Library/Obsolete/SerializationController.cs new file mode 100644 index 00000000000..e8977173c75 --- /dev/null +++ b/DNN Platform/Library/Obsolete/SerializationController.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.Entities.Modules.Settings +{ + using System; + using System.Reflection; + + using DotNetNuke.Abstractions; + using DotNetNuke.Common; + using Microsoft.Extensions.DependencyInjection; + + [Obsolete("Deprecated in 9.8.0. Use Dependency Injection to resolve 'DotNetNuke.Abstractions.ISerializationManager' instead. Scheduled for removal in v11.0.0.")] + public partial class SerializationController + { + static ISerializationManager SerializationManager => + Globals.DependencyProvider.GetRequiredService(); + + [Obsolete("Deprecated in 9.8.0. Use Dependency Injection to resolve 'DotNetNuke.Abstractions.ISerializationManager' instead. Scheduled for removal in v11.0.0.")] + public static string SerializeProperty(T myObject, PropertyInfo property) => + SerializationManager.SerializeProperty(myObject, property); + + [Obsolete("Deprecated in 9.8.0. Use Dependency Injection to resolve 'DotNetNuke.Abstractions.ISerializationManager' instead. Scheduled for removal in v11.0.0.")] + public static string SerializeProperty(T myObject, PropertyInfo property, string serializer) => + SerializationManager.SerializeProperty(myObject, property, serializer); + + [Obsolete("Deprecated in 9.8.0. Use Dependency Injection to resolve 'DotNetNuke.Abstractions.ISerializationManager' instead. Scheduled for removal in v11.0.0.")] + public static void DeserializeProperty(T myObject, PropertyInfo property, string propertyValue) + where T : class, new() => SerializationManager.DeserializeProperty(myObject, property, propertyValue); + + [Obsolete("Deprecated in 9.8.0. Use Dependency Injection to resolve 'DotNetNuke.Abstractions.ISerializationManager' instead. Scheduled for removal in v11.0.0.")] + public static void DeserializeProperty(T myObject, PropertyInfo property, string propertyValue, string serializer) + where T : class, new() => SerializationManager.DeserializeProperty(myObject, property, propertyValue, serializer); + } +} diff --git a/DNN Platform/Library/Prompt/ConsoleCommand.cs b/DNN Platform/Library/Prompt/ConsoleCommand.cs index 53e5cf8c613..b3731142e52 100644 --- a/DNN Platform/Library/Prompt/ConsoleCommand.cs +++ b/DNN Platform/Library/Prompt/ConsoleCommand.cs @@ -1,18 +1,24 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information -using DotNetNuke.Abstractions.Portals; -using DotNetNuke.Abstractions.Prompt; -using DotNetNuke.Abstractions.Users; -using DotNetNuke.Collections; -using DotNetNuke.Services.Localization; -using System.Collections.Generic; -using System.Reflection; - namespace DotNetNuke.Prompt { + using System.Collections.Generic; + using System.Reflection; + + using DotNetNuke.Abstractions; + using DotNetNuke.Abstractions.Portals; + using DotNetNuke.Abstractions.Prompt; + using DotNetNuke.Abstractions.Users; + using DotNetNuke.Collections; + using DotNetNuke.Services.Localization; + using Microsoft.Extensions.DependencyInjection; + public abstract class ConsoleCommand : IConsoleCommand { + private static ISerializationManager SerializationManager => + Common.Globals.DependencyProvider.GetRequiredService(); + public abstract string LocalResourceFile { get; } protected IPortalSettings PortalSettings { get; private set; } protected IUserInfo User { get; private set; } @@ -43,7 +49,7 @@ protected void AddMessage(string message) if (settingValue != null && property.CanWrite) { var tp = property.PropertyType; - Entities.Modules.Settings.SerializationController.DeserializeProperty(myCommand, property, settingValue); + SerializationManager.DeserializeProperty(myCommand, property, settingValue); } }); } diff --git a/DNN Platform/Library/Startup.cs b/DNN Platform/Library/Startup.cs index 3c9bb21b224..fe0dc8c353f 100644 --- a/DNN Platform/Library/Startup.cs +++ b/DNN Platform/Library/Startup.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information - namespace DotNetNuke { using DotNetNuke.Abstractions; @@ -11,6 +10,7 @@ namespace DotNetNuke using DotNetNuke.Common; using DotNetNuke.DependencyInjection; using DotNetNuke.Entities.Controllers; + using DotNetNuke.Entities.Modules.Settings; using DotNetNuke.Entities.Portals; using DotNetNuke.UI.Modules; using DotNetNuke.UI.Modules.Html5; @@ -31,6 +31,7 @@ public void ConfigureServices(IServiceCollection services) services.AddTransient(x => PortalController.Instance); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/ModuleSettingsTests.cs b/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/ModuleSettingsTests.cs index ba0008297b1..3371189a19f 100644 --- a/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/ModuleSettingsTests.cs +++ b/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/ModuleSettingsTests.cs @@ -30,6 +30,7 @@ public void Setup() serviceCollection.AddTransient(container => Mock.Of()); serviceCollection.AddTransient(container => Mock.Of()); serviceCollection.AddTransient(); + serviceCollection.AddTransient(); Globals.DependencyProvider = serviceCollection.BuildServiceProvider(); } diff --git a/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/NullableSettingsTests.cs b/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/NullableSettingsTests.cs index dfd8348635d..0fef70add9f 100644 --- a/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/NullableSettingsTests.cs +++ b/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/NullableSettingsTests.cs @@ -39,6 +39,7 @@ public void Setup() serviceCollection.AddTransient(container => Mock.Of()); serviceCollection.AddTransient(container => Mock.Of()); serviceCollection.AddTransient(); + serviceCollection.AddTransient(); Globals.DependencyProvider = serviceCollection.BuildServiceProvider(); } diff --git a/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/PortalSettingsTests.cs b/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/PortalSettingsTests.cs index d61e3644e80..f2626c789f3 100644 --- a/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/PortalSettingsTests.cs +++ b/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/PortalSettingsTests.cs @@ -31,6 +31,7 @@ public void Setup() serviceCollection.AddTransient(container => Mock.Of()); serviceCollection.AddTransient(container => Mock.Of()); serviceCollection.AddTransient(); + serviceCollection.AddTransient(); Globals.DependencyProvider = serviceCollection.BuildServiceProvider(); } diff --git a/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/TabModuleSettingsTests.cs b/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/TabModuleSettingsTests.cs index cc799b4d0bb..9f52a219577 100644 --- a/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/TabModuleSettingsTests.cs +++ b/DNN Platform/Tests/DotNetNuke.Tests.Core/Entities/Modules/Settings/TabModuleSettingsTests.cs @@ -30,6 +30,7 @@ public void Setup() serviceCollection.AddTransient(container => Mock.Of()); serviceCollection.AddTransient(container => Mock.Of()); serviceCollection.AddTransient(); + serviceCollection.AddTransient(); Globals.DependencyProvider = serviceCollection.BuildServiceProvider(); }