From f9ff62bdcdd2347f75bd52e6dc07cb3a9b8a3cd0 Mon Sep 17 00:00:00 2001 From: pomianowski <13592821+pomianowski@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:43:53 +0200 Subject: [PATCH] Prepare --- .editorconfig | 415 ++++++++++++++++++ .github/ISSUE_TEMPLATE/bug_report.yaml | 49 +++ .github/dependabot.yml | 25 ++ .github/funding.yml | 1 + .github/labeler.yml | 29 ++ .github/pull_request_template.md | 32 ++ .github/workflows/cqs-cd-nuget.yaml | 35 ++ .github/workflows/cqs-labeler.yaml | 15 + .github/workflows/cqs-pr-validator.yaml | 35 ++ .gitignore | 3 + .runsettings | 9 + CODEOWNERS | 6 + CODE_OF_CONDUCT.md | 128 ++++++ CommandQuerySegregation.sln | 37 ++ Contributing.md | 36 ++ Directory.Build.props | 103 +++++ Directory.Build.targets | 82 ++++ Directory.Packages.props | 21 + LICENSE | 2 +- LICENSE.md | 21 + README.md | 46 ++ ThirdPartyNotices.txt | 6 + build/nuget.png | Bin 0 -> 19908 bytes nuget.config | 17 + .../CommandQuerySegregation.csproj | 36 ++ src/CommandQuerySegregation/ICommandBus.cs | 29 ++ src/CommandQuerySegregation/IQueryBus.cs | 29 ++ tests/.gitkeep | 0 28 files changed, 1246 insertions(+), 1 deletion(-) create mode 100644 .editorconfig create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml create mode 100644 .github/dependabot.yml create mode 100644 .github/funding.yml create mode 100644 .github/labeler.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/cqs-cd-nuget.yaml create mode 100644 .github/workflows/cqs-labeler.yaml create mode 100644 .github/workflows/cqs-pr-validator.yaml create mode 100644 .runsettings create mode 100644 CODEOWNERS create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CommandQuerySegregation.sln create mode 100644 Contributing.md create mode 100644 Directory.Build.props create mode 100644 Directory.Build.targets create mode 100644 Directory.Packages.props create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 ThirdPartyNotices.txt create mode 100644 build/nuget.png create mode 100644 nuget.config create mode 100644 src/CommandQuerySegregation/CommandQuerySegregation.csproj create mode 100644 src/CommandQuerySegregation/ICommandBus.cs create mode 100644 src/CommandQuerySegregation/IQueryBus.cs create mode 100644 tests/.gitkeep diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7682014 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,415 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# All files +[*] + +#### Core EditorConfig Options #### + +# Encoding +charset = utf-8 + +# Indentation and spacing +tab_width = 4 +indent_size = 4 +indent_style = space + +# New line preferences +end_of_line = unset +insert_final_newline = false + +#### Build files #### + +# Solution files +[*.{sln,slnx}] +tab_width = 4 +indent_size = 4 +indent_style = tab + +# Configuration files +[*.{json,xml,yml,config,runsettings}] +indent_size = 2 + +# MSBuild files +[*.{slnf,props,targets,projitems,csproj,shproj}] +indent_size = 2 + +#### Source files #### + +# Markdown files +[*.md] +indent_size = 2 +insert_final_newline = true + +# C# files +[*.cs] + +#### File Header Template #### +file_header_template = This Source Code Form is subject to the terms of the MIT License.\nIf a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.\nCopyright (C) Leszek Pomianowski and CommandQuerySegregation Contributors.\nAll Rights Reserved. + +#### .NET Coding Conventions #### + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning + +# Parentheses preferences +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_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences (set to silent until https://github.com/dotnet/roslyn/issues/52904 is resolved) +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Code block preferences +dotnet_style_allow_multiple_blank_lines_experimental = false:warning +dotnet_style_allow_statement_immediately_after_block_experimental = false:warning + +# Expression-level preferences +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:silent +csharp_style_throw_expression = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = 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 +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning + +# Field preferences +dotnet_style_readonly_field = true:warning + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false:warning +csharp_style_var_for_built_in_types = false:none +csharp_style_var_when_type_is_apparent = false:none + +# Expression-bodied members +csharp_style_expression_bodied_accessors = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = false:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = false:silent + +# Pattern matching preferences +csharp_style_prefer_pattern_matching = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion + +# Null-checking preferences +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 + +# Code-block preferences +csharp_prefer_braces = true:suggestion +csharp_using_directive_placement = outside_namespace:warning +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_unused_value_assignment_preference = discard_variable:warning +csharp_style_unused_value_expression_statement_preference = discard_variable:warning +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:warning + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_prefer_static_local_function = true:warning +csharp_style_pattern_local_over_anonymous_function = true:warning + +#### 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 = true +csharp_indent_case_contents_when_block = false +csharp_indent_labels = no_change +csharp_indent_switch_labels = true + +# 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 Symbols + +# constant_fields - Define constant fields +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.required_modifiers = const +# non_private_readonly_fields - Define public, internal and protected readonly fields +dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, internal, protected +dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly +# static_readonly_fields - Define static and readonly fields +dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly +# private_readonly_fields - Define private readonly fields +dotnet_naming_symbols.private_readonly_fields.applicable_accessibilities = private +dotnet_naming_symbols.private_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.private_readonly_fields.required_modifiers = readonly +# public_internal_fields - Define public and internal fields +dotnet_naming_symbols.public_internal_protected_fields.applicable_accessibilities = public, internal, protected +dotnet_naming_symbols.public_internal_protected_fields.applicable_kinds = field +# private_protected_fields - Define private and protected fields +dotnet_naming_symbols.private_protected_fields.applicable_accessibilities = private, protected +dotnet_naming_symbols.private_protected_fields.applicable_kinds = field +# public_symbols - Define any public symbol +dotnet_naming_symbols.public_symbols.applicable_accessibilities = public, internal, protected, protected_internal +dotnet_naming_symbols.public_symbols.applicable_kinds = method, property, event, delegate +# parameters - Defines any parameter +dotnet_naming_symbols.parameters.applicable_kinds = parameter +# non_interface_types - Defines class, struct, enum and delegate types +dotnet_naming_symbols.non_interface_types.applicable_kinds = class, struct, enum, delegate +# interface_types - Defines interfaces +dotnet_naming_symbols.interface_types.applicable_kinds = interface + +# Naming Styles + +# camel_case - Define the camelCase style +dotnet_naming_style.camel_case.capitalization = camel_case +# pascal_case - Define the Pascal_case style +dotnet_naming_style.pascal_case.capitalization = pascal_case +# first_upper - The first character must start with an upper-case character +dotnet_naming_style.first_upper.capitalization = first_word_upper +# prefix_interface_interface_with_i - Interfaces must be PascalCase and the first character of an interface must be an 'I' +dotnet_naming_style.prefix_interface_interface_with_i.capitalization = pascal_case +dotnet_naming_style.prefix_interface_interface_with_i.required_prefix = I + +# Naming Rules + +# Async +dotnet_naming_rule.async_methods_end_in_async.severity = silent +dotnet_naming_rule.async_methods_end_in_async.symbols = any_async_methods +dotnet_naming_rule.async_methods_end_in_async.style = end_in_async + +dotnet_naming_symbols.any_async_methods.applicable_kinds = method +dotnet_naming_symbols.any_async_methods.applicable_accessibilities = * +dotnet_naming_symbols.any_async_methods.required_modifiers = async + +dotnet_naming_style.end_in_async.required_suffix = Async +dotnet_naming_style.end_in_async.capitalization = pascal_case + +# Constant fields must be PascalCase +dotnet_naming_rule.constant_fields_must_be_pascal_case.severity = silent +dotnet_naming_rule.constant_fields_must_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_must_be_pascal_case.style = pascal_case +# Public, internal and protected readonly fields must be PascalCase +dotnet_naming_rule.non_private_readonly_fields_must_be_pascal_case.severity = silent +dotnet_naming_rule.non_private_readonly_fields_must_be_pascal_case.symbols = non_private_readonly_fields +dotnet_naming_rule.non_private_readonly_fields_must_be_pascal_case.style = pascal_case +# Static readonly fields must be PascalCase +dotnet_naming_rule.static_readonly_fields_must_be_pascal_case.severity = silent +dotnet_naming_rule.static_readonly_fields_must_be_pascal_case.symbols = static_readonly_fields +dotnet_naming_rule.static_readonly_fields_must_be_pascal_case.style = pascal_case +# Private readonly fields must be camelCase +dotnet_naming_rule.private_readonly_fields_must_be_camel_case.severity = silent +dotnet_naming_rule.private_readonly_fields_must_be_camel_case.symbols = private_readonly_fields +dotnet_naming_rule.private_readonly_fields_must_be_camel_case.style = camel_case +# Public and internal fields must be PascalCase +dotnet_naming_rule.public_internal_protected_fields_must_be_pascal_case.severity = silent +dotnet_naming_rule.public_internal_protected_fields_must_be_pascal_case.symbols = public_internal_protected_fields +dotnet_naming_rule.public_internal_protected_fields_must_be_pascal_case.style = pascal_case +# Private and protected fields must be camelCase +dotnet_naming_rule.private_fields_must_be_camel_case.severity = silent +dotnet_naming_rule.private_fields_must_be_camel_case.symbols = private_protected_fields +dotnet_naming_rule.private_fields_must_be_camel_case.style = prefix_private_field_with_underscore +# Public members must be capitalized +dotnet_naming_rule.public_members_must_be_capitalized.severity = silent +dotnet_naming_rule.public_members_must_be_capitalized.symbols = public_symbols +dotnet_naming_rule.public_members_must_be_capitalized.style = first_upper +# Parameters must be camelCase +dotnet_naming_rule.parameters_must_be_camel_case.severity = silent +dotnet_naming_rule.parameters_must_be_camel_case.symbols = parameters +dotnet_naming_rule.parameters_must_be_camel_case.style = camel_case +# Class, struct, enum and delegates must be PascalCase +dotnet_naming_rule.non_interface_types_must_be_pascal_case.severity = silent +dotnet_naming_rule.non_interface_types_must_be_pascal_case.symbols = non_interface_types +dotnet_naming_rule.non_interface_types_must_be_pascal_case.style = pascal_case +# Interfaces must be PascalCase and start with an 'I' +dotnet_naming_rule.interface_types_must_be_prefixed_with_i.severity = silent +dotnet_naming_rule.interface_types_must_be_prefixed_with_i.symbols = interface_types +dotnet_naming_rule.interface_types_must_be_prefixed_with_i.style = prefix_interface_interface_with_i +# prefix_private_field_with_underscore - Private fields must be prefixed with _ +dotnet_naming_style.prefix_private_field_with_underscore.capitalization = camel_case +dotnet_naming_style.prefix_private_field_with_underscore.required_prefix = _ + +# .NET Code Analysis + +dotnet_diagnostic.CA1001.severity = warning +dotnet_diagnostic.CA1009.severity = warning +dotnet_diagnostic.CA1016.severity = warning +dotnet_diagnostic.CA1033.severity = warning +dotnet_diagnostic.CA1049.severity = warning +dotnet_diagnostic.CA1060.severity = warning +dotnet_diagnostic.CA1061.severity = warning +dotnet_diagnostic.CA1063.severity = warning +dotnet_diagnostic.CA1065.severity = warning +dotnet_diagnostic.CA1301.severity = warning +dotnet_diagnostic.CA1400.severity = warning +dotnet_diagnostic.CA1401.severity = warning +dotnet_diagnostic.CA1403.severity = warning +dotnet_diagnostic.CA1404.severity = warning +dotnet_diagnostic.CA1405.severity = warning +dotnet_diagnostic.CA1410.severity = warning +dotnet_diagnostic.CA1415.severity = warning +dotnet_diagnostic.CA1821.severity = warning +dotnet_diagnostic.CA1900.severity = warning +dotnet_diagnostic.CA1901.severity = warning +dotnet_diagnostic.CA2002.severity = warning +dotnet_diagnostic.CA2100.severity = warning +dotnet_diagnostic.CA2101.severity = warning +dotnet_diagnostic.CA2108.severity = warning +dotnet_diagnostic.CA2111.severity = warning +dotnet_diagnostic.CA2112.severity = warning +dotnet_diagnostic.CA2114.severity = warning +dotnet_diagnostic.CA2116.severity = warning +dotnet_diagnostic.CA2117.severity = warning +dotnet_diagnostic.CA2122.severity = warning +dotnet_diagnostic.CA2123.severity = warning +dotnet_diagnostic.CA2124.severity = warning +dotnet_diagnostic.CA2126.severity = warning +dotnet_diagnostic.CA2131.severity = warning +dotnet_diagnostic.CA2132.severity = warning +dotnet_diagnostic.CA2133.severity = warning +dotnet_diagnostic.CA2134.severity = warning +dotnet_diagnostic.CA2137.severity = warning +dotnet_diagnostic.CA2138.severity = warning +dotnet_diagnostic.CA2140.severity = warning +dotnet_diagnostic.CA2141.severity = warning +dotnet_diagnostic.CA2146.severity = warning +dotnet_diagnostic.CA2147.severity = warning +dotnet_diagnostic.CA2149.severity = warning +dotnet_diagnostic.CA2200.severity = warning +dotnet_diagnostic.CA2202.severity = warning +dotnet_diagnostic.CA2207.severity = warning +dotnet_diagnostic.CA2212.severity = warning +dotnet_diagnostic.CA2213.severity = warning +dotnet_diagnostic.CA2214.severity = warning +dotnet_diagnostic.CA2216.severity = warning +dotnet_diagnostic.CA2220.severity = warning +dotnet_diagnostic.CA2229.severity = warning +dotnet_diagnostic.CA2231.severity = warning +dotnet_diagnostic.CA2232.severity = warning +dotnet_diagnostic.CA2235.severity = warning +dotnet_diagnostic.CA2236.severity = warning +dotnet_diagnostic.CA2237.severity = warning +dotnet_diagnostic.CA2238.severity = warning +dotnet_diagnostic.CA2240.severity = warning +dotnet_diagnostic.CA2241.severity = warning +dotnet_diagnostic.CA2242.severity = warning + +# Require file header OR A source file contains a header that does not match the required text +dotnet_diagnostic.IDE0073.severity = error + +# StyleCop Code Analysis + +# Closing parenthesis should be spaced correctly: "foo()!" +dotnet_diagnostic.SA1009.severity = none + +# Hide warnings when using the new() expression from C# 9. +dotnet_diagnostic.SA1000.severity = none + +dotnet_diagnostic.SA1011.severity = none +dotnet_diagnostic.SA1101.severity = none + +# Hide warnings when accessing properties without "this". +dotnet_diagnostic.SA1101.severity = none +dotnet_diagnostic.SA1118.severity = none +dotnet_diagnostic.SA1200.severity = none +dotnet_diagnostic.SA1201.severity = none +dotnet_diagnostic.SA1202.severity = none +dotnet_diagnostic.SA1309.severity = none +dotnet_diagnostic.SA1310.severity = none + +# Hide warnings for record parameters. +dotnet_diagnostic.SA1313.severity = none + +# TypeParameterNamesMustBeginWithT: We do have a few templates that don't start with T. We need to double check that changing this is not a breaking change. If not, we can re-enable this. +dotnet_diagnostic.SA1314.severity = none + +# UseTrailingCommasInMultiLineInitializers: This would also mean a lot of changes at the end of all multiline initializers. It's also debatable if we want this or not. +dotnet_diagnostic.SA1413.severity = none + +dotnet_diagnostic.SA1600.severity = none +dotnet_diagnostic.SA1602.severity = none +dotnet_diagnostic.SA1611.severity = none + +# DocumentationTextMustEndWithAPeriod: Let's enable this rule back when we shift to WinUI3 (v8.x). If we do it now, it would mean more than 400 file changes. +dotnet_diagnostic.SA1629.severity = none + +dotnet_diagnostic.SA1633.severity = none +dotnet_diagnostic.SA1634.severity = none +dotnet_diagnostic.SA1652.severity = none + + + +# Additional Stylecop Analyzers +dotnet_diagnostic.SA1111.severity = none +dotnet_diagnostic.SA1121.severity = none +dotnet_diagnostic.SA1204.severity = none +dotnet_diagnostic.SA1208.severity = none +dotnet_diagnostic.SA1518.severity = none +dotnet_diagnostic.SA1615.severity = none +dotnet_diagnostic.SA1502.severity = none +dotnet_diagnostic.SA1010.severity = none # Opening square brackets should not be preceded by a space + # conflicts with collection expressions and IDE0028 + +# Suppress some ValueConverter warnings +dotnet_diagnostic.WPF0073.severity = none # Add ValueConversion attribute (unknown types) +dotnet_diagnostic.WPF0071.severity = none # Add ValueConversion attribute +dotnet_diagnostic.WPF0070.severity = none # Add default field to converter + +# Suppress some IDE warnings +dotnet_diagnostic.IDE0290.severity = none # Use primary constructor +dotnet_diagnostic.CS1591.severity = none # Missing XML comment for publicly visible type or member + # 15000+ warnings in the solution +dotnet_diagnostic.CA1510.severity = none # Use ArgumentNullException throw helper + # doesn't work with older versions of .NET + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000..c4d950a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,49 @@ +name: Bug report +description: Create a report to help us improve +title: "Bug title" +labels: [bug] +body: + - type: textarea + validations: + required: true + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is + - type: textarea + validations: + required: true + attributes: + label: To Reproduce + description: Steps to reproduce the behavior + - type: textarea + validations: + required: true + attributes: + label: Expected behavior + description: A clear and concise description of what you expected to happen + - type: textarea + attributes: + label: Screenshots + description: If applicable, add screenshots to help explain your problem + - type: textarea + validations: + required: true + attributes: + label: OS version + description: Which OS versions did you see the issue on? + - type: textarea + validations: + required: true + attributes: + label: .NET version + description: Which .NET versions did you see the issue on? + - type: textarea + validations: + required: true + attributes: + label: OpenAPI Client NuGet version + description: Which OpenAPI Client NuGet versions did you see the issue on? + - type: textarea + attributes: + label: Additional context + description: Add any other context about the problem here diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fc7053e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 + +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + target-branch: "development" + directory: "/" + schedule: + interval: "daily" + labels: + - "Actions" + + # Maintain dependencies for nuget + - package-ecosystem: "nuget" + target-branch: "development" + directory: "/" + schedule: + interval: "daily" + labels: + - "NuGet" diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 0000000..249b02c --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1 @@ +github: [lepoco] diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..4921ffe --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,29 @@ +release: + - base-branch: 'main' + +PR: + - base-branch: [ 'main', 'development' ] + +github_actions: +- changed-files: + - any-glob-to-any-file: '.github/workflows/**' + +documentation: +- changed-files: + - any-glob-to-any-file: [ 'docs/**', 'documentation/**' ] + +dotnet: +- changed-files: + - any-glob-to-any-file: '**/*.cs' + +update: +- changed-files: + - any-glob-to-any-file: 'src/Directory.Build.props' + +NuGet: +- changed-files: + - any-glob-to-any-file: [ 'src/CommandQuerySegregation/**', 'src/Directory.Packages.props' ] + +dependencies: +- changed-files: + - any-glob-to-any-file: [ 'src/Directory.Packages.props' ] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..b8f83b4 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,32 @@ + + +## Pull request type + + + +Please check the type of change your PR introduces: + +- [ ] Update +- [ ] Bugfix +- [ ] Feature +- [ ] Code style update (formatting, renaming) +- [ ] Refactoring (no functional changes, no api changes) +- [ ] Build related changes +- [ ] Documentation content changes + +## What is the current behavior? + + + +Issue Number: N/A + +## What is the new behavior? + + + +- +- + +## Other information + + diff --git a/.github/workflows/cqs-cd-nuget.yaml b/.github/workflows/cqs-cd-nuget.yaml new file mode 100644 index 0000000..63e07a3 --- /dev/null +++ b/.github/workflows/cqs-cd-nuget.yaml @@ -0,0 +1,35 @@ +name: cqs-cd-nuget + +on: + push: + branches: [main] + + workflow_dispatch: + +jobs: + deploy: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: microsoft/setup-msbuild@v1.3 + with: + msbuild-architecture: x64 + - uses: nuget/setup-nuget@v2 + with: + nuget-api-key: ${{ secrets.NUGET_API_KEY }} + - name: Setup .NET Core SDK 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.x + + - name: Install dependencies + run: dotnet restore + + - name: Build + run: dotnet build CommandQuerySegregation.sln --configuration Release --no-restore -p:SourceLinkEnabled=true + + - name: Run tests + run: dotnet test CommandQuerySegregation.sln --configuration Release --no-restore --no-build --verbosity quiet + + - name: Publish the package to NuGet.org + run: nuget push **\*.nupkg -NonInteractive -SkipDuplicate -Source 'https://api.nuget.org/v3/index.json' diff --git a/.github/workflows/cqs-labeler.yaml b/.github/workflows/cqs-labeler.yaml new file mode 100644 index 0000000..d8030e1 --- /dev/null +++ b/.github/workflows/cqs-labeler.yaml @@ -0,0 +1,15 @@ +name: cqs-labeler + +on: + - pull_request_target + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/cqs-pr-validator.yaml b/.github/workflows/cqs-pr-validator.yaml new file mode 100644 index 0000000..c5adcef --- /dev/null +++ b/.github/workflows/cqs-pr-validator.yaml @@ -0,0 +1,35 @@ +name: cqs-pr-validator + +on: + pull_request: + branches: [development] + push: + branches: [development] + + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: microsoft/setup-msbuild@v1.3 + with: + msbuild-architecture: x64 + - uses: nuget/setup-nuget@v2 + with: + nuget-api-key: ${{ secrets.NUGET_API_KEY }} + + - name: Setup .NET Core SDK 8.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.x + + - name: Install dependencies + run: dotnet restore + + - name: Build + run: dotnet build CommandQuerySegregation.sln --configuration Release --no-restore + + - name: Run tests + run: dotnet test CommandQuerySegregation.sln --configuration Release --no-restore --no-build --verbosity quiet diff --git a/.gitignore b/.gitignore index 8a30d25..42bc5d0 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,9 @@ *.userosscache *.sln.docstates +# Rider +.idea + # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs diff --git a/.runsettings b/.runsettings new file mode 100644 index 0000000..1f2d400 --- /dev/null +++ b/.runsettings @@ -0,0 +1,9 @@ + + + 0 + + 0 + ClassLevel + + + diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..cd47b4e --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,6 @@ +# Lines starting with '#' are comments. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in the repo, +# and will automatically be added as reviewers to all pull requests. +* @pomianowski diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..80bd6d3 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +support@lepo.co. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CommandQuerySegregation.sln b/CommandQuerySegregation.sln new file mode 100644 index 0000000..279ea29 --- /dev/null +++ b/CommandQuerySegregation.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandQuerySegregation", "src\CommandQuerySegregation\CommandQuerySegregation.csproj", "{F5FF47B8-A0CC-4F20-A848-AEEF51D4C2C7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3D12BBC8-E962-4230-AA5F-C97BDCB7AB24}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets + Directory.Packages.props = Directory.Packages.props + nuget.config = nuget.config + README.md = README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{7A58AE12-65AA-4E1B-B5DB-CBD2732D1AE7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F5FF47B8-A0CC-4F20-A848-AEEF51D4C2C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5FF47B8-A0CC-4F20-A848-AEEF51D4C2C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5FF47B8-A0CC-4F20-A848-AEEF51D4C2C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5FF47B8-A0CC-4F20-A848-AEEF51D4C2C7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B017BA78-67A5-4D0F-92A3-671B0D8A2911} + EndGlobalSection +EndGlobal diff --git a/Contributing.md b/Contributing.md new file mode 100644 index 0000000..8d2ce14 --- /dev/null +++ b/Contributing.md @@ -0,0 +1,36 @@ +# ✨ Contributing to the CommandQuerySegregation + +Thank you for exhibiting interest in contributing to the CommandQuerySegregation. The team is delighted to welcome you onboard to our exciting and growing project. Any contribution or value added go a long way to enhance the project! + +In the next few steps, you will be able to see a glimpse of ways you can contribute to the CommandQuerySegregation. + +## ❔ Questions + +Due to the high volume of incoming issues please keep our GitHub issues for bug reports and feature requests. For general questions, there is a higher chance of getting your question answered on [StackOverflow](https://stackoverflow.com/questions/tagged/lepo-cqs) where questions should be tagged with the tag `lepo-cqs`. + +## 🐛 Fix a Bug + +If you find any bug, you can help the community by [submitting an issue](https://github.com/lepoco/cqs/issues/new?labels=bug+:bug:&title=[Bug]). Once the issue is filed, feel free to start working on the PR and submit a PR. + +## 👌 Good First Issue + +If this is your first time contributing to the CommandQuerySegregation (_WCT_) and do not have advanced level programming experience, we have got you covered 💥 WCT has a list of [good first issue](https://github.com/lepoco/cqs/labels/good%20first%20issue) that can be a great entryway to find and fix any issues that best fit your expertise or technical background. + +## 🙋 Help Wanted + +WCT also has a list of issues that are labeled as [help wanted](https://github.com/lepoco/cqs/labels/help%20wanted). The level of complexity in the list can vary but if you have an advanced level of programming experience, feel free to jump in to solve these issues. + +## 📬 Add New Feature + +* To contribute a new feature, fill out the [Feature Request Template](https://github.com/lepoco/cqs/issues/new?template=feature_request.md&labels=feature+request+:mailbox_with_mail:&title=[Feature]) and provide detailed information to express the proposal. +* Once the Feature Request is submitted, it will be open for discussion. +* If it gets approved by the team, proceed to submit a PR of the proposed Feature. +* If the PR contains an error-free code and the reviewer signs off, the PR will be merged. + +## 🚀 Create, Submit or Review Pull Request + +Anyone can create a Pull Request by forking the CommandQuerySegregation Repository. Here is how you can [Create a Pull Request from fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork). Once you fork the CommandQuerySegregation repo, it is essential to create all changes in the feature branch of your forked repository. If you have the changes in the forked feature branch, you can then create a Pull Request in the main CommandQuerySegregation. + +## 💙 Thank You + +**Thank you so much for contributing to this amazing project. We hope you will continue to add value and find yourself as a highly reliable source to the CommandQuerySegregation.** diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..fb7da87 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,103 @@ + + + + $(MSBuildThisFileDirectory) + $(RepositoryDirectory)build\ + + + + 1.0.0 + 1.0.0-preview.1 + + + + lepo.co + lepo.co + CommandQuerySegregation + lepoco;commands;queries;bus;messages + MIT + true + (c) lepo.co | Leszek Pomianowski and Contributors. All rights reserved. + https://github.com/lepoco/cqs + https://github.com/lepoco/cqs/releases + Icon.png + https://github.com/lepoco/cqs/main/build/nuget.png + + + + true + moderate + true + false + + + + true + + + + true + 12.0 + enable + + + $(NoWarn);CS8500 + + + + $(MSBuildProjectName.Contains('Test')) + False + True + + + + true + true + $(TF_BUILD) + + + + + + README.md + true + + + + + false + false + $(NoWarn);CS8002;SA0001 + + + + + + + + all + build; analyzers + + + + + + + + true + + true + + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..93aa491 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,82 @@ + + + + + $(Product) Asset + + + + $(CommonTags);.NET + $(CommonTags);$(PackageTags) + $(CommonTags) + + + + + + + + + + + + + <_Parameter1>CommitHash + <_Parameter2>$(SourceRevisionId) + + + + + + + NETSTANDARD2_1_OR_GREATER + + + + + true + true + true + true + + + + + $(IntermediateOutputPath)$(MSBuildProjectName).SkipLocalsInit.g.cs + + +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +[module: global::System.Runtime.CompilerServices.SkipLocalsInitAttribute]]]> + + + + + + + + + + + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..da3f96b --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE index 2dd167a..f979f83 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 lepo +Copyright (c) 2024 Leszek Pomianowski and CommandQuerySegregation Contributors. https://dev.lepo.co/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f979f83 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Leszek Pomianowski and CommandQuerySegregation Contributors. https://dev.lepo.co/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1fd4816 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# 🚎 CommandQuerySegregation + +[Created with ❤ in Poland by lepo.co](https://dev.lepo.co/) +Elevate your application's command and query responsibilities. CommandQuerySegregation provides intuitive interfaces and classes for implementing Command Query Responsibility Segregation (CQRS) in .NET applications. It facilitates clear separation of command and query operations, promoting clean architecture and enhanced maintainability. + +[![GitHub license](https://img.shields.io/github/license/lepoco/cqs)](https://github.com/lepoco/cqs/blob/master/LICENSE) [![Nuget](https://img.shields.io/nuget/v/CommandQuerySegregation)](https://www.nuget.org/packages/CommandQuerySegregation/) [![Nuget](https://img.shields.io/nuget/dt/CommandQuerySegregation?label=nuget)](https://www.nuget.org/packages/CommandQuerySegregation/) [![Sponsors](https://img.shields.io/github/sponsors/lepoco)](https://github.com/sponsors/lepoco) + +## 👀 What does this repo contain? + +This repository houses the source code for the CommandQuerySegregation NuGet package. + +## Gettings started + +CommandQuerySegregation is available as NuGet package on NuGet.org: +https://www.nuget.org/packages/CommandQuerySegregation + +You can add it to your project using .NET CLI: + +```powershell +dotnet add package CommandQuerySegregation +``` + +, or package manager console: + +```powershell +NuGet\Install-Package CommandQuerySegregation +``` + +### 🛠️ How to Use CommandQuerySegregation +tba + +## Compilation + +To build the project, use Visual Studio 2022 and open the .sln file. + +Visual Studio +**CommandQuerySegregation** is an Open Source project. You are entitled to download and use the freely available Visual Studio Community Edition to build, run or develop for CommandQuerySegregation. As per the Visual Studio Community Edition license, this applies regardless of whether you are an individual or a corporate user. + +## Code of Conduct + +This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. + +## License + +**CommandQuerySegregation** is free and open source software licensed under **MIT License**. You can use it in private and commercial projects. +Keep in mind that you must include a copy of the license in your project. diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt new file mode 100644 index 0000000..5127949 --- /dev/null +++ b/ThirdPartyNotices.txt @@ -0,0 +1,6 @@ +CommandQuerySegregation + +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION +Do Not Translate or Localize + +This project incorporates components from the projects listed below. The original copyright notices and the licenses under which the authors received such components are set forth below. diff --git a/build/nuget.png b/build/nuget.png new file mode 100644 index 0000000000000000000000000000000000000000..111f86d65041e8c550a39acc3abe07cd858d24ba GIT binary patch literal 19908 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 literal 0 HcmV?d00001 diff --git a/nuget.config b/nuget.config new file mode 100644 index 0000000..6eca12a --- /dev/null +++ b/nuget.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/CommandQuerySegregation/CommandQuerySegregation.csproj b/src/CommandQuerySegregation/CommandQuerySegregation.csproj new file mode 100644 index 0000000..ba981a3 --- /dev/null +++ b/src/CommandQuerySegregation/CommandQuerySegregation.csproj @@ -0,0 +1,36 @@ + + + + CommandQuerySegregation + netstandard2.0;netstandard2.1;net462;net6.0;net8.0 + true + true + true + About + Elevate your application's command and query responsibilities. CommandQuerySegregation provides intuitive interfaces and classes for implementing Command Query Responsibility Segregation (CQRS) in .NET applications. It facilitates clear separation of command and query operations, promoting clean architecture and enhanced maintainability. + + + + true + true + Speed + + + + + + System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute; + System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute; + System.Diagnostics.CodeAnalysis.MemberNotNullAttribute; + System.Diagnostics.CodeAnalysis.NotNullAttribute; + System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute; + System.Diagnostics.CodeAnalysis.NotNullWhenAttribute; + System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute; + System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute; + System.Runtime.CompilerServices.CallerArgumentExpressionAttribute; + System.Runtime.CompilerServices.IsExternalInit; + System.Runtime.CompilerServices.SkipLocalsInitAttribute; + + + + diff --git a/src/CommandQuerySegregation/ICommandBus.cs b/src/CommandQuerySegregation/ICommandBus.cs new file mode 100644 index 0000000..30b7d17 --- /dev/null +++ b/src/CommandQuerySegregation/ICommandBus.cs @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and CommandQuerySegregation Contributors. +// All Rights Reserved. + +using System.Threading; +using System.Threading.Tasks; + +namespace CommandQuerySegregation; + +/// +/// Defines a contract for a command bus in a Command Query Responsibility Segregation (CQRS) pattern. +/// +/// +/// A command bus is responsible for dispatching commands to their appropriate handlers. +/// +public interface ICommandBus +{ + /// + /// Executes the given command asynchronously. + /// + /// The type of the command to execute. + /// The type of the result that the command returns. + /// The command to execute. + /// A cancellation token that can be used to cancel the work. + /// A task that represents the asynchronous operation. + Task ExecuteAsync(TCommand command, CancellationToken cancellationToken) + where TCommand : class; +} diff --git a/src/CommandQuerySegregation/IQueryBus.cs b/src/CommandQuerySegregation/IQueryBus.cs new file mode 100644 index 0000000..05c447a --- /dev/null +++ b/src/CommandQuerySegregation/IQueryBus.cs @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and CommandQuerySegregation Contributors. +// All Rights Reserved. + +using System.Threading; +using System.Threading.Tasks; + +namespace CommandQuerySegregation; + +/// +/// Defines a contract for a query bus in a Command Query Responsibility Segregation (CQRS) pattern. +/// +/// +/// A query bus is responsible for dispatching queries to their appropriate handlers. +/// +public interface IQueryBus +{ + /// + /// Executes the given query asynchronously. + /// + /// The type of the query to execute. + /// The type of the result that the query returns. + /// The query to execute. + /// A cancellation token that can be used to cancel the work. + /// A task that represents the asynchronous operation. + Task ExecuteAsync(TQuery query, CancellationToken cancellationToken) + where TQuery : class; +} diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000..e69de29