From 04b5c00d44564804768b9e3b6ae2f9c052f9ab2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20LB?= Date: Wed, 21 Feb 2024 21:49:21 +0100 Subject: [PATCH] DESIGN: POC Implementation v2. ServiceProvider instantiation when registering with no DI. Adds AbstractionProvider. #10 --- .editorconfig | 272 ------------------ .../SPALOrchestrationService.Registerings.cs | 44 --- .../IAbstractionProvider.cs | 27 ++ .../STX.SPAL.Providers.Abstractions.csproj | 13 + .../AbstractionProvider.Exceptions.cs | 29 ++ .../AbstractionProvider.Validations.cs | 18 ++ STX.SPAL.Providers/AbstractionProvider.cs | 173 +++++++++++ .../AbstractionProviderExtensions.cs | 52 ++++ STX.SPAL.Providers/STX.SPAL.Providers.csproj | 14 + .../ISPALOrchestrationService.cs | 3 +- {STX.SPAL.Core => STX.SPAL}/SPALExtensions.cs | 16 +- .../SPALOrchestrationService.Assemblies.cs | 2 +- .../SPALOrchestrationService.Exceptions.cs | 2 +- .../SPALOrchestrationService.Registerings.cs | 57 ++++ .../SPALOrchestrationService.Resolvers.cs | 28 +- .../SPALOrchestrationService.Types.cs | 38 ++- .../SPALOrchestrationService.Validations.cs | 25 +- .../SPALOrchestrationService.cs | 20 +- .../STX.SPAL.csproj | 1 + .../Program.Tests.cs | 4 +- STX.Serialization.POC/Program.Tests.cs | 32 ++- STX.Serialization.POC/Program.cs | 2 + STX.Serialization.Providers.Abstractions.sln | 36 ++- .../ISerializationAbstractionProvider.cs | 6 +- ...erialization.Providers.Abstractions.csproj | 1 + .../STX.Serialization.Providers.csproj | 2 +- ...lizationAbstractionProvider.Validations.cs | 3 +- .../SerializationAbstractionProvider.cs | 136 ++++----- ...ializationAbstractionProviderExtensions.cs | 28 +- 29 files changed, 615 insertions(+), 469 deletions(-) delete mode 100644 .editorconfig delete mode 100644 STX.SPAL.Core/SPALOrchestrationService.Registerings.cs create mode 100644 STX.SPAL.Providers.Abstractions/IAbstractionProvider.cs create mode 100644 STX.SPAL.Providers.Abstractions/STX.SPAL.Providers.Abstractions.csproj create mode 100644 STX.SPAL.Providers/AbstractionProvider.Exceptions.cs create mode 100644 STX.SPAL.Providers/AbstractionProvider.Validations.cs create mode 100644 STX.SPAL.Providers/AbstractionProvider.cs create mode 100644 STX.SPAL.Providers/AbstractionProviderExtensions.cs create mode 100644 STX.SPAL.Providers/STX.SPAL.Providers.csproj rename {STX.SPAL.Core => STX.SPAL}/ISPALOrchestrationService.cs (84%) rename {STX.SPAL.Core => STX.SPAL}/SPALExtensions.cs (61%) rename {STX.SPAL.Core => STX.SPAL}/SPALOrchestrationService.Assemblies.cs (98%) rename {STX.SPAL.Core => STX.SPAL}/SPALOrchestrationService.Exceptions.cs (96%) create mode 100644 STX.SPAL/SPALOrchestrationService.Registerings.cs rename {STX.SPAL.Core => STX.SPAL}/SPALOrchestrationService.Resolvers.cs (71%) rename {STX.SPAL.Core => STX.SPAL}/SPALOrchestrationService.Types.cs (64%) rename {STX.SPAL.Core => STX.SPAL}/SPALOrchestrationService.Validations.cs (78%) rename {STX.SPAL.Core => STX.SPAL}/SPALOrchestrationService.cs (67%) rename STX.SPAL.Core/STX.SPAL.Core.csproj => STX.SPAL/STX.SPAL.csproj (83%) diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 6e7cfc7..0000000 --- a/.editorconfig +++ /dev/null @@ -1,272 +0,0 @@ -# Remove the line below if you want to inherit .editorconfig settings from higher directories -root = true - -# C# files -[*.cs] - -#### Core EditorConfig Options #### - -#Formatting - header template -file_header_template = ----------------------------------------------------------------------------------\nCopyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers\n---------------------------------------------------------------------------------- - -# Indentation and spacing -indent_size = 4 -indent_style = tab -tab_width = 4 - -# New line preferences -end_of_line = crlf -insert_final_newline = false - -#### .NET Coding Conventions #### - -# Organize usings -dotnet_separate_import_directive_groups = false -dotnet_sort_system_directives_first = false -file_header_template = ----------------------------------------------------------------------------------\nCopyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers\n---------------------------------------------------------------------------------- - -# this. and Me. preferences -dotnet_style_qualification_for_event = false -dotnet_style_qualification_for_field = false -dotnet_style_qualification_for_method = false -dotnet_style_qualification_for_property = false - -# Language keywords vs BCL types preferences -dotnet_style_predefined_type_for_locals_parameters_members = true -dotnet_style_predefined_type_for_member_access = true - -# Parentheses preferences -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity -dotnet_style_parentheses_in_other_operators = never_if_unnecessary -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity - -# Modifier preferences -dotnet_style_require_accessibility_modifiers = for_non_interface_members - -# Expression-level preferences -dotnet_style_coalesce_expression = true -dotnet_style_collection_initializer = true -dotnet_style_explicit_tuple_names = true -dotnet_style_namespace_match_folder = true -dotnet_style_null_propagation = true -dotnet_style_object_initializer = true -dotnet_style_operator_placement_when_wrapping = beginning_of_line -dotnet_style_prefer_auto_properties = true -dotnet_style_prefer_collection_expression = when_types_loosely_match -dotnet_style_prefer_compound_assignment = true -dotnet_style_prefer_conditional_expression_over_assignment = true -dotnet_style_prefer_conditional_expression_over_return = true -dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed -dotnet_style_prefer_inferred_anonymous_type_member_names = true -dotnet_style_prefer_inferred_tuple_names = true -dotnet_style_prefer_is_null_check_over_reference_equality_method = true -dotnet_style_prefer_simplified_boolean_expressions = true -dotnet_style_prefer_simplified_interpolation = true - -# Field preferences -dotnet_style_readonly_field = true - -# Parameter preferences -dotnet_code_quality_unused_parameters = all - -# Suppression preferences -dotnet_remove_unnecessary_suppression_exclusions = none - -# New line preferences -dotnet_style_allow_multiple_blank_lines_experimental = true -dotnet_style_allow_statement_immediately_after_block_experimental = true - -#### C# Coding Conventions #### - -# var preferences -csharp_style_var_elsewhere = false:silent -csharp_style_var_for_built_in_types = false:silent -csharp_style_var_when_type_is_apparent = false:silent - -# Expression-bodied members -csharp_style_expression_bodied_accessors = true:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_lambdas = true:silent -csharp_style_expression_bodied_local_functions = false:silent -csharp_style_expression_bodied_methods = false:silent -csharp_style_expression_bodied_operators = false:silent -csharp_style_expression_bodied_properties = true:silent - -# Pattern matching preferences -csharp_style_pattern_matching_over_as_with_null_check = true:suggestion -csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_prefer_extended_property_pattern = true:suggestion -csharp_style_prefer_not_pattern = true:suggestion -csharp_style_prefer_pattern_matching = true:silent -csharp_style_prefer_switch_expression = true:suggestion - -# Null-checking preferences -csharp_style_conditional_delegate_call = true:suggestion - -# Modifier preferences -csharp_prefer_static_local_function = true:suggestion -csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async -csharp_style_prefer_readonly_struct = true:suggestion -csharp_style_prefer_readonly_struct_member = true:suggestion - -# Code-block preferences -csharp_prefer_braces = true:silent -csharp_prefer_simple_using_statement = true:suggestion -csharp_style_namespace_declarations = block_scoped:silent -csharp_style_prefer_method_group_conversion = true:silent -csharp_style_prefer_primary_constructors = true:suggestion -csharp_style_prefer_top_level_statements = true:silent - -# Expression-level preferences -csharp_prefer_simple_default_expression = true:suggestion -csharp_style_deconstructed_variable_declaration = true:suggestion -csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion -csharp_style_prefer_index_operator = true:suggestion -csharp_style_prefer_local_over_anonymous_function = true:suggestion -csharp_style_prefer_null_check_over_type_check = true:suggestion -csharp_style_prefer_range_operator = true:suggestion -csharp_style_prefer_tuple_swap = true:suggestion -csharp_style_prefer_utf8_string_literals = true:suggestion -csharp_style_throw_expression = true:suggestion -csharp_style_unused_value_assignment_preference = discard_variable:suggestion -csharp_style_unused_value_expression_statement_preference = discard_variable:silent - -# 'using' directive preferences -csharp_using_directive_placement = outside_namespace:silent - -# New line preferences -csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent -csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent -csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent -csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent -csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent - -#### C# Formatting Rules #### - -# New line preferences -csharp_new_line_before_catch = true -csharp_new_line_before_else = true -csharp_new_line_before_finally = true -csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_open_brace = all -csharp_new_line_between_query_expression_clauses = true - -# Indentation preferences -csharp_indent_block_contents = true -csharp_indent_braces = false -csharp_indent_case_contents = false -csharp_indent_case_contents_when_block = false -csharp_indent_labels = no_change -csharp_indent_switch_labels = false - -# Space preferences -csharp_space_after_cast = false -csharp_space_after_colon_in_inheritance_clause = true -csharp_space_after_comma = true -csharp_space_after_dot = false -csharp_space_after_keywords_in_control_flow_statements = true -csharp_space_after_semicolon_in_for_statement = true -csharp_space_around_binary_operators = before_and_after -csharp_space_around_declaration_statements = false -csharp_space_before_colon_in_inheritance_clause = true -csharp_space_before_comma = false -csharp_space_before_dot = false -csharp_space_before_open_square_brackets = false -csharp_space_before_semicolon_in_for_statement = false -csharp_space_between_empty_square_brackets = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false -csharp_space_between_method_call_parameter_list_parentheses = false -csharp_space_between_method_declaration_empty_parameter_list_parentheses = false -csharp_space_between_method_declaration_name_and_open_parenthesis = false -csharp_space_between_method_declaration_parameter_list_parentheses = false -csharp_space_between_parentheses = false -csharp_space_between_square_brackets = false - -# Wrapping preferences -csharp_preserve_single_line_blocks = true -csharp_preserve_single_line_statements = true - -#### Naming styles #### - -# Naming rules - -dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion -dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface -dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i - -dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.types_should_be_pascal_case.symbols = types -dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case - -dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members -dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case - -# Symbol specifications - -dotnet_naming_symbols.interface.applicable_kinds = interface -dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = - -dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum -dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = - -dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method -dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = - -# Naming styles - -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = -dotnet_naming_style.pascal_case.capitalization = pascal_case - -dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = -dotnet_naming_style.begins_with_i.capitalization = pascal_case - -[*.{cs,vb}] -dotnet_style_operator_placement_when_wrapping = beginning_of_line -tab_width = 4 -indent_size = 4 -end_of_line = crlf -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion -dotnet_style_prefer_auto_properties = true:silent -dotnet_style_object_initializer = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_prefer_simplified_boolean_expressions = true:suggestion -dotnet_style_prefer_conditional_expression_over_assignment = true:silent -dotnet_style_prefer_conditional_expression_over_return = true:silent -dotnet_style_explicit_tuple_names = true:suggestion -dotnet_style_prefer_inferred_tuple_names = true:suggestion -dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_compound_assignment = true:suggestion -dotnet_style_prefer_simplified_interpolation = true:suggestion -dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion -dotnet_style_namespace_match_folder = true:suggestion -indent_style = space -dotnet_style_readonly_field = true:suggestion -dotnet_style_predefined_type_for_locals_parameters_members = true:silent -dotnet_style_predefined_type_for_member_access = true:silent -dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent -dotnet_style_allow_statement_immediately_after_block_experimental = true:silent -dotnet_style_allow_multiple_blank_lines_experimental = true:silent -dotnet_code_quality_unused_parameters = all:suggestion -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent -dotnet_style_qualification_for_property = false:silent -dotnet_style_qualification_for_field = false:silent -dotnet_style_qualification_for_method = false:silent -dotnet_style_qualification_for_event = false:silent \ No newline at end of file diff --git a/STX.SPAL.Core/SPALOrchestrationService.Registerings.cs b/STX.SPAL.Core/SPALOrchestrationService.Registerings.cs deleted file mode 100644 index 910f1d2..0000000 --- a/STX.SPAL.Core/SPALOrchestrationService.Registerings.cs +++ /dev/null @@ -1,44 +0,0 @@ -// ---------------------------------------------------------------------------------- -// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers -// ---------------------------------------------------------------------------------- - -using Microsoft.Extensions.DependencyInjection; -using System; - -namespace STX.SPAL.Core -{ - internal partial class SPALOrchestrationService - { - private static IServiceCollection RegisterImplementation( - IServiceCollection services, - Type implementationType, - bool registeringMultipleProviders) - { - ValidateImplementationTypeRegistered(services, allowMultipleProviders); - - if (registeringMultipleProviders) - { - string spalId = implementationType.Namespace; - services.AddKeyedScoped(typeof(T), spalId, implementationType); - Console.WriteLine($"Registered {implementationType.FullName} ({typeof(T).Name}) with SPAL Id {spalId}"); - } - else - { - services.AddScoped(typeof(T), implementationType); - Console.WriteLine($"Registered {implementationType.FullName} ({typeof(T).Name})"); - } - - return services; - } - - private static IServiceCollection RegisterImplementations( - IServiceCollection services, - Type[] implementationTypes) - { - foreach (var implementationType in implementationTypes) - RegisterImplementation(services, implementationType, implementationTypes.Length > 1); - - return services; - } - } -} diff --git a/STX.SPAL.Providers.Abstractions/IAbstractionProvider.cs b/STX.SPAL.Providers.Abstractions/IAbstractionProvider.cs new file mode 100644 index 0000000..e91eb05 --- /dev/null +++ b/STX.SPAL.Providers.Abstractions/IAbstractionProvider.cs @@ -0,0 +1,27 @@ +// ---------------------------------------------------------------------------------- +// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers +// ---------------------------------------------------------------------------------- + +using STX.SPAL.Abstractions; +using System; +using System.Threading.Tasks; + +namespace STX.SPAL.Providers.Abstractions +{ + public interface IAbstractionProvider where T : ISPALProvider + { + T GetProvider(); + + void UseProvider(string spalId = null); + void UseProvider(Type concreteProviderType = null, string spalId = null); + void UseProvider(string spalId = null) where TConcreteProviderType : T; + + void Invoke(Action spalFunction); + void InvokeWithProvider(Action spalFunction) where TConcreteProviderType : T; + + TResult Invoke(Func spalFunction); + ValueTask InvokeAsync(Func spalFunction); + ValueTask InvokeAsync(Func> spalFunction); + + } +} diff --git a/STX.SPAL.Providers.Abstractions/STX.SPAL.Providers.Abstractions.csproj b/STX.SPAL.Providers.Abstractions/STX.SPAL.Providers.Abstractions.csproj new file mode 100644 index 0000000..48b846e --- /dev/null +++ b/STX.SPAL.Providers.Abstractions/STX.SPAL.Providers.Abstractions.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + disable + disable + + + + + + + diff --git a/STX.SPAL.Providers/AbstractionProvider.Exceptions.cs b/STX.SPAL.Providers/AbstractionProvider.Exceptions.cs new file mode 100644 index 0000000..4f1f3f6 --- /dev/null +++ b/STX.SPAL.Providers/AbstractionProvider.Exceptions.cs @@ -0,0 +1,29 @@ +// ---------------------------------------------------------------------------------- +// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers +// ---------------------------------------------------------------------------------- + +using System; + +namespace STX.SPAL.Providers +{ + internal partial class AbstractionProvider + { + private static TResult TryCatch( + Func function) + { + try + { + return function(); + } + + catch (InvalidOperationException invalidOperationException) + { + throw; + } + catch (Exception exception) + { + throw; + } + } + } +} diff --git a/STX.SPAL.Providers/AbstractionProvider.Validations.cs b/STX.SPAL.Providers/AbstractionProvider.Validations.cs new file mode 100644 index 0000000..30fede4 --- /dev/null +++ b/STX.SPAL.Providers/AbstractionProvider.Validations.cs @@ -0,0 +1,18 @@ +// ---------------------------------------------------------------------------------- +// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers +// ---------------------------------------------------------------------------------- + +using STX.SPAL.Abstractions; +using System; + +namespace STX.SPAL.Providers +{ + internal partial class AbstractionProvider + { + private static void ValidateProvider(ISPALProvider provider) + { + if (provider == null) + throw new Exception("There is no provider initialized."); + } + } +} diff --git a/STX.SPAL.Providers/AbstractionProvider.cs b/STX.SPAL.Providers/AbstractionProvider.cs new file mode 100644 index 0000000..b8972d7 --- /dev/null +++ b/STX.SPAL.Providers/AbstractionProvider.cs @@ -0,0 +1,173 @@ +// ---------------------------------------------------------------------------------- +// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers +// ---------------------------------------------------------------------------------- + +using Microsoft.Extensions.DependencyInjection; +using STX.SPAL.Abstractions; +using STX.SPAL.Providers.Abstractions; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace STX.SPAL.Providers +{ + internal partial class AbstractionProvider : IAbstractionProvider + where T : ISPALProvider + { + private readonly ISPALOrchestrationService spalOrchestrationService; + private readonly T defaultProvider; + private T provider; + + public AbstractionProvider(ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + : this(spalOrchestrationService: null, defaultProviderType: null, defaultProviderSPALId: null, serviceLifetime) + { + } + + public AbstractionProvider(Type defaultProviderType, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + : this(spalOrchestrationService: null, defaultProviderType: defaultProviderType, defaultProviderSPALId: null, serviceLifetime) + { + } + + public AbstractionProvider(string defaultProviderSPALId, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + : this(spalOrchestrationService: null, defaultProviderType: null, defaultProviderSPALId: defaultProviderSPALId, serviceLifetime) + { + } + + public AbstractionProvider(Type defaultProviderType, string defaultProviderSPALId, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + : this(spalOrchestrationService: null, defaultProviderType: defaultProviderType, defaultProviderSPALId: defaultProviderSPALId, serviceLifetime) + { + } + + public AbstractionProvider( + ISPALOrchestrationService spalOrchestrationService, + Type defaultProviderType, + string defaultProviderSPALId, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + { + this.spalOrchestrationService = + spalOrchestrationService == null + ? defaultProvider.GetSPAL(serviceLifetime) + : spalOrchestrationService; + + this.defaultProvider = this.provider = + GetProvider( + providerType: defaultProviderType, + spalId: defaultProviderSPALId); + } + + public AbstractionProvider(T serializationProvider) + { + this.defaultProvider = this.provider = serializationProvider; + } + + public AbstractionProvider( + ISPALOrchestrationService spalOrchestrationService, + Type defaultProviderType = null, + string defaultProviderSPALId = null) + { + this.spalOrchestrationService = spalOrchestrationService; + this.defaultProvider = this.provider = + this.GetProvider( + providerType: defaultProviderType, + spalId: defaultProviderSPALId); + } + + private T GetProvider(Type providerType, string spalId) + { + T provider = default; + + if (providerType == null + && string.IsNullOrEmpty(spalId)) + { + if (defaultProvider != null) + provider = defaultProvider; + else + provider = spalOrchestrationService.GetImplementation(); + } + else + provider = spalOrchestrationService.GetImplementation(providerType, spalId); + + return provider; + } + + public T GetProvider() => + TryCatch(() => + { + ValidateProvider(provider); + + return provider; + }); + + public void UseProvider(string spalId = null) + { + provider = + GetProvider( + providerType: null, + spalId: spalId); + } + + public void UseProvider(Type concreteProviderType = null, string spalId = null) + { + provider = + GetProvider( + providerType: concreteProviderType, + spalId: spalId); + } + + public void UseProvider(string spalId = null) + where TConcreteProviderType : T + { + provider = + GetProvider( + providerType: typeof(TConcreteProviderType), + spalId: spalId); + } + + public void Invoke(Action spalFunction) => + TryCatch(() => + { + ValidateProvider(provider); + spalFunction(provider); + + return true; + }); + + public void InvokeWithProvider(Action spalFunction) + where TConcreteProviderType : T => + TryCatch(() => + { + return spalOrchestrationService + .GetImplementations(typeof(TConcreteProviderType), null) + .Select(implementation => + { + spalFunction(implementation); + return true; + }) + .ToArray(); + }); + + public TResult Invoke(Func spalFunction) => + TryCatch(() => + { + ValidateProvider(provider); + + return spalFunction(provider); + }); + + + public ValueTask InvokeAsync(Func spalFunction) => + TryCatch(async () => + { + ValidateProvider(provider); + await spalFunction(provider); + }); + + public ValueTask InvokeAsync(Func> spalFunction) => + TryCatch>(async () => + { + ValidateProvider(provider); + + return await spalFunction(provider); + }); + } +} diff --git a/STX.SPAL.Providers/AbstractionProviderExtensions.cs b/STX.SPAL.Providers/AbstractionProviderExtensions.cs new file mode 100644 index 0000000..222e348 --- /dev/null +++ b/STX.SPAL.Providers/AbstractionProviderExtensions.cs @@ -0,0 +1,52 @@ +// ---------------------------------------------------------------------------------- +// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers +// ---------------------------------------------------------------------------------- + +using Microsoft.Extensions.DependencyInjection; +using STX.SPAL.Abstractions; +using STX.SPAL.Providers.Abstractions; +using System; + +namespace STX.SPAL.Providers +{ + public static class AbstractionProviderExtensions + { + public static IServiceCollection RegisterAllImplementations( + this IServiceCollection services, + Type defaultProviderType, + string defaultProviderSPALId, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + where T : ISPALProvider + { + return services = + SPALExtensions.RegisterAllImplementations(services, serviceLifetime) + .AddScoped, AbstractionProvider>(sp => + { + ISPALOrchestrationService spalOrchestrationService = sp.GetRequiredService(); + + return new AbstractionProvider( + spalOrchestrationService, + defaultProviderType: defaultProviderType, + defaultProviderSPALId: defaultProviderSPALId); + }); + } + + public static IAbstractionProvider GetAbstractionProvider( + this IAbstractionProvider abstractionProvider, + Type defaultProviderType, + string defaultProviderSPALId, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + where T : ISPALProvider + { + return new AbstractionProvider(defaultProviderType, defaultProviderSPALId, serviceLifetime); + } + + public static IAbstractionProvider GetAbstractionProvider( + this IAbstractionProvider abstractionProvider, + T provider) + where T : ISPALProvider + { + return new AbstractionProvider(provider); + } + } +} diff --git a/STX.SPAL.Providers/STX.SPAL.Providers.csproj b/STX.SPAL.Providers/STX.SPAL.Providers.csproj new file mode 100644 index 0000000..2c3fdea --- /dev/null +++ b/STX.SPAL.Providers/STX.SPAL.Providers.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + disable + disable + + + + + + + + diff --git a/STX.SPAL.Core/ISPALOrchestrationService.cs b/STX.SPAL/ISPALOrchestrationService.cs similarity index 84% rename from STX.SPAL.Core/ISPALOrchestrationService.cs rename to STX.SPAL/ISPALOrchestrationService.cs index eb54f1c..293a62d 100644 --- a/STX.SPAL.Core/ISPALOrchestrationService.cs +++ b/STX.SPAL/ISPALOrchestrationService.cs @@ -5,7 +5,7 @@ using STX.SPAL.Abstractions; using System; -namespace STX.SPAL.Core +namespace STX.SPAL { public interface ISPALOrchestrationService { @@ -13,5 +13,6 @@ public interface ISPALOrchestrationService T GetImplementation(Type concreteTypeProvider) where T : ISPALProvider; T GetImplementation(string spalId) where T : ISPALProvider; T GetImplementation(Type concreteProviderType, string spalId) where T : ISPALProvider; + T[] GetImplementations(Type concreteProviderType, string spalId) where T : ISPALProvider; } } diff --git a/STX.SPAL.Core/SPALExtensions.cs b/STX.SPAL/SPALExtensions.cs similarity index 61% rename from STX.SPAL.Core/SPALExtensions.cs rename to STX.SPAL/SPALExtensions.cs index f8bfcb1..48fbe82 100644 --- a/STX.SPAL.Core/SPALExtensions.cs +++ b/STX.SPAL/SPALExtensions.cs @@ -5,18 +5,24 @@ using Microsoft.Extensions.DependencyInjection; using STX.SPAL.Abstractions; -namespace STX.SPAL.Core +namespace STX.SPAL { public static class SPALExtensions { - public static IServiceCollection RegisterAllImplementations(IServiceCollection services) + public static IServiceCollection RegisterAllImplementations( + IServiceCollection services, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) where T : ISPALProvider { - return SPALOrchestrationService.RegisterAllImplementations(services) + return SPALOrchestrationService.RegisterAllImplementations(services, serviceLifetime) .AddScoped(sp => new SPALOrchestrationService(sp)); } - public static ISPALOrchestrationService GetSPAL(this ISPALProvider spalProvider) => - new SPALOrchestrationService(); + public static ISPALOrchestrationService GetSPAL( + this ISPALProvider spalProvider, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + { + return new SPALOrchestrationService(typeof(T), serviceLifetime); + } } } diff --git a/STX.SPAL.Core/SPALOrchestrationService.Assemblies.cs b/STX.SPAL/SPALOrchestrationService.Assemblies.cs similarity index 98% rename from STX.SPAL.Core/SPALOrchestrationService.Assemblies.cs rename to STX.SPAL/SPALOrchestrationService.Assemblies.cs index 9737461..20be0ad 100644 --- a/STX.SPAL.Core/SPALOrchestrationService.Assemblies.cs +++ b/STX.SPAL/SPALOrchestrationService.Assemblies.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Reflection; -namespace STX.SPAL.Core +namespace STX.SPAL { internal partial class SPALOrchestrationService { diff --git a/STX.SPAL.Core/SPALOrchestrationService.Exceptions.cs b/STX.SPAL/SPALOrchestrationService.Exceptions.cs similarity index 96% rename from STX.SPAL.Core/SPALOrchestrationService.Exceptions.cs rename to STX.SPAL/SPALOrchestrationService.Exceptions.cs index 40e01cb..ffd36bc 100644 --- a/STX.SPAL.Core/SPALOrchestrationService.Exceptions.cs +++ b/STX.SPAL/SPALOrchestrationService.Exceptions.cs @@ -4,7 +4,7 @@ using System; -namespace STX.SPAL.Core +namespace STX.SPAL { internal partial class SPALOrchestrationService { diff --git a/STX.SPAL/SPALOrchestrationService.Registerings.cs b/STX.SPAL/SPALOrchestrationService.Registerings.cs new file mode 100644 index 0000000..ca40f4a --- /dev/null +++ b/STX.SPAL/SPALOrchestrationService.Registerings.cs @@ -0,0 +1,57 @@ +// ---------------------------------------------------------------------------------- +// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers +// ---------------------------------------------------------------------------------- + +using Microsoft.Extensions.DependencyInjection; +using System; + +namespace STX.SPAL +{ + internal partial class SPALOrchestrationService + { + private static IServiceCollection RegisterImplementation( + IServiceCollection services, + Type spalInterfaceType, + Type implementationType, + ServiceLifetime serviceLifetime, + bool registeringMultipleProviders) + { + ValidateImplementationTypeRegistered(services, spalInterfaceType, allowMultipleProviders); + + if (registeringMultipleProviders) + { + string spalId = implementationType.Namespace; + services.Add(new ServiceDescriptor(spalInterfaceType, spalId, implementationType, serviceLifetime)); + //services.AddKeyedScoped(spalInterfaceType, spalId, implementationType); + Console.WriteLine($"Registered {implementationType.FullName} ({spalInterfaceType.Name}) with SPAL Id {spalId} with Lifetime {serviceLifetime}"); + } + else + { + services.Add(new ServiceDescriptor(spalInterfaceType, implementationType, serviceLifetime)); + //services.AddScoped(typeof(T), implementationType); + Console.WriteLine($"Registered {implementationType.FullName} ({spalInterfaceType.Name}) with Lifetime {serviceLifetime}"); + } + + return services; + } + + private static IServiceCollection RegisterImplementations( + IServiceCollection services, + Type spalInterfaceType, + ServiceLifetime serviceLifetime) + { + Type[] exportedTypesOfT = GetExportedTypesFromAssembliesPaths( + spalInterfaceType, + concreteTypeProvider: null, + spalId: null); + + foreach (var exportedTypeOfT in exportedTypesOfT) + RegisterImplementation(services, spalInterfaceType, exportedTypeOfT, serviceLifetime, exportedTypesOfT.Length > 1); + + Console.WriteLine($"Register Done!."); + + return services; + + } + } +} diff --git a/STX.SPAL.Core/SPALOrchestrationService.Resolvers.cs b/STX.SPAL/SPALOrchestrationService.Resolvers.cs similarity index 71% rename from STX.SPAL.Core/SPALOrchestrationService.Resolvers.cs rename to STX.SPAL/SPALOrchestrationService.Resolvers.cs index 95e7205..79e8a5b 100644 --- a/STX.SPAL.Core/SPALOrchestrationService.Resolvers.cs +++ b/STX.SPAL/SPALOrchestrationService.Resolvers.cs @@ -7,11 +7,11 @@ using System; using System.Linq; -namespace STX.SPAL.Core +namespace STX.SPAL { internal partial class SPALOrchestrationService { - private T ResolveImplementationWithDI(Type concreteProviderType, string spalId) + private T ResolveImplementation(Type concreteProviderType, string spalId) where T : ISPALProvider { if (serviceProvider == null) @@ -49,29 +49,17 @@ private T ResolveImplementationWithDI(Type concreteProviderType, string spalI implementation = serviceProvider.GetService(); } - return implementation; - } - - private T ResolveImplementationWithoutDI(Type concreteProviderType, string spalId) - where T : ISPALProvider - { - Type[] exportedTypesOfT = GetExportedTypesFromAssembliesPaths(concreteProviderType, spalId); - ValidateExportedTypes(exportedTypesOfT); + ValidateInstance(implementation, concreteProviderType, spalId); - return (T)Activator.CreateInstance(exportedTypesOfT.Single()); + return implementation; } - private T ResolveImplementation(Type concreteProviderType, string spalId) + private T[] ResolveImplementations(Type concreteProviderType, string spalId) where T : ISPALProvider { - T instance = - serviceProvider != null - ? ResolveImplementationWithDI(concreteProviderType, spalId) - : ResolveImplementationWithoutDI(concreteProviderType, spalId); - - ValidateInstance(instance, concreteProviderType, spalId); - - return instance; + // TODO - We need a way to get all the services registered. This method implemented doesn´t return anything because dependending + // on how the registering was done maybe it used a keyService. + return serviceProvider.GetServices().ToArray(); } } } diff --git a/STX.SPAL.Core/SPALOrchestrationService.Types.cs b/STX.SPAL/SPALOrchestrationService.Types.cs similarity index 64% rename from STX.SPAL.Core/SPALOrchestrationService.Types.cs rename to STX.SPAL/SPALOrchestrationService.Types.cs index d364d61..aabef87 100644 --- a/STX.SPAL.Core/SPALOrchestrationService.Types.cs +++ b/STX.SPAL/SPALOrchestrationService.Types.cs @@ -2,43 +2,42 @@ // Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers // ---------------------------------------------------------------------------------- -using STX.SPAL.Abstractions; using System; using System.Linq; using System.Reflection; -namespace STX.SPAL.Core +namespace STX.SPAL { internal partial class SPALOrchestrationService { - private static Type[] GetInterfaceImplementations( + private static Type[] GetInterfaceImplementations( Assembly assembly, - Type concreteTypeProvider, + Type spalInterfaceType, + Type concreteProviderType, string spalId) - where T : ISPALProvider { - Type spalInterfaceType = typeof(T); + ValidateSPALInterfaceType(spalInterfaceType); Type[] implementations = assembly .GetExportedTypes() .Where(exportedType => - exportedType.GetInterfaces() + exportedType + .GetInterfaces() .Any(interfaceType => - //@interface is T interfaceType.Assembly.FullName == spalInterfaceType.Assembly.FullName && interfaceType.FullName == spalInterfaceType.FullName)) .Where(exportedType => - (concreteTypeProvider == null + (concreteProviderType == null && string.IsNullOrEmpty(spalId)) - || (concreteTypeProvider == null + || (concreteProviderType == null && !string.IsNullOrEmpty(spalId) && exportedType.Namespace == spalId) - || (concreteTypeProvider != null - && concreteTypeProvider.FullName == exportedType.FullName + || (concreteProviderType != null + && concreteProviderType.FullName == exportedType.FullName && string.IsNullOrEmpty(spalId)) - || (concreteTypeProvider != null - && concreteTypeProvider.FullName == exportedType.FullName + || (concreteProviderType != null + && concreteProviderType.FullName == exportedType.FullName && !string.IsNullOrEmpty(spalId) && exportedType.Namespace == spalId)) .ToArray(); @@ -46,25 +45,24 @@ private static Type[] GetInterfaceImplementations( return implementations; } - private static Type[] GetExportedTypesFromAssemblyPath( + private static Type[] GetExportedTypesFromAssemblyPath( string assemblyPath, + Type spalInterfaceType, Type concreteTypeProvider, string spalId) - where T : ISPALProvider { Assembly applicationAssembly = Assembly.LoadFrom(assemblyPath); - return GetInterfaceImplementations(applicationAssembly, concreteTypeProvider, spalId); + return GetInterfaceImplementations(applicationAssembly, spalInterfaceType, concreteTypeProvider, spalId); } - private static Type[] GetExportedTypesFromAssembliesPaths(Type concreteTypeProvider, string spalId) - where T : ISPALProvider + private static Type[] GetExportedTypesFromAssembliesPaths(Type spalInterfaceType, Type concreteTypeProvider, string spalId) { string[] applicationAssembliesPaths = GetApplicationAssemblies(); Type[] exportedTypesOfT = applicationAssembliesPaths .SelectMany(applicationAssemblyPath => - GetExportedTypesFromAssemblyPath(applicationAssemblyPath, concreteTypeProvider, spalId)) + GetExportedTypesFromAssemblyPath(applicationAssemblyPath, spalInterfaceType, concreteTypeProvider, spalId)) .ToArray(); return exportedTypesOfT; diff --git a/STX.SPAL.Core/SPALOrchestrationService.Validations.cs b/STX.SPAL/SPALOrchestrationService.Validations.cs similarity index 78% rename from STX.SPAL.Core/SPALOrchestrationService.Validations.cs rename to STX.SPAL/SPALOrchestrationService.Validations.cs index 9fd201e..5d6c42f 100644 --- a/STX.SPAL.Core/SPALOrchestrationService.Validations.cs +++ b/STX.SPAL/SPALOrchestrationService.Validations.cs @@ -7,15 +7,24 @@ using System; using System.Linq; -namespace STX.SPAL.Core +namespace STX.SPAL { internal partial class SPALOrchestrationService { - private static void ValidateImplementationTypeRegistered(IServiceCollection services, bool allowMultipleTypes) + private static void ValidateSPALInterfaceType(Type spalInterfaceType) + { + if (spalInterfaceType == null) + throw new Exception("SPAL Interface can not be null."); + + if (!spalInterfaceType.GetInterfaces().Any(@interface => @interface == typeof(ISPALProvider))) + throw new Exception("SPAL Interface can not be null."); + } + + private static void ValidateImplementationTypeRegistered(IServiceCollection services, Type spalInterfaceType, bool allowMultipleTypes) { if (!allowMultipleTypes - && services.Any(serviceDescriptor => serviceDescriptor.ServiceType == typeof(T))) - throw new Exception($"More than one implementation registered for {typeof(T).Name}. Please specify one of them, disallow multiple types or use keys for specifing multiple implementations for the same interface."); + && services.Any(serviceDescriptor => serviceDescriptor.ServiceType == spalInterfaceType)) + throw new Exception($"More than one implementation registered for {spalInterfaceType.Name}. Please specify one of them, disallow multiple types or use keys for specifing multiple implementations for the same interface."); } private static void ValidateExportedTypes(Type[] exportedTypesOfT) @@ -44,19 +53,19 @@ private static void ValidateInstance(T instance, Type concreteProviderType, s { if (string.IsNullOrEmpty(spalId) && concreteProviderType == null) - throw new Exception($"There is no dependency to resolve {typeof(T).Name}. Please add a package with one implementation or maybe SPAL detected more than one implementations."); + throw new Exception($"There is no dependency to resolve {typeof(T).Name}. Please add a package with one implementation or maybe SPAL detected more than one implementation."); else if (!string.IsNullOrEmpty(spalId) && concreteProviderType == null) - throw new Exception($"There is no dependency to resolve {typeof(T).Name} for concrete provider spal Id {spalId}. Please add a package with one implementation or maybe SPAL detected more than one implementations."); + throw new Exception($"There is no dependency to resolve {typeof(T).Name} for concrete provider spal Id {spalId}. Please add a package with one implementation or maybe SPAL detected more than one implementation."); else if (string.IsNullOrEmpty(spalId) && concreteProviderType != null) - throw new Exception($"There is no dependency to resolve {typeof(T).Name} for concrete provider type {concreteProviderType.FullName}. Please add a package with one implementation or maybe SPAL detected more than one implementations."); + throw new Exception($"There is no dependency to resolve {typeof(T).Name} for concrete provider type {concreteProviderType.FullName}. Please add a package with one implementation or maybe SPAL detected more than one implementation."); else if (!string.IsNullOrEmpty(spalId) && concreteProviderType != null) - throw new Exception($"There is no dependency to resolve {typeof(T).Name} for concrete provider type {concreteProviderType.FullName} with spal Id {spalId}. Please add a package with one implementation or maybe SPAL detected more than one implementations."); + throw new Exception($"There is no dependency to resolve {typeof(T).Name} for concrete provider type {concreteProviderType.FullName} with spal Id {spalId}. Please add a package with one implementation or maybe SPAL detected more than one implementation."); } else diff --git a/STX.SPAL.Core/SPALOrchestrationService.cs b/STX.SPAL/SPALOrchestrationService.cs similarity index 67% rename from STX.SPAL.Core/SPALOrchestrationService.cs rename to STX.SPAL/SPALOrchestrationService.cs index 142abb9..5027174 100644 --- a/STX.SPAL.Core/SPALOrchestrationService.cs +++ b/STX.SPAL/SPALOrchestrationService.cs @@ -6,7 +6,7 @@ using STX.SPAL.Abstractions; using System; -namespace STX.SPAL.Core +namespace STX.SPAL { internal partial class SPALOrchestrationService : ISPALOrchestrationService { @@ -15,20 +15,22 @@ internal partial class SPALOrchestrationService : ISPALOrchestrationService private readonly IServiceProvider serviceProvider; private static readonly bool allowMultipleProviders = true; - public SPALOrchestrationService() + public SPALOrchestrationService(Type spalInterfaceType, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) { + IServiceCollection services = new ServiceCollection(); + RegisterImplementations(services, spalInterfaceType, serviceLifetime); + this.serviceProvider = services.BuildServiceProvider(); } public SPALOrchestrationService(IServiceProvider serviceProvider) => this.serviceProvider = serviceProvider; - public static IServiceCollection RegisterAllImplementations(IServiceCollection services) + + public static IServiceCollection RegisterAllImplementations(IServiceCollection services, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) where T : ISPALProvider { - Type[] exportedTypesOfT = GetExportedTypesFromAssembliesPaths(concreteTypeProvider: null, spalId: null); - RegisterImplementations(services, exportedTypesOfT); - Console.WriteLine($"Register Done!."); - + Type spalInterfaceType = typeof(T); + RegisterImplementations(services, spalInterfaceType, serviceLifetime); return services; } @@ -47,5 +49,9 @@ public T GetImplementation(string spalId) where T : ISPALProvider => public T GetImplementation(Type concreteProviderType, string spalId) where T : ISPALProvider => TryCatch(() => ResolveImplementation(concreteProviderType: concreteProviderType, spalId: spalId)); + + public T[] GetImplementations(Type concreteProviderType, string spalId) where T : ISPALProvider => + TryCatch(() => + ResolveImplementations(concreteProviderType: concreteProviderType, spalId: spalId)); } } diff --git a/STX.SPAL.Core/STX.SPAL.Core.csproj b/STX.SPAL/STX.SPAL.csproj similarity index 83% rename from STX.SPAL.Core/STX.SPAL.Core.csproj rename to STX.SPAL/STX.SPAL.csproj index 01e48a1..b17733a 100644 --- a/STX.SPAL.Core/STX.SPAL.Core.csproj +++ b/STX.SPAL/STX.SPAL.csproj @@ -7,6 +7,7 @@ + diff --git a/STX.Serialization.POC.NoProvidersReferenced/Program.Tests.cs b/STX.Serialization.POC.NoProvidersReferenced/Program.Tests.cs index 2ba4fb1..0f9359c 100644 --- a/STX.Serialization.POC.NoProvidersReferenced/Program.Tests.cs +++ b/STX.Serialization.POC.NoProvidersReferenced/Program.Tests.cs @@ -48,7 +48,7 @@ private static void CallProviderWithoutDIMultipleProvidersSwitching() Console.WriteLine(serializationAbstractionProvider.GetName()); - serializationAbstractionProvider.UseSerializationProvider(SYSTEMTEXT_SPAL_ID); + serializationAbstractionProvider.UseProvider(SYSTEMTEXT_SPAL_ID); Console.WriteLine(serializationAbstractionProvider.GetName()); }); } @@ -109,7 +109,7 @@ private static void CallProviderWithDIMultipleProvidersSwitching() Console.WriteLine(serializationAbstractionProvider.GetName()); - serializationAbstractionProvider.UseSerializationProvider(spalId: SYSTEMTEXT_SPAL_ID); + serializationAbstractionProvider.UseProvider(spalId: SYSTEMTEXT_SPAL_ID); Console.WriteLine(serializationAbstractionProvider.GetName()); }); } diff --git a/STX.Serialization.POC/Program.Tests.cs b/STX.Serialization.POC/Program.Tests.cs index 0535780..8b6ca96 100644 --- a/STX.Serialization.POC/Program.Tests.cs +++ b/STX.Serialization.POC/Program.Tests.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using STX.Serialization.Providers; using STX.Serialization.Providers.Abstractions; +using STX.SPAL.Abstractions; using System; using ProviderNewtonsoft = STX.Serialization.Providers.NewtonsoftJson; using ProviderSystemTextJson = STX.Serialization.Providers.SystemTextJson; @@ -46,11 +47,19 @@ private static void CallProviderWithoutDIMultipleProvidersSwitching() Console.WriteLine(serializationAbstractionProvider.GetName()); - serializationAbstractionProvider.UseSerializationProvider(); + serializationAbstractionProvider.UseProvider(); Console.WriteLine(serializationAbstractionProvider.GetName()); }); } + private static void CallMultipleProvidersWithoutDIMultipleProviders() => + TryCatch(() => + { + ISerializationAbstractionProvider serializationAbstractionProvider = null; + serializationAbstractionProvider = serializationAbstractionProvider.GetSerializationAbstractionProvider(); + serializationAbstractionProvider.InvokeWithProvider(provider => Console.WriteLine(provider.GetName())); + }); + private static void CallProviderWithDISingleProvider() { TryCatch(() => @@ -106,9 +115,28 @@ private static void CallProviderWithDIMultipleProvidersSwitching() Console.WriteLine(serializationAbstractionProvider.GetName()); - serializationAbstractionProvider.UseSerializationProvider(); + serializationAbstractionProvider.UseProvider(); Console.WriteLine(serializationAbstractionProvider.GetName()); }); } + + private static void CallMultipleProvidersWithDIMultipleProviders() + { + TryCatch(() => + { + IServiceCollection services = new ServiceCollection(); + services + .RegisterSerializationProviders(defaultProviderType: typeof(ProviderNewtonsoft.SerializationProvider)); + + IServiceProvider serviceProvider = services.BuildServiceProvider(); + using IServiceScope scope = serviceProvider.CreateScope(); + + ISerializationAbstractionProvider serializationAbstractionProvider = + scope.ServiceProvider + .GetRequiredService(); + + serializationAbstractionProvider.InvokeWithProvider(provider => Console.WriteLine(provider.GetName())); + }); + } } } diff --git a/STX.Serialization.POC/Program.cs b/STX.Serialization.POC/Program.cs index ed1883d..a162201 100644 --- a/STX.Serialization.POC/Program.cs +++ b/STX.Serialization.POC/Program.cs @@ -11,10 +11,12 @@ static void Main(string[] args) CallProviderWithoutDISingleProvider(); CallProviderWithoutDIMultipleProviders(); CallProviderWithoutDIMultipleProvidersSwitching(); + CallMultipleProvidersWithoutDIMultipleProviders(); CallProviderWithDISingleProvider(); CallProviderWithDIMultipleProviders(); CallProviderWithDIMultipleProvidersSwitching(); + CallMultipleProvidersWithDIMultipleProviders(); } } } diff --git a/STX.Serialization.Providers.Abstractions.sln b/STX.Serialization.Providers.Abstractions.sln index cb3306a..6f6f7b0 100644 --- a/STX.Serialization.Providers.Abstractions.sln +++ b/STX.Serialization.Providers.Abstractions.sln @@ -9,7 +9,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STX.Serialization.Providers EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STX.Serialization.Providers.Abstractions.Tests.Acceptance", "STX.Serialization.Providers.Abstractions.Tests.Acceptance\STX.Serialization.Providers.Abstractions.Tests.Acceptance.csproj", "{A3E3CBE6-74E2-4196-94E1-F4238C36639E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STX.SPAL.Core", "STX.SPAL.Core\STX.SPAL.Core.csproj", "{9B7FD3F7-B60C-446E-9934-D55C2FFFE8C7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STX.SPAL", "STX.SPAL\STX.SPAL.csproj", "{9B7FD3F7-B60C-446E-9934-D55C2FFFE8C7}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STX.SPAL.Abstractions", "STX.SPAL.Abstractions\STX.SPAL.Abstractions.csproj", "{4D5CC8C1-688F-41A6-B866-57AD16FEFFA0}" EndProject @@ -26,7 +26,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STX.Serialization.POC.NoProvidersReferenced", "STX.Serialization.POC.NoProvidersReferenced\STX.Serialization.POC.NoProvidersReferenced.csproj", "{34AA149C-4375-48FF-AF2C-3BCFFC58093F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STX.Serialization.POC.NoProvidersReferenced", "STX.Serialization.POC.NoProvidersReferenced\STX.Serialization.POC.NoProvidersReferenced.csproj", "{34AA149C-4375-48FF-AF2C-3BCFFC58093F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SPAL", "SPAL", "{C5606FCE-7EF0-4DF3-9562-6B77E5709C6C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "POC", "POC", "{D9AC34D2-C122-4E3D-9473-D071D8FD005A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Serialization", "Serialization", "{385A6E54-D939-4326-B52E-4AE0AECFC286}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AbstractionProvider", "AbstractionProvider", "{5087AA37-1324-4610-B05A-4E46FA9C0F07}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STX.SPAL.Providers", "STX.SPAL.Providers\STX.SPAL.Providers.csproj", "{72C8258C-8591-4A66-8062-30F4FE7DF2C9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "STX.SPAL.Providers.Abstractions", "STX.SPAL.Providers.Abstractions\STX.SPAL.Providers.Abstractions.csproj", "{811A4EDD-F4AA-457E-8A02-EBE884920CA2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -74,10 +86,30 @@ Global {34AA149C-4375-48FF-AF2C-3BCFFC58093F}.Debug|Any CPU.Build.0 = Debug|Any CPU {34AA149C-4375-48FF-AF2C-3BCFFC58093F}.Release|Any CPU.ActiveCfg = Release|Any CPU {34AA149C-4375-48FF-AF2C-3BCFFC58093F}.Release|Any CPU.Build.0 = Release|Any CPU + {72C8258C-8591-4A66-8062-30F4FE7DF2C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72C8258C-8591-4A66-8062-30F4FE7DF2C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72C8258C-8591-4A66-8062-30F4FE7DF2C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72C8258C-8591-4A66-8062-30F4FE7DF2C9}.Release|Any CPU.Build.0 = Release|Any CPU + {811A4EDD-F4AA-457E-8A02-EBE884920CA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {811A4EDD-F4AA-457E-8A02-EBE884920CA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {811A4EDD-F4AA-457E-8A02-EBE884920CA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {811A4EDD-F4AA-457E-8A02-EBE884920CA2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {38A8052D-3C6E-44DC-ACEB-AA28881C5CD5} = {385A6E54-D939-4326-B52E-4AE0AECFC286} + {9B7FD3F7-B60C-446E-9934-D55C2FFFE8C7} = {C5606FCE-7EF0-4DF3-9562-6B77E5709C6C} + {4D5CC8C1-688F-41A6-B866-57AD16FEFFA0} = {C5606FCE-7EF0-4DF3-9562-6B77E5709C6C} + {A0DE0DD1-7975-47A4-AC20-F95BCC4D8901} = {385A6E54-D939-4326-B52E-4AE0AECFC286} + {9DC355E4-5391-4572-B4D0-26684F00F737} = {385A6E54-D939-4326-B52E-4AE0AECFC286} + {4ADB3A3D-FF90-4531-AA33-446A67DF2471} = {D9AC34D2-C122-4E3D-9473-D071D8FD005A} + {3D7D063A-DE1B-416A-A1B8-40B523B8918C} = {385A6E54-D939-4326-B52E-4AE0AECFC286} + {34AA149C-4375-48FF-AF2C-3BCFFC58093F} = {D9AC34D2-C122-4E3D-9473-D071D8FD005A} + {72C8258C-8591-4A66-8062-30F4FE7DF2C9} = {C5606FCE-7EF0-4DF3-9562-6B77E5709C6C} + {811A4EDD-F4AA-457E-8A02-EBE884920CA2} = {C5606FCE-7EF0-4DF3-9562-6B77E5709C6C} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {166720F6-D37C-46CD-8C41-B137710AC307} EndGlobalSection diff --git a/STX.Serialization.Providers.Abstractions/ISerializationAbstractionProvider.cs b/STX.Serialization.Providers.Abstractions/ISerializationAbstractionProvider.cs index d5df8c7..ca3e21f 100644 --- a/STX.Serialization.Providers.Abstractions/ISerializationAbstractionProvider.cs +++ b/STX.Serialization.Providers.Abstractions/ISerializationAbstractionProvider.cs @@ -2,11 +2,11 @@ // Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers // ---------------------------------------------------------------------------------- +using STX.SPAL.Providers.Abstractions; + namespace STX.Serialization.Providers.Abstractions { - public interface ISerializationAbstractionProvider : ISerializationOperations + public interface ISerializationAbstractionProvider : IAbstractionProvider, ISerializationOperations { - void UseSerializationProvider(string spalId = null) where T : ISerializationProvider; - void UseSerializationProvider(string spalId); } } diff --git a/STX.Serialization.Providers.Abstractions/STX.Serialization.Providers.Abstractions.csproj b/STX.Serialization.Providers.Abstractions/STX.Serialization.Providers.Abstractions.csproj index c3ec483..b28099f 100644 --- a/STX.Serialization.Providers.Abstractions/STX.Serialization.Providers.Abstractions.csproj +++ b/STX.Serialization.Providers.Abstractions/STX.Serialization.Providers.Abstractions.csproj @@ -46,6 +46,7 @@ + diff --git a/STX.Serialization.Providers/STX.Serialization.Providers.csproj b/STX.Serialization.Providers/STX.Serialization.Providers.csproj index 2ce2485..13547ed 100644 --- a/STX.Serialization.Providers/STX.Serialization.Providers.csproj +++ b/STX.Serialization.Providers/STX.Serialization.Providers.csproj @@ -8,7 +8,7 @@ - + diff --git a/STX.Serialization.Providers/SerializationAbstractionProvider.Validations.cs b/STX.Serialization.Providers/SerializationAbstractionProvider.Validations.cs index 7fb7f62..3cdacd6 100644 --- a/STX.Serialization.Providers/SerializationAbstractionProvider.Validations.cs +++ b/STX.Serialization.Providers/SerializationAbstractionProvider.Validations.cs @@ -3,13 +3,14 @@ // ---------------------------------------------------------------------------------- using STX.Serialization.Providers.Abstractions; +using STX.SPAL.Providers.Abstractions; using System; namespace STX.Serialization.Providers { internal partial class SerializationAbstractionProvider { - private static void ValidateSerializationProvider(ISerializationProvider serializationProvider) + private static void ValidateSerializationProvider(IAbstractionProvider serializationProvider) { if (serializationProvider == null) throw new Exception("There is no serialization provider initialized."); diff --git a/STX.Serialization.Providers/SerializationAbstractionProvider.cs b/STX.Serialization.Providers/SerializationAbstractionProvider.cs index b28d490..122e0cf 100644 --- a/STX.Serialization.Providers/SerializationAbstractionProvider.cs +++ b/STX.Serialization.Providers/SerializationAbstractionProvider.cs @@ -2,8 +2,10 @@ // Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers // ---------------------------------------------------------------------------------- +using Microsoft.Extensions.DependencyInjection; using STX.Serialization.Providers.Abstractions; -using STX.SPAL.Core; +using STX.SPAL.Providers; +using STX.SPAL.Providers.Abstractions; using System; using System.Threading.Tasks; @@ -11,115 +13,115 @@ namespace STX.Serialization.Providers { internal partial class SerializationAbstractionProvider : ISerializationAbstractionProvider { - private readonly ISPALOrchestrationService spalOrchestrationService; - private readonly ISerializationProvider defaultSerializationProvider; - private ISerializationProvider serializationProvider; + private readonly IAbstractionProvider abstractionProvider; - public SerializationAbstractionProvider() + public SerializationAbstractionProvider(ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + : this(defaultProviderType: null, + defaultProviderSPALId: null, + serviceLifetime) { - this.spalOrchestrationService = defaultSerializationProvider.GetSPAL(); - this.defaultSerializationProvider = this.serializationProvider = - GetSerializationProvider(serializationProviderType: null, spalId: null); } - public SerializationAbstractionProvider(Type defaultProviderType) + public SerializationAbstractionProvider(Type defaultProviderType, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + : this(defaultProviderType: defaultProviderType, + defaultProviderSPALId: null, + serviceLifetime) { - this.spalOrchestrationService = defaultSerializationProvider.GetSPAL(); - this.defaultSerializationProvider = this.serializationProvider = - GetSerializationProvider( - serializationProviderType: defaultProviderType, - spalId: null); } - public SerializationAbstractionProvider(string defaultProviderSPALId) + public SerializationAbstractionProvider(string defaultProviderSPALId, ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) + : this(defaultProviderType: null, + defaultProviderSPALId: defaultProviderSPALId, + serviceLifetime) { - this.spalOrchestrationService = defaultSerializationProvider.GetSPAL(); - this.defaultSerializationProvider = this.serializationProvider = - GetSerializationProvider( - serializationProviderType: null, - spalId: defaultProviderSPALId); } - public SerializationAbstractionProvider(Type defaultProviderType, string defaultProviderSPALId) + public SerializationAbstractionProvider( + Type defaultProviderType, + string defaultProviderSPALId, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) { - this.spalOrchestrationService = defaultSerializationProvider.GetSPAL(); - this.defaultSerializationProvider = this.serializationProvider = - GetSerializationProvider( - serializationProviderType: defaultProviderType, - spalId: defaultProviderSPALId); + this.abstractionProvider = abstractionProvider.GetAbstractionProvider(defaultProviderType, defaultProviderSPALId, serviceLifetime); } public SerializationAbstractionProvider(ISerializationProvider serializationProvider) { - this.defaultSerializationProvider = this.serializationProvider = serializationProvider; + this.abstractionProvider = abstractionProvider.GetAbstractionProvider(serializationProvider); } public SerializationAbstractionProvider( - ISPALOrchestrationService spalOrchestrationService, - Type defaultProviderType = null, - string defaultProviderSPALId = null) + IAbstractionProvider abstractionProvider, + Type defaultProviderType, + string defaultProviderSPALId) { - this.spalOrchestrationService = spalOrchestrationService; - this.defaultSerializationProvider = this.serializationProvider = - this.GetSerializationProvider( - serializationProviderType: defaultProviderType, - spalId: defaultProviderSPALId); + this.abstractionProvider = abstractionProvider; + abstractionProvider.UseProvider(defaultProviderType, defaultProviderSPALId); } - private ISerializationProvider GetSerializationProvider(Type serializationProviderType, string spalId) + public void UseProvider(string spalId = null) { - ISerializationProvider serializationProvider = null; - - if (serializationProviderType == null - && string.IsNullOrEmpty(spalId)) - { - if (defaultSerializationProvider != null) - serializationProvider = defaultSerializationProvider; - else - serializationProvider = spalOrchestrationService.GetImplementation(); - } - else - serializationProvider = spalOrchestrationService.GetImplementation(serializationProviderType, spalId); - - return serializationProvider; + this.abstractionProvider.UseProvider(spalId: spalId); } - public void UseSerializationProvider(string spalId = null) - where T : ISerializationProvider + public void UseProvider(Type concreteProviderType = null, string spalId = null) { - serializationProvider = - GetSerializationProvider( - serializationProviderType: typeof(T), - spalId: spalId); + throw new NotImplementedException(); } - public void UseSerializationProvider(string spalId) + public void UseProvider(string spalId = null) where TConcreteProviderType : ISerializationProvider { - serializationProvider = - GetSerializationProvider( - serializationProviderType: null, - spalId: spalId); + this.abstractionProvider.UseProvider(spalId); } public string GetName() { - ValidateSerializationProvider(this.serializationProvider); + ValidateSerializationProvider(this.abstractionProvider); - return this.serializationProvider.GetName(); + return this.abstractionProvider.GetProvider().GetName(); } public ValueTask Deserialize(string content) { - ValidateSerializationProvider(this.serializationProvider); + ValidateSerializationProvider(this.abstractionProvider); - return this.serializationProvider.Deserialize(content); + return this.abstractionProvider.GetProvider().Deserialize(content); } public ValueTask Serialize(T @object) { - ValidateSerializationProvider(this.serializationProvider); + ValidateSerializationProvider(this.abstractionProvider); + + return this.abstractionProvider.GetProvider().Serialize(@object); + } + + public void InvokeWithProvider(Action providerFunction) where TConcreteProviderType : ISerializationProvider + { + this.abstractionProvider.InvokeWithProvider(providerFunction); + } + + public ISerializationProvider GetProvider() + { + throw new NotImplementedException(); + } - return this.serializationProvider.Serialize(@object); + public void Invoke(Action spalFunction) + { + throw new NotImplementedException(); + } + + public TResult Invoke(Func spalFunction) + { + throw new NotImplementedException(); + } + + public ValueTask InvokeAsync(Func spalFunction) + { + throw new NotImplementedException(); + } + + public ValueTask InvokeAsync(Func> spalFunction) + { + throw new NotImplementedException(); } } } diff --git a/STX.Serialization.Providers/SerializationAbstractionProviderExtensions.cs b/STX.Serialization.Providers/SerializationAbstractionProviderExtensions.cs index a6dcae8..411ba77 100644 --- a/STX.Serialization.Providers/SerializationAbstractionProviderExtensions.cs +++ b/STX.Serialization.Providers/SerializationAbstractionProviderExtensions.cs @@ -4,7 +4,8 @@ using Microsoft.Extensions.DependencyInjection; using STX.Serialization.Providers.Abstractions; -using STX.SPAL.Core; +using STX.SPAL.Providers; +using STX.SPAL.Providers.Abstractions; using System; namespace STX.Serialization.Providers @@ -14,36 +15,39 @@ public static class SerializationAbstractionProviderExtensions public static IServiceCollection RegisterSerializationProviders( this IServiceCollection services, Type defaultProviderType = null, - string defaultProviderSPALId = null) + string defaultProviderSPALId = null, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) { - services = SPALExtensions.RegisterAllImplementations(services); - return services + .RegisterAllImplementations(defaultProviderType, defaultProviderSPALId, serviceLifetime) .AddScoped(sp => { - ISPALOrchestrationService spalOrchestrationService = sp.GetRequiredService(); - return new SerializationAbstractionProvider(spalOrchestrationService, defaultProviderType, defaultProviderSPALId); + IAbstractionProvider abstractionProvider = sp.GetRequiredService>(); + return new SerializationAbstractionProvider(abstractionProvider, defaultProviderType, defaultProviderSPALId); }); } public static ISerializationAbstractionProvider GetSerializationAbstractionProvider( - this ISerializationAbstractionProvider serializationAbstractionProvider) + this ISerializationAbstractionProvider serializationAbstractionProvider, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) { - return new SerializationAbstractionProvider(); + return new SerializationAbstractionProvider(serviceLifetime); } public static ISerializationAbstractionProvider GetSerializationAbstractionProvider( - this ISerializationAbstractionProvider serializationAbstractionProvider) + this ISerializationAbstractionProvider serializationAbstractionProvider, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) where T : ISerializationProvider { - return new SerializationAbstractionProvider(defaultProviderType: typeof(T)); + return new SerializationAbstractionProvider(defaultProviderType: typeof(T), serviceLifetime); } public static ISerializationAbstractionProvider GetSerializationAbstractionProvider( this ISerializationAbstractionProvider serializationAbstractionProvider, - string defaultProviderSPALId) + string defaultProviderSPALId, + ServiceLifetime serviceLifetime = ServiceLifetime.Scoped) { - return new SerializationAbstractionProvider(defaultProviderSPALId); + return new SerializationAbstractionProvider(defaultProviderSPALId, serviceLifetime); } } }