Improve scoped service
This commit is contained in:
@@ -4,10 +4,10 @@ using Toolkit.Foundation;
|
||||
|
||||
namespace Toolkit.Avalonia;
|
||||
|
||||
public class FileProvider(ITopLevelProvider topLevelProvider) :
|
||||
IFileProvider
|
||||
public class FilePicker(ITopLevelProvider topLevelProvider) :
|
||||
IFilePicker
|
||||
{
|
||||
public async Task<IReadOnlyCollection<string>> SelectFiles(FileFilter filter)
|
||||
public async Task<IReadOnlyCollection<string>> Get(FilePickerFilter filter)
|
||||
{
|
||||
if (topLevelProvider.Get() is TopLevel topLevel)
|
||||
{
|
||||
@@ -4,10 +4,10 @@ using Toolkit.Foundation;
|
||||
|
||||
namespace Toolkit.Avalonia;
|
||||
|
||||
public class FolderProvider(ITopLevelProvider topLevelProvider) :
|
||||
IFolderProvider
|
||||
public class FolderPicker(ITopLevelProvider topLevelProvider) :
|
||||
IFolderPicker
|
||||
{
|
||||
public async Task<IReadOnlyCollection<string>> SelectFolders(FolderFilter filter)
|
||||
public async Task<IReadOnlyCollection<string>> Get(FolderPickerPicker filter)
|
||||
{
|
||||
if (topLevelProvider.Get() is TopLevel topLevel)
|
||||
{
|
||||
@@ -12,8 +12,8 @@ public static class IServiceCollectionExtensions
|
||||
public static IServiceCollection AddAvalonia(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<ITopLevelProvider, TopLevelProvider>();
|
||||
services.AddTransient<IFileProvider, FileProvider>();
|
||||
services.AddTransient<IFolderProvider, FolderProvider>();
|
||||
services.AddTransient<IFilePicker, FilePicker>();
|
||||
services.AddTransient<IFolderPicker, FolderPicker>();
|
||||
|
||||
services.AddTransient<IClipboardWriter, ClipboardWriter>();
|
||||
|
||||
@@ -27,8 +27,8 @@ public static class IServiceCollectionExtensions
|
||||
services.AddTransient<INavigationRegion, NavigationRegion>();
|
||||
|
||||
services.AddAsyncHandler<WriteEventArgs<Clipboard<object>>, WriteClipboardHandler>();
|
||||
services.AddAsyncHandler<SelectionEventArgs<FolderFilter>, IReadOnlyCollection<string>?, SelectFoldersHandler>();
|
||||
services.AddAsyncHandler<SelectionEventArgs<FileFilter>, IReadOnlyCollection<string>?, SelectFilesHandler>();
|
||||
services.AddAsyncHandler<SelectionEventArgs<FolderPickerPicker>, IReadOnlyCollection<string>?, SelectFoldersHandler>();
|
||||
services.AddAsyncHandler<SelectionEventArgs<FilePickerFilter>, IReadOnlyCollection<string>?, SelectFilesHandler>();
|
||||
|
||||
services.AddHandler<NavigateTemplateEventArgs, ClassicDesktopStyleApplicationHandler>(nameof(IClassicDesktopStyleApplicationLifetime));
|
||||
services.AddHandler<NavigateTemplateEventArgs, SingleViewApplicationHandler>(nameof(ISingleViewApplicationLifetime));
|
||||
@@ -51,8 +51,8 @@ public static class IServiceCollectionExtensions
|
||||
new ProxyServiceCollection<IComponentBuilder>(services =>
|
||||
{
|
||||
services.AddTransient<ITopLevelProvider, TopLevelProvider>();
|
||||
services.AddTransient<IFileProvider, FileProvider>();
|
||||
services.AddTransient<IFolderProvider, FolderProvider>();
|
||||
services.AddTransient<IFilePicker, FilePicker>();
|
||||
services.AddTransient<IFolderPicker, FolderPicker>();
|
||||
|
||||
services.AddTransient<IClipboardWriter, ClipboardWriter>();
|
||||
|
||||
@@ -66,8 +66,8 @@ public static class IServiceCollectionExtensions
|
||||
services.AddTransient<INavigationRegion, NavigationRegion>();
|
||||
|
||||
services.AddAsyncHandler<WriteEventArgs<Clipboard<object>>, WriteClipboardHandler>();
|
||||
services.AddAsyncHandler<SelectionEventArgs<FolderFilter>, IReadOnlyCollection<string>?, SelectFoldersHandler>();
|
||||
services.AddAsyncHandler<SelectionEventArgs<FileFilter>, IReadOnlyCollection<string>?, SelectFilesHandler>();
|
||||
services.AddAsyncHandler<SelectionEventArgs<FolderPickerPicker>, IReadOnlyCollection<string>?, SelectFoldersHandler>();
|
||||
services.AddAsyncHandler<SelectionEventArgs<FilePickerFilter>, IReadOnlyCollection<string>?, SelectFilesHandler>();
|
||||
|
||||
services.AddHandler<NavigateTemplateEventArgs, ContentControlHandler>(nameof(ContentControl));
|
||||
|
||||
|
||||
@@ -52,8 +52,10 @@ public class DefaultHostBuilder :
|
||||
services.AddTransient<IComponentFactory, ComponentFactory>();
|
||||
services.AddTransient<IComponentScopeProvider, ComponentScopeProvider>();
|
||||
|
||||
services.AddHandlerScoped<NavigateEventArgs, NavigateHandler>();
|
||||
services.AddHandlerScoped<NavigateBackEventArgs, NavigateBackHandler>();
|
||||
services.AddScopedHandler<NavigateEventArgs, NavigateHandler>();
|
||||
services.AddScopedHandler<NavigateBackEventArgs, NavigateBackHandler>();
|
||||
|
||||
services.AddTransient<IFileProvider, FileProvider>();
|
||||
|
||||
services.AddInitialization<ComponentInitializer>();
|
||||
});
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public record FileDescriptor(string Name, string Path, long Size) :
|
||||
IFileDescriptor;
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public record FileFilter(string Name, List<string> Extensions, bool AllowMultiple = false);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public record FilePickerFilter(string Name, List<string> Extensions, bool AllowMultiple = false);
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class FileProvider :
|
||||
IFileProvider
|
||||
{
|
||||
public IReadOnlyCollection<string> Get(string path,
|
||||
FileProviderFilter filter)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
List<string> searchPatterns = filter.Extensions.Count > 0
|
||||
? filter.Extensions.Select(ext => $"*.{ext}").ToList()
|
||||
: ["*.*"];
|
||||
|
||||
List<string> files = [];
|
||||
|
||||
foreach (string pattern in searchPatterns)
|
||||
{
|
||||
files.AddRange(Directory.EnumerateFiles(path, pattern, SearchOption.TopDirectoryOnly));
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public record FileProviderFilter(List<string> Extensions);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public record FolderFilter(bool AllowMultiple = false);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public record FolderPickerPicker(bool AllowMultiple = false);
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface IFileDescriptor
|
||||
{
|
||||
string Name { get; }
|
||||
|
||||
string Path { get; }
|
||||
|
||||
long Size { get; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface IFilePicker
|
||||
{
|
||||
Task<IReadOnlyCollection<string>> Get(FilePickerFilter filter);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface IFileProvider
|
||||
|
||||
namespace Toolkit.Foundation
|
||||
{
|
||||
Task<IReadOnlyCollection<string>> SelectFiles(FileFilter filter);
|
||||
public interface IFileProvider
|
||||
{
|
||||
IReadOnlyCollection<string> Get(string path, FileProviderFilter filter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface IFolderPicker
|
||||
{
|
||||
Task<IReadOnlyCollection<string>> Get(FolderPickerPicker filter);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface IFolderProvider
|
||||
{
|
||||
Task<IReadOnlyCollection<string>> SelectFolders(FolderFilter filter);
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface IServiceScopeFactory<TService>
|
||||
public interface IScopedServiceFactory<TService>
|
||||
{
|
||||
(IServiceScope, TService) Create(params object?[] parameters);
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public interface IServiceScopeProvider<TService>
|
||||
public interface IScopedServiceProvider<TService>
|
||||
{
|
||||
bool TryGet(TService service, out IServiceScope? serviceScope);
|
||||
}
|
||||
@@ -216,11 +216,11 @@ public static class IServiceCollectionExtensions
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHandlerScoped<TMessage, THandler>(this IServiceCollection services,
|
||||
public static IServiceCollection AddScopedHandler<TMessage, THandler>(this IServiceCollection services,
|
||||
string key) where THandler : class, IHandler<TMessage>
|
||||
where TMessage : class => AddHandlerScoped<TMessage, THandler>(services, ServiceLifetime.Transient, key);
|
||||
where TMessage : class => AddScopedHandler<TMessage, THandler>(services, ServiceLifetime.Transient, key);
|
||||
|
||||
public static IServiceCollection AddHandlerScoped<TMessage, THandler>(this IServiceCollection services,
|
||||
public static IServiceCollection AddScopedHandler<TMessage, THandler>(this IServiceCollection services,
|
||||
ServiceLifetime lifetime = ServiceLifetime.Transient,
|
||||
string? key = null) where THandler : class, IHandler<TMessage>
|
||||
where TMessage : class
|
||||
@@ -243,11 +243,11 @@ public static class IServiceCollectionExtensions
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHandlerScoped<TMessage, TResponse, THandler>(this IServiceCollection services,
|
||||
public static IServiceCollection AddScopedHandler<TMessage, TResponse, THandler>(this IServiceCollection services,
|
||||
string key) where THandler : class, IHandler<TMessage, TResponse>
|
||||
where TMessage : class => AddHandlerScoped<TMessage, TResponse, THandler>(services, ServiceLifetime.Transient, key);
|
||||
where TMessage : class => AddScopedHandler<TMessage, TResponse, THandler>(services, ServiceLifetime.Transient, key);
|
||||
|
||||
public static IServiceCollection AddHandlerScoped<TMessage, TResponse, THandler>(this IServiceCollection services,
|
||||
public static IServiceCollection AddScopedHandler<TMessage, TResponse, THandler>(this IServiceCollection services,
|
||||
ServiceLifetime lifetime = ServiceLifetime.Transient,
|
||||
string? key = null) where THandler : class, IHandler<TMessage, TResponse>
|
||||
where TMessage : class
|
||||
@@ -351,30 +351,38 @@ public static class IServiceCollectionExtensions
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddServiceScope<TServiceScope>(this IServiceCollection services)
|
||||
where TServiceScope : notnull
|
||||
public static IServiceCollection AddScopedService<TScopedService>(this IServiceCollection services)
|
||||
where TScopedService : class
|
||||
{
|
||||
services.AddCache<TServiceScope, IServiceScope>();
|
||||
services.AddTransient<IServiceScopeProvider<TServiceScope>, ServiceScopeProvider<TServiceScope>>();
|
||||
services.AddTransient<IServiceScopeFactory<TServiceScope>, ServiceScopeFactory<TServiceScope>>();
|
||||
services.AddScoped<IScopedServiceDescriptor<TScopedService>, ScopedServiceDescriptor<TScopedService>>();
|
||||
services.AddScoped(provider => provider.GetRequiredService<IScopedServiceDescriptor<TScopedService>>().Value!);
|
||||
|
||||
services.AddCache<TScopedService, IServiceScope>();
|
||||
|
||||
services.AddTransient<IScopedServiceProvider<TScopedService>, ScopedServiceProvider<TScopedService>>();
|
||||
services.AddTransient<IScopedServiceFactory<TScopedService>, ScopedServiceFactory<TScopedService>>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddServiceScope<TServiceScope>(this IServiceCollection services,
|
||||
public static IServiceCollection AddScopedService<TScopedService>(this IServiceCollection services,
|
||||
Action<IServiceProvider> providerDelegate)
|
||||
where TServiceScope : notnull
|
||||
where TScopedService : class
|
||||
{
|
||||
services.AddCache<TServiceScope, IServiceScope>();
|
||||
services.AddTransient<IServiceScopeProvider<TServiceScope>, ServiceScopeProvider<TServiceScope>>();
|
||||
services.AddTransient<IServiceScopeFactory<TServiceScope>, ServiceScopeFactory<TServiceScope>>(provider =>
|
||||
services.AddScoped<IScopedServiceDescriptor<TScopedService>, ScopedServiceDescriptor<TScopedService>>();
|
||||
services.AddScoped(provider => provider.GetRequiredService<IScopedServiceDescriptor<TScopedService>>().Value!);
|
||||
|
||||
services.AddCache<TScopedService, IServiceScope>();
|
||||
|
||||
services.AddTransient<IScopedServiceProvider<TScopedService>, ScopedServiceProvider<TScopedService>>();
|
||||
services.AddTransient<IScopedServiceFactory<TScopedService>, ScopedServiceFactory<TScopedService>>(provider =>
|
||||
{
|
||||
providerDelegate.Invoke(provider);
|
||||
|
||||
IServiceScopeFactory factory = provider.GetRequiredService<IServiceScopeFactory>();
|
||||
ICache<TServiceScope, IServiceScope> cache = provider.GetRequiredService<ICache<TServiceScope, IServiceScope>>();
|
||||
ICache<TScopedService, IServiceScope> cache = provider.GetRequiredService<ICache<TScopedService, IServiceScope>>();
|
||||
|
||||
return new ServiceScopeFactory<TServiceScope>(factory, cache);
|
||||
return new ScopedServiceFactory<TScopedService>(factory, cache);
|
||||
});
|
||||
|
||||
return services;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class ScopedServiceFactory<TScopedService>(IServiceScopeFactory serviceScopeFactory,
|
||||
ICache<TScopedService, IServiceScope> cache) :
|
||||
IScopedServiceFactory<TScopedService>
|
||||
where TScopedService : notnull
|
||||
{
|
||||
public (IServiceScope, TScopedService) Create(params object?[] parameters)
|
||||
{
|
||||
if (serviceScopeFactory.CreateScope() is IServiceScope serviceScope)
|
||||
{
|
||||
IServiceProvider serviceProvider = serviceScope.ServiceProvider;
|
||||
|
||||
if (serviceProvider.GetRequiredService<IServiceFactory>() is IServiceFactory factory)
|
||||
{
|
||||
if (factory.Create<TScopedService>(parameters) is TScopedService service)
|
||||
{
|
||||
serviceProvider.GetRequiredService<IScopedServiceDescriptor<TScopedService>>().Set(service);
|
||||
cache.Add(service, serviceScope);
|
||||
|
||||
foreach (IInitializationScoped initializationScoped in serviceScope.ServiceProvider.GetServices<IInitializationScoped>())
|
||||
{
|
||||
initializationScoped.Initialize();
|
||||
}
|
||||
|
||||
return (serviceScope, service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class ServiceScopeProvider<TService>(ICache<TService, IServiceScope> cache) :
|
||||
IServiceScopeProvider<TService>
|
||||
public class ScopedServiceProvider<TService>(ICache<TService, IServiceScope> cache) :
|
||||
IScopedServiceProvider<TService>
|
||||
where TService : notnull
|
||||
{
|
||||
public bool TryGet(TService service,
|
||||
@@ -1,14 +1,14 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class SelectFilesHandler(IFileProvider fileProvider) :
|
||||
IAsyncHandler<SelectionEventArgs<FileFilter>, IReadOnlyCollection<string>?>
|
||||
public class SelectFilesHandler(IFilePicker fileProvider) :
|
||||
IAsyncHandler<SelectionEventArgs<FilePickerFilter>, IReadOnlyCollection<string>?>
|
||||
{
|
||||
public async Task<IReadOnlyCollection<string>?> Handle(SelectionEventArgs<FileFilter> args,
|
||||
public async Task<IReadOnlyCollection<string>?> Handle(SelectionEventArgs<FilePickerFilter> args,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (args.Value is FileFilter filter)
|
||||
if (args.Value is FilePickerFilter filter)
|
||||
{
|
||||
if (await fileProvider.SelectFiles(filter)
|
||||
if (await fileProvider.Get(filter)
|
||||
is { Count: > 0 } files)
|
||||
{
|
||||
return files;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
|
||||
public class SelectFoldersHandler(IFolderProvider folderProvider) :
|
||||
IAsyncHandler<SelectionEventArgs<FolderFilter>, IReadOnlyCollection<string>?>
|
||||
public class SelectFoldersHandler(IFolderPicker folderProvider) :
|
||||
IAsyncHandler<SelectionEventArgs<FolderPickerPicker>, IReadOnlyCollection<string>?>
|
||||
{
|
||||
public async Task<IReadOnlyCollection<string>?> Handle(SelectionEventArgs<FolderFilter> args,
|
||||
public async Task<IReadOnlyCollection<string>?> Handle(SelectionEventArgs<FolderPickerPicker> args,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (args.Value is FolderFilter filter)
|
||||
if (args.Value is FolderPickerPicker filter)
|
||||
{
|
||||
if (await folderProvider.SelectFolders(filter)
|
||||
if (await folderProvider.Get(filter)
|
||||
is { Count: > 0 } folders)
|
||||
{
|
||||
return folders;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Toolkit.Foundation;
|
||||
|
||||
public class ServiceScopeFactory<TServiceScope>(IServiceScopeFactory serviceScopeFactory,
|
||||
ICache<TServiceScope, IServiceScope> cache) :
|
||||
IServiceScopeFactory<TServiceScope>
|
||||
where TServiceScope : notnull
|
||||
{
|
||||
public (IServiceScope, TServiceScope) Create(params object?[] parameters)
|
||||
{
|
||||
if (serviceScopeFactory.CreateScope() is IServiceScope serviceScope)
|
||||
{
|
||||
if (serviceScope.ServiceProvider.GetService<IServiceFactory>() is IServiceFactory factory)
|
||||
{
|
||||
if (factory.Create<TServiceScope>(parameters) is TServiceScope service)
|
||||
{
|
||||
cache.Add(service, serviceScope);
|
||||
foreach (IInitializationScoped initializationScoped in serviceScope.ServiceProvider.GetServices<IInitializationScoped>())
|
||||
{
|
||||
initializationScoped.Initialize();
|
||||
}
|
||||
|
||||
return (serviceScope, service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@ public static class IServiceCollectionExtensions
|
||||
services.AddTransient<IContentTemplate, ContentTemplate>();
|
||||
services.AddTransient<INavigationRegion, NavigationRegion>();
|
||||
|
||||
services.AddHandlerScoped<NavigateTemplateEventArgs, ContentControlHandler>(nameof(ContentControl));
|
||||
services.AddHandlerScoped<NavigateTemplateEventArgs, ContentDialogHandler>(nameof(ContentDialog));
|
||||
services.AddScopedHandler<NavigateTemplateEventArgs, ContentControlHandler>(nameof(ContentControl));
|
||||
services.AddScopedHandler<NavigateTemplateEventArgs, ContentDialogHandler>(nameof(ContentDialog));
|
||||
|
||||
services.AddTransient((Func<IServiceProvider, IProxyServiceCollection<IComponentBuilder>>)(provider =>
|
||||
new ProxyServiceCollection<IComponentBuilder>(services =>
|
||||
|
||||
Reference in New Issue
Block a user