diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..bd36349 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,143 @@ +# To learn more about .editorconfig see https://aka.ms/editorconfigdocs +############################### +# Core EditorConfig Options # +############################### +# All files +[*] +indent_style =tab +# Code files +[*.{cs,csx,vb,vbx}] +#indent_size = 2 +insert_final_newline = true +charset = utf-8-bom +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = true +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true:suggestion +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +# Instance fields are camelCase and start with _ +dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields +dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style + +dotnet_naming_symbols.instance_fields.applicable_kinds = field + +dotnet_naming_style.instance_field_style.capitalization = camel_case +dotnet_naming_style.instance_field_style.required_prefix = _ +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 2 +indent_size = 2 +end_of_line = crlf +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +############################### +# C# Coding Conventions # +############################### +[*.cs] +# var preferences +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent +# Expression-bodied members +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +# Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +# Namespaces +csharp_style_namespace_declarations = file_scoped:warning +############################### +# C# Formatting Rules # +############################### +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +############################### +# VB Coding Conventions # +############################### +[*.vb] +# Modifier preferences +visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..705065f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,25 @@ +name: .NET Core + +on: + push: + branches: + - main + paths: + - 'src/DynamicDiToolkit/**' + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET Core + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '7.x' + - name: Install dependencies + run: dotnet restore + - name: Build + run: dotnet build --configuration Release --no-restore + \ No newline at end of file diff --git a/.github/workflows/nuget-publish.yml b/.github/workflows/nuget-publish.yml new file mode 100644 index 0000000..03a193d --- /dev/null +++ b/.github/workflows/nuget-publish.yml @@ -0,0 +1,34 @@ +name: Publish DynamicDiToolkit to NuGet + +on: + push: + branches: + - main # Your default release branch + paths: + - 'src/DynamicDiToolkit/**' + +jobs: + publish: + name: Build and Publish + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + + # Required for a specific dotnet version that doesn't come with ubuntu-latest / windows-latest + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '7.0.x' + + # Restore + - name: Dotnet restore + run: dotnet restore src/DynamicDiToolkit/DynamicDiToolkit.csproj + + # Publish + - name: Create the package + run: dotnet pack -c Release -o . src/DynamicDiToolkit/DynamicDiToolkit.csproj + + - name: Publish to nuget.org + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + run: nuget push DynamicDiToolkit.*.nupkg -src https://api.nuget.org/v3/index.json ${{secrets.NUGET_API_KEY}} diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..865dfcc --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,62 @@ + + + true + true + + + + + + + + runtime; build; native; contentfiles; analyzers + all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + \ No newline at end of file diff --git a/DynamicDiToolkit.nuspec b/DynamicDiToolkit.nuspec new file mode 100644 index 0000000..2aff669 --- /dev/null +++ b/DynamicDiToolkit.nuspec @@ -0,0 +1,33 @@ + + + + DynamicDiToolkit + Dynamic DI Toolkit + 1.0.0 + ShadyNagy + + Dynamic DI Toolkit Package + + + + + + + + + en-US + MIT + https://github.com/ShadyNagy/DynamicDiToolkit + + DynamicDiToolkit Package. + DynamicDiToolkit, DI, Ardalis Specification, dependency injection, service, services + icon.png + Copyright 2024 (c) ShadyNagy. All rights reserved. + README.md + + + + + + + \ No newline at end of file diff --git a/DynamicDiToolkit.sln b/DynamicDiToolkit.sln new file mode 100644 index 0000000..6b777df --- /dev/null +++ b/DynamicDiToolkit.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33815.320 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1A59296A-18CF-4272-A9CB-04CCCD18F460}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C1B38C9A-65EC-42E7-90A9-5B6EA55C6B4A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FCF0E238-EED0-482A-9ACC-650693578B59}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitignore = .gitignore + .github\workflows\build.yml = .github\workflows\build.yml + Directory.Packages.props = Directory.Packages.props + DynamicDiToolkit.nuspec = DynamicDiToolkit.nuspec + .github\workflows\nuget-publish.yml = .github\workflows\nuget-publish.yml + README.md = README.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamicDiToolkit", "src\DynamicDiToolkit\DynamicDiToolkit.csproj", "{072876FE-DDD8-43EB-8FD4-C11B840DB63F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {072876FE-DDD8-43EB-8FD4-C11B840DB63F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {072876FE-DDD8-43EB-8FD4-C11B840DB63F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {072876FE-DDD8-43EB-8FD4-C11B840DB63F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {072876FE-DDD8-43EB-8FD4-C11B840DB63F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {072876FE-DDD8-43EB-8FD4-C11B840DB63F} = {1A59296A-18CF-4272-A9CB-04CCCD18F460} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8F8D7AF9-01CD-4A86-88AF-2770F7FBC902} + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md index 658a5bc..7772336 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ -# DynamicDiToolkit \ No newline at end of file +[![publish to nuget](https://github.com/ShadyNagy/DynamicDiToolkit/actions/workflows/nuget-publish.yml/badge.svg)](https://github.com/ShadyNagy/DynamicDiToolkit/actions/workflows/nuget-publish.yml) +[![DynamicDiToolkit on NuGet](https://img.shields.io/nuget/v/DynamicDiToolkit?label=DynamicDiToolkit)](https://www.nuget.org/packages/DynamicDiToolkit/) +[![NuGet](https://img.shields.io/nuget/dt/DynamicDiToolkit)](https://www.nuget.org/packages/DynamicDiToolkit) +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/ShadyNagy/DynamicDiToolkit/blob/main/LICENSE) +[![paypal](https://img.shields.io/badge/PayPal-tip%20me-green.svg?logo=paypal)](https://www.paypal.me/shadynagy) +[![Visit My Website](https://img.shields.io/badge/Visit-My%20Website-blue?logo=internetexplorer)](https://ShadyNagy.com) + + +# Dynamic DI Toolkit + diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..0bc843f Binary files /dev/null and b/icon.png differ diff --git a/nuget.config b/nuget.config new file mode 100644 index 0000000..d98c142 --- /dev/null +++ b/nuget.config @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/DynamicDiToolkit/DynamicDiToolkit.csproj b/src/DynamicDiToolkit/DynamicDiToolkit.csproj new file mode 100644 index 0000000..59fdd1f --- /dev/null +++ b/src/DynamicDiToolkit/DynamicDiToolkit.csproj @@ -0,0 +1,20 @@ + + + + net7.0 + ../../DynamicDiToolkit.nuspec + 10.0 + enable + true + + + + + + + + + + + + diff --git a/src/DynamicDiToolkit/Extensions/ServiceCollectionExtensions.cs b/src/DynamicDiToolkit/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..76b4574 --- /dev/null +++ b/src/DynamicDiToolkit/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,28 @@ +using DynamicDiToolkit.Services; +using DynamicDiToolkit.Interfaces; +using Microsoft.Extensions.DependencyInjection; + +namespace DynamicDiToolkit.Extensions; +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddSingletonArdalisSpecificationRepositoryFactoryServices(this IServiceCollection services) + { + services.AddSingleton(); + + return services; + } + + public static IServiceCollection AddScopedArdalisSpecificationRepositoryFactoryServices(this IServiceCollection services) + { + services.AddScoped(); + + return services; + } + + public static IServiceCollection AddTransientArdalisSpecificationRepositoryFactoryServices(this IServiceCollection services) + { + services.AddTransient(); + + return services; + } +} diff --git a/src/DynamicDiToolkit/Interfaces/IAggregateRoot.cs b/src/DynamicDiToolkit/Interfaces/IAggregateRoot.cs new file mode 100644 index 0000000..480c107 --- /dev/null +++ b/src/DynamicDiToolkit/Interfaces/IAggregateRoot.cs @@ -0,0 +1,5 @@ +namespace DynamicDiToolkit.Interfaces; + +public interface IAggregateRoot +{ +} diff --git a/src/DynamicDiToolkit/Interfaces/IArdalisSpecificationRepositoryFactory.cs b/src/DynamicDiToolkit/Interfaces/IArdalisSpecificationRepositoryFactory.cs new file mode 100644 index 0000000..f34c702 --- /dev/null +++ b/src/DynamicDiToolkit/Interfaces/IArdalisSpecificationRepositoryFactory.cs @@ -0,0 +1,12 @@ +using System; +using Ardalis.Specification; + +namespace DynamicDiToolkit.Interfaces; + +public interface IArdalisSpecificationRepositoryFactory +{ + IRepositoryBase GetRepository() where T : class; + IRepositoryBase GetRepository(string className); + IRepositoryBase GetRepository(string entityName, string entitiesAssembly); + IRepositoryBase GetRepository(Type type); +} diff --git a/src/DynamicDiToolkit/Interfaces/IRepository.cs b/src/DynamicDiToolkit/Interfaces/IRepository.cs new file mode 100644 index 0000000..94b835d --- /dev/null +++ b/src/DynamicDiToolkit/Interfaces/IRepository.cs @@ -0,0 +1,6 @@ +using Ardalis.Specification; + +namespace DynamicDiToolkit.Interfaces; +public interface IRepository : IRepositoryBase where T : class +{ +} diff --git a/src/DynamicDiToolkit/Services/ArdalisSpecificationRepositoryFactory.cs b/src/DynamicDiToolkit/Services/ArdalisSpecificationRepositoryFactory.cs new file mode 100644 index 0000000..dd0382e --- /dev/null +++ b/src/DynamicDiToolkit/Services/ArdalisSpecificationRepositoryFactory.cs @@ -0,0 +1,72 @@ +using System; +using System.Linq; +using Ardalis.Specification; +using DynamicDiToolkit.Interfaces; + +namespace DynamicDiToolkit.Services; + +public class ArdalisSpecificationRepositoryFactory : IArdalisSpecificationRepositoryFactory +{ + private readonly IServiceProvider _serviceProvider; + + public ArdalisSpecificationRepositoryFactory(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public IRepositoryBase GetRepository() where T : class + { + var serviceType = typeof(IRepositoryBase); + return (IRepositoryBase)_serviceProvider.GetService(serviceType)! + ?? throw new InvalidOperationException($"Service for type {typeof(T).Name} not found."); + } + + public IRepositoryBase GetRepository(string entityName) + { + var entityType = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(assembly => assembly.GetTypes()) + .FirstOrDefault(type => type.Name.Equals(entityName, StringComparison.OrdinalIgnoreCase)); + + return GetRepositoryInternally(entityType, entityName); + } + + public IRepositoryBase GetRepository(string entityName, string entitiesAssembly) + { + var assembly = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == entitiesAssembly); + var entityType = assembly?.GetTypes() + .FirstOrDefault(t => t.Name.Equals(entityName, StringComparison.OrdinalIgnoreCase)); + + return GetRepositoryInternally(entityType, entityName); + } + + public IRepositoryBase GetRepository(Type type) + { + var repoType = typeof(IRepositoryBase<>).MakeGenericType(type); + var service = _serviceProvider.GetService(repoType); + if (service == null) + { + throw new InvalidOperationException($"Service for type {type.Name} not found."); + } + + return (IRepositoryBase)service; + } + + private IRepositoryBase GetRepositoryInternally(Type? entityType, string entityName) + { + if (entityType == null) + { + throw new InvalidOperationException($"Entity type {entityName} not found."); + } + + var repositoryGenericType = typeof(IRepositoryBase<>).MakeGenericType(entityType); + var repository = _serviceProvider.GetService(repositoryGenericType); + + if (repository == null) + { + throw new InvalidOperationException($"Repository for entity type {entityName} not found."); + } + + return (IRepositoryBase)repository; + } +}