ContentAccess, CreateContainer
This commit is contained in:
@@ -8,6 +8,7 @@ using FileTime.Core.Command.CreateContainer;
|
||||
using FileTime.Core.Interactions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
using InitableService;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using CopyCommand = FileTime.Core.Command.Copy.CopyCommand;
|
||||
|
||||
@@ -21,10 +22,9 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
|
||||
private readonly IClipboardService _clipboardService;
|
||||
private readonly IInputInterface _inputInterface;
|
||||
private readonly ILogger<ItemManipulationUserCommandHandlerService> _logger;
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly ICommandScheduler _commandScheduler;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly BindedCollection<FullName>? _markedItems;
|
||||
private PointInTime _currentPointInTime;
|
||||
private IContainer? _currentLocation;
|
||||
|
||||
public ItemManipulationUserCommandHandlerService(
|
||||
@@ -34,20 +34,19 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
|
||||
IInputInterface inputInterface,
|
||||
ILogger<ItemManipulationUserCommandHandlerService> logger,
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
ICommandScheduler commandScheduler) : base(appState, timelessContentProvider)
|
||||
ICommandScheduler commandScheduler,
|
||||
IServiceProvider serviceProvider) : base(appState, timelessContentProvider)
|
||||
{
|
||||
_userCommandHandlerService = userCommandHandlerService;
|
||||
_clipboardService = clipboardService;
|
||||
_inputInterface = inputInterface;
|
||||
_logger = logger;
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_commandScheduler = commandScheduler;
|
||||
_currentPointInTime = null!;
|
||||
_serviceProvider = serviceProvider;
|
||||
|
||||
SaveSelectedTab(t => _selectedTab = t);
|
||||
SaveCurrentLocation(l => _currentLocation = l);
|
||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||
SaveCurrentPointInTime(t => _currentPointInTime = t);
|
||||
|
||||
_markedItems = new BindedCollection<FullName>(appState.SelectedTab.Select(t => t?.MarkedItems));
|
||||
|
||||
@@ -85,7 +84,9 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
|
||||
else if (_currentSelectedItem?.BaseItem != null)
|
||||
{
|
||||
var item = _currentSelectedItem.BaseItem;
|
||||
_clipboardService.AddContent(item.FullName ?? throw new ArgumentException($"{nameof(item.FullName)} can not be null.", nameof(item)));
|
||||
_clipboardService.AddContent(item.FullName ??
|
||||
throw new ArgumentException($"{nameof(item.FullName)} can not be null.",
|
||||
nameof(item)));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
@@ -134,7 +135,9 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
|
||||
|
||||
if (_currentLocation?.FullName is null || newContainerName is null) return;
|
||||
|
||||
var command = new CreateContainerCommand(_currentLocation.FullName, newContainerName, _timelessContentProvider);
|
||||
var command = _serviceProvider
|
||||
.GetInitableResolver<FullName, string>(_currentLocation.FullName, newContainerName)
|
||||
.GetRequiredService<CreateContainerCommand>();
|
||||
await _commandScheduler.AddCommand(command);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using FileTime.App.Core.StartupServices;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.Core.ViewModels.ItemPreview;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace FileTime.App.Core;
|
||||
|
||||
@@ -11,20 +12,19 @@ public static class Startup
|
||||
{
|
||||
public static IServiceCollection AddCoreAppServices(this IServiceCollection serviceCollection)
|
||||
{
|
||||
return serviceCollection
|
||||
.AddTransient<ITabViewModel, TabViewModel>()
|
||||
.AddTransient<IContainerViewModel, ContainerViewModel>()
|
||||
.AddTransient<IElementViewModel, ElementViewModel>()
|
||||
.AddTransient<IFileViewModel, FileViewModel>()
|
||||
.AddTransient<IContainerSizeContainerViewModel, ContainerSizeContainerViewModel>()
|
||||
.AddTransient<IItemNameConverterService, ItemNameConverterService>()
|
||||
.AddTransient<ElementPreviewViewModel>()
|
||||
.AddSingleton<IUserCommandHandlerService, UserCommandHandlerService>()
|
||||
.AddSingleton<IClipboardService, ClipboardService>()
|
||||
.AddSingleton<IIdentifiableUserCommandService, IdentifiableUserCommandService>()
|
||||
.AddSingleton<IStartupHandler, DefaultIdentifiableCommandHandlerRegister>()
|
||||
.AddSingleton<IItemPreviewService, ItemPreviewService>()
|
||||
.AddCommandHandlers();
|
||||
serviceCollection.TryAddTransient<ITabViewModel, TabViewModel>();
|
||||
serviceCollection.TryAddTransient<IContainerViewModel, ContainerViewModel>();
|
||||
serviceCollection.TryAddTransient<IElementViewModel, ElementViewModel>();
|
||||
serviceCollection.TryAddTransient<IFileViewModel, FileViewModel>();
|
||||
serviceCollection.TryAddTransient<IContainerSizeContainerViewModel, ContainerSizeContainerViewModel>();
|
||||
serviceCollection.TryAddTransient<IItemNameConverterService, ItemNameConverterService>();
|
||||
serviceCollection.TryAddTransient<ElementPreviewViewModel>();
|
||||
serviceCollection.TryAddSingleton<IUserCommandHandlerService, UserCommandHandlerService>();
|
||||
serviceCollection.TryAddSingleton<IClipboardService, ClipboardService>();
|
||||
serviceCollection.TryAddSingleton<IIdentifiableUserCommandService, IdentifiableUserCommandService>();
|
||||
serviceCollection.TryAddSingleton<IStartupHandler, DefaultIdentifiableCommandHandlerRegister>();
|
||||
serviceCollection.TryAddSingleton<IItemPreviewService, ItemPreviewService>();
|
||||
return serviceCollection.AddCommandHandlers();
|
||||
}
|
||||
|
||||
private static IServiceCollection AddCommandHandlers(this IServiceCollection serviceCollection)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using FileTime.App.Core;
|
||||
using FileTime.Core.Command;
|
||||
using FileTime.Core.Command.CreateContainer;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Services;
|
||||
using FileTime.Core.Timeline;
|
||||
using FileTime.Providers.Local;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ICommandExecutor = FileTime.Core.Timeline.ICommandExecutor;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace FileTime.App.DependencyInjection;
|
||||
|
||||
@@ -14,13 +16,21 @@ public static class DependencyInjection
|
||||
{
|
||||
serviceCollection ??= new ServiceCollection();
|
||||
|
||||
serviceCollection.TryAddSingleton<ICommandScheduler, CommandScheduler>();
|
||||
serviceCollection.TryAddSingleton<ITimelessContentProvider, TimelessContentProvider>();
|
||||
serviceCollection.TryAddSingleton<ICommandRunner, CommandRunner>();
|
||||
serviceCollection.TryAddSingleton<IContentAccessorFactory, ContentAccessorFactory>();
|
||||
serviceCollection.TryAddSingleton<ITab, Tab>();
|
||||
serviceCollection.TryAddSingleton<ILocalCommandExecutor, LocalCommandExecutor>();
|
||||
|
||||
return serviceCollection
|
||||
.AddSingleton<ICommandScheduler, CommandScheduler>()
|
||||
.AddSingleton<ITimelessContentProvider, TimelessContentProvider>()
|
||||
.AddSingleton<ICommandRunner, CommandRunner>()
|
||||
.AddTransient<ITab, Tab>()
|
||||
.AddTransient<ILocalCommandExecutor, LocalCommandExecutor>()
|
||||
.AddCoreAppServices()
|
||||
.AddLocalServices();
|
||||
.AddLocalServices()
|
||||
.RegisterCommands();
|
||||
}
|
||||
|
||||
public static IServiceCollection RegisterCommands(this IServiceCollection serviceCollection)
|
||||
{
|
||||
return serviceCollection.AddTransient<CreateContainerCommand>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public interface IContentAccessorFactory
|
||||
{
|
||||
IItemCreator<TContentProvider> GetItemCreator<TContentProvider>() where TContentProvider : IContentProvider;
|
||||
IItemCreator GetItemCreator(IContentProvider provider);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public interface IItemCreator
|
||||
{
|
||||
Task CreateContainerAsync(IContentProvider contentProvider, FullName fullName);
|
||||
Task CreateElementAsync(IContentProvider contentProvider, FullName fullName);
|
||||
}
|
||||
|
||||
public interface IItemCreator<in TContentProvider> : IItemCreator where TContentProvider : IContentProvider
|
||||
{
|
||||
Task CreateContainerAsync(TContentProvider contentProvider, FullName fullName);
|
||||
Task CreateElementAsync(TContentProvider contentProvider, FullName fullName);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public abstract class ItemCreatorBase<TContentProvider> : IItemCreator<TContentProvider>
|
||||
where TContentProvider : IContentProvider
|
||||
{
|
||||
public async Task CreateContainerAsync(IContentProvider contentProvider, FullName fullName)
|
||||
=> await CreateContainerAsync((TContentProvider)contentProvider, fullName);
|
||||
|
||||
public async Task CreateElementAsync(IContentProvider contentProvider, FullName fullName)
|
||||
=> await CreateElementAsync((TContentProvider)contentProvider, fullName);
|
||||
|
||||
public abstract Task CreateContainerAsync(TContentProvider contentProvider, FullName fullName);
|
||||
|
||||
public abstract Task CreateElementAsync(TContentProvider contentProvider, FullName fullName);
|
||||
}
|
||||
@@ -1,28 +1,36 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Extensions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
using InitableService;
|
||||
|
||||
namespace FileTime.Core.Command.CreateContainer;
|
||||
|
||||
public class CreateContainerCommand : IExecutableCommand
|
||||
public class CreateContainerCommand : IExecutableCommand, IInitable<FullName, string>
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
public FullName Parent { get; }
|
||||
public string NewContainerName { get; }
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
public FullName? Parent { get; private set; }
|
||||
public string? NewContainerName { get; private set; }
|
||||
|
||||
public CreateContainerCommand(
|
||||
FullName parent,
|
||||
string newContainerName,
|
||||
ITimelessContentProvider timelessContentProvider)
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IContentAccessorFactory contentAccessorFactory)
|
||||
{
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
Parent = parent;
|
||||
NewContainerName = newContainerName;
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public async Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
{
|
||||
if (Parent is null)
|
||||
throw new ArgumentNullException(nameof(Parent),
|
||||
$"Property {nameof(Parent)} is not initialized. Call the {nameof(Init)} method before using the command.");
|
||||
if (NewContainerName is null)
|
||||
throw new ArgumentNullException(nameof(NewContainerName),
|
||||
$"Property {nameof(NewContainerName)} is not initialized. Call the {nameof(Init)} method before using the command.");
|
||||
|
||||
try
|
||||
{
|
||||
var parent = await ResolveParentAsync();
|
||||
@@ -49,6 +57,13 @@ public class CreateContainerCommand : IExecutableCommand
|
||||
|
||||
public Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
{
|
||||
if (Parent is null)
|
||||
throw new ArgumentNullException(nameof(Parent),
|
||||
$"Property {nameof(Parent)} is not initialized. Call the {nameof(Init)} method before using the command.");
|
||||
if (NewContainerName is null)
|
||||
throw new ArgumentNullException(nameof(NewContainerName),
|
||||
$"Property {nameof(NewContainerName)} is not initialized. Call the {nameof(Init)} method before using the command.");
|
||||
|
||||
return Task.FromResult(
|
||||
currentTime.WithDifferences(newPointInTime =>
|
||||
new List<Difference>()
|
||||
@@ -66,11 +81,35 @@ public class CreateContainerCommand : IExecutableCommand
|
||||
);
|
||||
}
|
||||
|
||||
public Task Execute()
|
||||
public async Task Execute()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
if (Parent is null)
|
||||
throw new ArgumentNullException(nameof(Parent),
|
||||
$"Property {nameof(Parent)} is not initialized. Call the {nameof(Init)} method before using the command.");
|
||||
if (NewContainerName is null)
|
||||
throw new ArgumentNullException(nameof(NewContainerName),
|
||||
$"Property {nameof(NewContainerName)} is not initialized. Call the {nameof(Init)} method before using the command.");
|
||||
|
||||
var resolvedParent = await _timelessContentProvider.GetItemByFullNameAsync(Parent, PointInTime.Present);
|
||||
var itemCreator = _contentAccessorFactory.GetItemCreator(resolvedParent.Provider);
|
||||
await itemCreator.CreateContainerAsync(resolvedParent.Provider, Parent.GetChild(NewContainerName));
|
||||
}
|
||||
|
||||
private async Task<IItem> ResolveParentAsync()
|
||||
=> await _timelessContentProvider.GetItemByFullNameAsync(Parent, PointInTime.Present);
|
||||
{
|
||||
if (Parent is null)
|
||||
throw new ArgumentNullException(nameof(Parent),
|
||||
$"Property {nameof(Parent)} is not initialized. Call the {nameof(Init)} method before using the command.");
|
||||
if (NewContainerName is null)
|
||||
throw new ArgumentNullException(nameof(NewContainerName),
|
||||
$"Property {nameof(NewContainerName)} is not initialized. Call the {nameof(Init)} method before using the command.");
|
||||
|
||||
return await _timelessContentProvider.GetItemByFullNameAsync(Parent, PointInTime.Present);
|
||||
}
|
||||
|
||||
public void Init(FullName parent, string newContainerName)
|
||||
{
|
||||
Parent = parent;
|
||||
NewContainerName = newContainerName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public class ContentAccessorFactory : IContentAccessorFactory
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ContentAccessorFactory(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public IItemCreator<TContentProvider> GetItemCreator<TContentProvider>() where TContentProvider : IContentProvider
|
||||
{
|
||||
var genericType = typeof(IItemCreator<>).MakeGenericType(typeof(TContentProvider));
|
||||
|
||||
return (IItemCreator<TContentProvider>)_serviceProvider.GetRequiredService(genericType);
|
||||
}
|
||||
|
||||
public IItemCreator GetItemCreator(IContentProvider provider)
|
||||
{
|
||||
var genericType = typeof(IItemCreator<>).MakeGenericType(provider.GetType());
|
||||
|
||||
return (IItemCreator)_serviceProvider.GetRequiredService(genericType);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ using FileTime.GuiApp.Services;
|
||||
using FileTime.GuiApp.ViewModels;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Serilog;
|
||||
using Serilog.Configuration;
|
||||
|
||||
@@ -20,26 +21,27 @@ public static class Startup
|
||||
{
|
||||
internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection)
|
||||
{
|
||||
return serviceCollection
|
||||
.AddSingleton<MainWindowViewModel>()
|
||||
.AddSingleton<GuiAppState>()
|
||||
.AddSingleton<IAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>())
|
||||
.AddSingleton<IGuiAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>());
|
||||
serviceCollection.TryAddSingleton<MainWindowViewModel>();
|
||||
serviceCollection.TryAddSingleton<GuiAppState>();
|
||||
serviceCollection.TryAddSingleton<IAppState>(s => s.GetRequiredService<GuiAppState>());
|
||||
serviceCollection.TryAddSingleton<IGuiAppState>(s => s.GetRequiredService<GuiAppState>());
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
internal static IServiceCollection RegisterServices(this IServiceCollection serviceCollection)
|
||||
{
|
||||
return serviceCollection
|
||||
.AddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>()
|
||||
.AddSingleton<IKeyInputHandlerService, KeyInputHandlerService>()
|
||||
.AddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>()
|
||||
.AddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>()
|
||||
.AddSingleton<IRapidTravelModeKeyInputHandler, RapidTravelModeKeyInputHandler>()
|
||||
.AddSingleton<IStartupHandler, RootDriveInfoService>()
|
||||
.AddSingleton<LifecycleService>()
|
||||
.AddSingleton<IIconProvider, MaterialIconProvider>()
|
||||
.AddSingleton<IModalService, ModalService>()
|
||||
.AddSingleton<IDialogService, DialogService>()
|
||||
.AddSingleton<IInputInterface>(s => s.GetRequiredService<IDialogService>());
|
||||
serviceCollection.TryAddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>();
|
||||
serviceCollection.TryAddSingleton<IKeyInputHandlerService, KeyInputHandlerService>();
|
||||
serviceCollection.TryAddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>();
|
||||
serviceCollection.TryAddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>();
|
||||
serviceCollection.TryAddSingleton<IRapidTravelModeKeyInputHandler, RapidTravelModeKeyInputHandler>();
|
||||
serviceCollection.TryAddSingleton<IStartupHandler, RootDriveInfoService>();
|
||||
serviceCollection.TryAddSingleton<LifecycleService>();
|
||||
serviceCollection.TryAddSingleton<IIconProvider, MaterialIconProvider>();
|
||||
serviceCollection.TryAddSingleton<IModalService, ModalService>();
|
||||
serviceCollection.TryAddSingleton<IDialogService, DialogService>();
|
||||
serviceCollection.TryAddSingleton<IInputInterface>(s => s.GetRequiredService<IDialogService>());
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection)
|
||||
@@ -79,7 +81,7 @@ public static class Startup
|
||||
return serviceProvider;
|
||||
}
|
||||
|
||||
internal static LoggerConfiguration MessageBoxSink(
|
||||
private static LoggerConfiguration MessageBoxSink(
|
||||
this LoggerSinkConfiguration loggerConfiguration,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
xmlns:config="using:FileTime.GuiApp.Configuration"
|
||||
xmlns:appCoreModels="using:FileTime.App.Core.Models"
|
||||
xmlns:interactions="using:FileTime.Core.Interactions"
|
||||
MinHeight="600"
|
||||
MinWidth="800"
|
||||
Title="FileTime"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
|
||||
23
src/Providers/FileTime.Providers.Local/LocalItemCreator.cs
Normal file
23
src/Providers/FileTime.Providers.Local/LocalItemCreator.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Providers.Local;
|
||||
|
||||
public class LocalItemCreator : ItemCreatorBase<ILocalContentProvider>
|
||||
{
|
||||
public override Task CreateContainerAsync(ILocalContentProvider contentProvider, FullName fullName)
|
||||
{
|
||||
var path = contentProvider.GetNativePath(fullName).Path;
|
||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task CreateElementAsync(ILocalContentProvider contentProvider, FullName fullName)
|
||||
{
|
||||
var path = contentProvider.GetNativePath(fullName).Path;
|
||||
await using (File.Create(path))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace FileTime.Providers.Local;
|
||||
|
||||
@@ -8,8 +8,10 @@ public static class Startup
|
||||
{
|
||||
public static IServiceCollection AddLocalServices(this IServiceCollection serviceCollection)
|
||||
{
|
||||
return serviceCollection
|
||||
.AddSingleton<ILocalContentProvider, LocalContentProvider>()
|
||||
.AddSingleton<IContentProvider, ILocalContentProvider>(sp => sp.GetRequiredService<ILocalContentProvider>());
|
||||
serviceCollection.TryAddSingleton<ILocalContentProvider, LocalContentProvider>();
|
||||
serviceCollection.TryAddSingleton<IContentProvider>(sp => sp.GetRequiredService<ILocalContentProvider>());
|
||||
serviceCollection.TryAddSingleton<IItemCreator<ILocalContentProvider>, LocalItemCreator>();
|
||||
serviceCollection.TryAddSingleton<IItemCreator<LocalContentProvider>>(sp => sp.GetRequiredService<IItemCreator<ILocalContentProvider>>());
|
||||
return serviceCollection;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user