diff --git a/Example/Data/Context.cs b/Example/Data/Context.cs index a0e381b..01b7e85 100644 --- a/Example/Data/Context.cs +++ b/Example/Data/Context.cs @@ -1,8 +1,6 @@ using Example.Data.Entities; using FileContextCore; -using FileContextCore.StoreManager; using Microsoft.EntityFrameworkCore; -using OfficeOpenXml; namespace Example.Data { diff --git a/FileContextCore/Extensions/FileContextDbContextOptionsExtensions.cs b/FileContextCore/Extensions/FileContextDbContextOptionsExtensions.cs index 159e88b..42f426a 100644 --- a/FileContextCore/Extensions/FileContextDbContextOptionsExtensions.cs +++ b/FileContextCore/Extensions/FileContextDbContextOptionsExtensions.cs @@ -91,7 +91,7 @@ public static DbContextOptionsBuilder UseFileContextDatabase( ?? new FileContextOptionsExtension(); extension = extension.WithCustomOptions(databaseName, location, password, - typeof(DefaultStoreManager)); + typeof(DefaultStoreManager), typeof(JSONSerializer), typeof(DefaultFileManager)); if (databaseRoot != null) { @@ -183,7 +183,7 @@ public static DbContextOptionsBuilder UseFileContextDatabase)); + typeof(DefaultStoreManager), typeof(TSerializer), typeof(TFileManager)); if (databaseRoot != null) { @@ -270,7 +270,7 @@ public static DbContextOptionsBuilder UseFileContextDatabase( var extension = optionsBuilder.Options.FindExtension() ?? new FileContextOptionsExtension(); - extension = extension.WithCustomOptions(databaseName, location, password, typeof(TStoreManager)); + extension = extension.WithCustomOptions(databaseName, location, password, typeof(TStoreManager), null, null); if (databaseRoot != null) { diff --git a/FileContextCore/Extensions/FileContextServiceCollectionExtensions.cs b/FileContextCore/Extensions/FileContextServiceCollectionExtensions.cs index f4c6a04..23c1df8 100644 --- a/FileContextCore/Extensions/FileContextServiceCollectionExtensions.cs +++ b/FileContextCore/Extensions/FileContextServiceCollectionExtensions.cs @@ -4,10 +4,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using FileContextCore.Diagnostics.Internal; +using FileContextCore.FileManager; using FileContextCore.Infrastructure.Internal; using FileContextCore.Metadata.Conventions; using FileContextCore.Query.Internal; +using FileContextCore.Serializer; using FileContextCore.Storage.Internal; +using FileContextCore.StoreManager; using FileContextCore.ValueGeneration.Internal; using FileContextCore.Utilities; using JetBrains.Annotations; @@ -70,7 +73,16 @@ public static IServiceCollection AddEntityFrameworkFileContextDatabase([NotNull] b => b .TryAddSingleton() .TryAddSingleton() - .TryAddScoped()); + .TryAddScoped() + .TryAddTransient() + .TryAddTransient() + .TryAddTransient() + .TryAddTransient() + .TryAddTransient() + .TryAddTransient() + .TryAddTransient() + .TryAddTransient() + .TryAddTransient()); builder.TryAddCoreServices(); diff --git a/FileContextCore/Infrastructure/Internal/FileContextOptionsExtension.cs b/FileContextCore/Infrastructure/Internal/FileContextOptionsExtension.cs index e0453e3..d646040 100644 --- a/FileContextCore/Infrastructure/Internal/FileContextOptionsExtension.cs +++ b/FileContextCore/Infrastructure/Internal/FileContextOptionsExtension.cs @@ -28,7 +28,7 @@ public class FileContextOptionsExtension : IDbContextOptionsExtension public FileContextOptionsExtension() { _options = new FileContextScopedOptions(null, null, null, - typeof(DefaultStoreManager)); + typeof(DefaultStoreManager), typeof(JSONSerializer), typeof(DefaultFileManager)); } @@ -49,10 +49,10 @@ public virtual DbContextOptionsExtensionInfo Info public virtual FileContextScopedOptions Options => _options; - public virtual FileContextOptionsExtension WithCustomOptions(string databaseName, string location, string password, Type storeManagerType) + public virtual FileContextOptionsExtension WithCustomOptions(string databaseName, string location, string password, Type storeManagerType, Type serializerType, Type fileManagerType) { var clone = Clone(); - clone._options = new FileContextScopedOptions(databaseName, location, password, storeManagerType); + clone._options = new FileContextScopedOptions(databaseName, location, password, storeManagerType, serializerType, fileManagerType); return clone; } @@ -105,6 +105,9 @@ public override string LogFragment builder.Append("Location=").Append(Extension.Options.Location).Append(' '); builder.Append("DatabaseName=").Append(Extension.Options.DatabaseName).Append(' '); builder.Append("StoreManager=").Append(Extension.Options.StoreManagerType).Append(' '); + builder.Append("Serializer=").Append(Extension.Options.SerializerType).Append(' '); + builder.Append("FileManager=").Append(Extension.Options.FileManagerType).Append(' '); + builder.Append("StoreManager=").Append(Extension.Options.StoreManagerType).Append(' '); builder.Append("Password=").Append("").Append(' '); _logFragment = builder.ToString(); diff --git a/FileContextCore/Infrastructure/Internal/FileContextScopedOptions.cs b/FileContextCore/Infrastructure/Internal/FileContextScopedOptions.cs index bd8e575..a7be62b 100644 --- a/FileContextCore/Infrastructure/Internal/FileContextScopedOptions.cs +++ b/FileContextCore/Infrastructure/Internal/FileContextScopedOptions.cs @@ -1,18 +1,17 @@ using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.EntityFrameworkCore.Infrastructure; namespace FileContextCore.Infrastructure.Internal { public class FileContextScopedOptions : IFileContextScopedOptions { - public FileContextScopedOptions(string databaseName, string location, string password, Type storeManagerType) + public FileContextScopedOptions(string databaseName, string location, string password, Type storeManagerType, Type serializerType, Type fileManagerType) { DatabaseName = databaseName; Location = location; Password = password; StoreManagerType = storeManagerType; + SerializerType = serializerType; + FileManagerType = fileManagerType; } public string DatabaseName { get; } @@ -22,10 +21,14 @@ public FileContextScopedOptions(string databaseName, string location, string pas public string Password { get; } public Type StoreManagerType { get; } + + public Type SerializerType { get; } + + public Type FileManagerType { get; } public override int GetHashCode() { - return (DatabaseName + Location + Password + StoreManagerType).GetHashCode(); + return (DatabaseName + Location + Password + StoreManagerType + SerializerType + FileManagerType).GetHashCode(); } public override bool Equals(object obj) @@ -37,7 +40,8 @@ public override bool Equals(object obj) FileContextScopedOptions optionsCompare = (FileContextScopedOptions) obj; return optionsCompare.DatabaseName == DatabaseName && optionsCompare.Location == Location && - optionsCompare.Password == Password && optionsCompare.StoreManagerType == StoreManagerType; + optionsCompare.Password == Password && optionsCompare.StoreManagerType == StoreManagerType && + optionsCompare.SerializerType == SerializerType && optionsCompare.FileManagerType == FileManagerType; } } } diff --git a/FileContextCore/Infrastructure/Internal/IFileContextScopedOptions.cs b/FileContextCore/Infrastructure/Internal/IFileContextScopedOptions.cs index 307db4f..f3243c4 100644 --- a/FileContextCore/Infrastructure/Internal/IFileContextScopedOptions.cs +++ b/FileContextCore/Infrastructure/Internal/IFileContextScopedOptions.cs @@ -8,5 +8,7 @@ public interface IFileContextScopedOptions string Location { get; } string Password { get; } Type StoreManagerType { get; } + Type SerializerType { get; } + Type FileManagerType { get; } } } diff --git a/FileContextCore/Serializer/JSONSerializer.cs b/FileContextCore/Serializer/JSONSerializer.cs index d2dba1b..5afd711 100644 --- a/FileContextCore/Serializer/JSONSerializer.cs +++ b/FileContextCore/Serializer/JSONSerializer.cs @@ -1,11 +1,10 @@ -using Microsoft.EntityFrameworkCore.Metadata; -using Newtonsoft.Json.Linq; -using System; +using System; using System.Collections.Generic; using System.Linq; using FileContextCore.Infrastructure.Internal; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; +using Microsoft.EntityFrameworkCore.Metadata; +using Newtonsoft.Json.Linq; namespace FileContextCore.Serializer { @@ -15,7 +14,7 @@ public class JSONSerializer : ISerializer private object _keyValueFactory; private string[] _propertyKeys; private Type[] _typeList; - + public void Initialize(IFileContextScopedOptions _, IEntityType entityType, object keyValueFactory) { _keyValueFactory = keyValueFactory; diff --git a/FileContextCore/Storage/Internal/FileContextStoreCache.cs b/FileContextCore/Storage/Internal/FileContextStoreCache.cs index 1c3ef09..0765104 100644 --- a/FileContextCore/Storage/Internal/FileContextStoreCache.cs +++ b/FileContextCore/Storage/Internal/FileContextStoreCache.cs @@ -3,6 +3,7 @@ // Modified version by morrisjdev // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Concurrent; using System.Threading; using FileContextCore.Infrastructure.Internal; @@ -15,15 +16,18 @@ namespace FileContextCore.Storage.Internal public class FileContextStoreCache : IFileContextStoreCache { [NotNull] private readonly ILoggingOptions _loggingOptions; + private readonly IServiceProvider _serviceProvider; private readonly bool _useNameMatching; private readonly ConcurrentDictionary _namedStores; public FileContextStoreCache( [NotNull] ILoggingOptions loggingOptions, - [CanBeNull] IFileContextSingletonOptions options) + [CanBeNull] IFileContextSingletonOptions options, + IServiceProvider serviceProvider) { _loggingOptions = loggingOptions; + _serviceProvider = serviceProvider; if (options?.DatabaseRoot != null) { _useNameMatching = true; @@ -43,7 +47,7 @@ public FileContextStoreCache( public virtual IFileContextStore GetStore(IFileContextScopedOptions options) { - return _namedStores.GetOrAdd(options, _ => new FileContextStore(new FileContextTableFactory(_loggingOptions, options), _useNameMatching)); + return _namedStores.GetOrAdd(options, _ => new FileContextStore(new FileContextTableFactory(_loggingOptions, options, _serviceProvider), _useNameMatching)); } } } diff --git a/FileContextCore/Storage/Internal/FileContextTable.cs b/FileContextCore/Storage/Internal/FileContextTable.cs index 3af7a08..22e8c1e 100644 --- a/FileContextCore/Storage/Internal/FileContextTable.cs +++ b/FileContextCore/Storage/Internal/FileContextTable.cs @@ -33,6 +33,7 @@ public class FileContextTable : IFileContextTable private readonly bool _sensitiveLoggingEnabled; private readonly IEntityType _entityType; private readonly IFileContextScopedOptions _options; + private readonly IServiceProvider _serviceProvider; private readonly Dictionary _rows; private IStoreManager _storeManager; @@ -44,12 +45,14 @@ public FileContextTable( [NotNull] Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IPrincipalKeyValueFactory keyValueFactory, bool sensitiveLoggingEnabled, IEntityType entityType, - IFileContextScopedOptions options) + IFileContextScopedOptions options, + IServiceProvider serviceProvider) { _keyValueFactory = keyValueFactory; _sensitiveLoggingEnabled = sensitiveLoggingEnabled; _entityType = entityType; _options = options; + _serviceProvider = serviceProvider; _rows = Init(); } @@ -242,7 +245,7 @@ protected virtual void ThrowUpdateConcurrencyException([NotNull] IUpdateEntry en private Dictionary Init() { - _storeManager = (IStoreManager)Activator.CreateInstance(_options.StoreManagerType); + _storeManager = (IStoreManager)_serviceProvider.GetService(_options.StoreManagerType); _storeManager.Initialize(_options, _entityType, _keyValueFactory); Dictionary newList = new Dictionary(_keyValueFactory.EqualityComparer); diff --git a/FileContextCore/Storage/Internal/FileContextTableFactory.cs b/FileContextCore/Storage/Internal/FileContextTableFactory.cs index 6abc3ab..57e0c1a 100644 --- a/FileContextCore/Storage/Internal/FileContextTableFactory.cs +++ b/FileContextCore/Storage/Internal/FileContextTableFactory.cs @@ -5,34 +5,34 @@ using System; using System.Collections.Concurrent; -using System.Linq; using System.Reflection; using FileContextCore.Infrastructure.Internal; using FileContextCore.Utilities; using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Utilities; +using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace FileContextCore.Storage.Internal { public class FileContextTableFactory // WARNING: The in-memory provider is using EF internal code here. This should not be copied by other providers. See #15096 - : Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMapFactoryFactoryBase, IFileContextTableFactory + : IdentityMapFactoryFactoryBase, IFileContextTableFactory { private readonly IFileContextScopedOptions _options; + private readonly IServiceProvider _serviceProvider; private readonly bool _sensitiveLoggingEnabled; private readonly ConcurrentDictionary> _factories = new ConcurrentDictionary>(); - public FileContextTableFactory([NotNull] ILoggingOptions loggingOptions, [NotNull] IFileContextScopedOptions options) + public FileContextTableFactory([NotNull] ILoggingOptions loggingOptions, [NotNull] IFileContextScopedOptions options, IServiceProvider serviceProvider) { _options = options; + _serviceProvider = serviceProvider; Check.NotNull(loggingOptions, nameof(loggingOptions)); _sensitiveLoggingEnabled = loggingOptions.IsSensitiveDataLoggingEnabled; @@ -46,15 +46,16 @@ private Func Create([NotNull] IKey key) => (Func)typeof(FileContextTableFactory).GetTypeInfo() .GetDeclaredMethod(nameof(CreateFactory)) .MakeGenericMethod(GetKeyType(key)) - .Invoke(null, new object[] { key, key.DeclaringEntityType, _sensitiveLoggingEnabled, _options }); + .Invoke(null, new object[] { key, key.DeclaringEntityType, _sensitiveLoggingEnabled, _options, _serviceProvider }); [UsedImplicitly] - private static Func CreateFactory(IKey key, IEntityType entityType, bool sensitiveLoggingEnabled, IFileContextScopedOptions options) + private static Func CreateFactory(IKey key, IEntityType entityType, bool sensitiveLoggingEnabled, IFileContextScopedOptions options, IServiceProvider serviceProvider) => () => new FileContextTable( // WARNING: The in-memory provider is using EF internal code here. This should not be copied by other providers. See #15096 - Microsoft.EntityFrameworkCore.Metadata.Internal.KeyExtensions.GetPrincipalKeyValueFactory(key), + KeyExtensions.GetPrincipalKeyValueFactory(key), sensitiveLoggingEnabled, entityType, - options); + options, + serviceProvider); } } diff --git a/FileContextCore/StoreManager/DefaultStoreManager.cs b/FileContextCore/StoreManager/DefaultStoreManager.cs index 8e98f68..6a4e4f8 100644 --- a/FileContextCore/StoreManager/DefaultStoreManager.cs +++ b/FileContextCore/StoreManager/DefaultStoreManager.cs @@ -7,25 +7,28 @@ namespace FileContextCore.StoreManager { - public class DefaultStoreManager : IStoreManager - where TSerializer : ISerializer - where TFileManager : IFileManager - { + class DefaultStoreManager : IStoreManager { + private readonly IServiceProvider _serviceProvider; private ISerializer _serializer; private IFileManager _fileManager; private object _keyValueFactory; private IEntityType _entityType; + + public DefaultStoreManager(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } public void Initialize(IFileContextScopedOptions options, IEntityType entityType, object keyValueFactory) { _keyValueFactory = keyValueFactory; _entityType = entityType; - - _serializer = (ISerializer)Activator.CreateInstance(typeof(TSerializer)); + + _serializer = (ISerializer)_serviceProvider.GetService(options.SerializerType); _serializer.Initialize(options, _entityType, _keyValueFactory); - - _fileManager = (IFileManager)Activator.CreateInstance(typeof(TFileManager)); + + _fileManager = (IFileManager)_serviceProvider.GetService(options.FileManagerType); _fileManager.Initialize(options, entityType, _serializer.FileType); }