Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 103 additions & 35 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,41 @@ indent_size = 4
indent_style = space

# New line preferences
end_of_line = unset
end_of_line = crlf
insert_final_newline = false
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
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
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_diagnostic.CA1304.severity = warning
dotnet_diagnostic.CA1707.severity = none
dotnet_diagnostic.CA1829.severity = warning

#### Build files ####

# Solution files
[*.{sln,slnx}]
[*.{sln}]
tab_width = 4
indent_size = 4
indent_style = tab

# Modern solution files
[*.{slnx}]
indent_size = 2

# Configuration files
[*.{json,xml,yml,config,runsettings}]
indent_size = 2
Expand Down Expand Up @@ -123,7 +147,7 @@ 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_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:warning

# Expression-level preferences
Expand Down Expand Up @@ -225,9 +249,9 @@ dotnet_naming_style.prefix_interface_interface_with_i.required_prefix
# Naming Rules

# Async
dotnet_naming_rule.async_methods_end_in_async.severity = silent
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_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 = *
Expand All @@ -237,45 +261,45 @@ dotnet_naming_style.end_in_async.required_suffix
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.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
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.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
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.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
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.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
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.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
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.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
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.severity = silent
dotnet_naming_rule.public_members_must_be_capitalized.symbols = public_symbols
dotnet_naming_rule.public_members_must_be_capitalized.style = first_upper
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.severity = silent
dotnet_naming_rule.parameters_must_be_camel_case.symbols = parameters
dotnet_naming_rule.parameters_must_be_camel_case.style = camel_case
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.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
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.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
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 = _
Expand Down Expand Up @@ -344,18 +368,36 @@ dotnet_diagnostic.CA2238.severity = warning
dotnet_diagnostic.CA2240.severity = warning
dotnet_diagnostic.CA2241.severity = warning
dotnet_diagnostic.CA2242.severity = warning
dotnet_diagnostic.CS9107.severity = suggestion
dotnet_diagnostic.CS0612.severity = suggestion

# Async Fixer

dotnet_diagnostic.AsyncFixer01.severity = silent

# ErrorProne

dotnet_diagnostic.EPC12.severity = suggestion
dotnet_diagnostic.EPS05.severity = suggestion

# IDispossable

dotnet_diagnostic.IDISP001.severity = warning
dotnet_diagnostic.IDISP017.severity = none
dotnet_diagnostic.IDISP013.severity = suggestion
dotnet_diagnostic.IDISP004.severity = warning
dotnet_diagnostic.IDISP001.severity = warning
dotnet_diagnostic.IDISP026.severity = suggestion

# 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.SA1005.severity = suggestion # Single line comments should begin with a space
dotnet_diagnostic.SA0001.severity = none
dotnet_diagnostic.SA1009.severity = none # Closing parenthesis should be spaced correctly: "foo()!"
dotnet_diagnostic.SA1000.severity = none # Hide warnings when using the new() expression from C# 9.
dotnet_diagnostic.SA1011.severity = none
dotnet_diagnostic.SA1101.severity = none

Expand All @@ -382,7 +424,7 @@ 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.SA1629.severity = warning

dotnet_diagnostic.SA1633.severity = none
dotnet_diagnostic.SA1634.severity = none
Expand All @@ -409,7 +451,33 @@ 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

csharp_prefer_simple_using_statement = true:suggestion
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_expression_bodied_local_functions = false:silent

dotnet_diagnostic.ASPIREPROXYENDPOINTS001.severity = none
csharp_prefer_system_threading_lock = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
dotnet_diagnostic.CA1311.severity = warning

# unreachable code
dotnet_diagnostic.CS0162.severity = error

# non-nullable property uninitialized
dotnet_diagnostic.CS8618.severity = error

# nullability of type argument doesn't match 'notnull' constraint
dotnet_diagnostic.CS8714.severity = error

# nullability mismatch in return type of lambda
dotnet_diagnostic.CS8621.severity = error
dotnet_diagnostic.CS8766.severity = error

# switch expression not exhaustive
dotnet_diagnostic.CS8524.severity = warning
dotnet_diagnostic.CS8509.severity = error
2 changes: 1 addition & 1 deletion .github/workflows/reflection-events-cd-nuget.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
run: dotnet restore

- name: Build
run: dotnet build ReflectionEventing.sln --configuration Release --no-restore -p:SourceLinkEnabled=true
run: dotnet build ReflectionEventing.slnx --configuration Release --no-restore -p:SourceLinkEnabled=true

- name: Publish the package to NuGet.org
run: nuget push **\*.nupkg -NonInteractive -SkipDuplicate -Source 'https://api.nuget.org/v3/index.json'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/reflection-events-pr-validator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
run: dotnet restore

- name: Build
run: dotnet build ReflectionEventing.sln --configuration Release --no-restore
run: dotnet build ReflectionEventing.slnx --configuration Release --no-restore

- name: Run tests
run: dotnet test ReflectionEventing.sln --configuration Release --no-restore --no-build --verbosity quiet
run: dotnet test ReflectionEventing.slnx --configuration Release --no-restore --no-build --verbosity quiet
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ src/lepo.snk
# DocFX
docs/api/

docs/board.md

# User-specific files
*.rsuser
*.suo
Expand Down
1 change: 1 addition & 0 deletions .serena/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/cache
108 changes: 108 additions & 0 deletions .serena/memories/architecture_patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Architecture and Design Patterns

## Core Architecture

ReflectionEventing follows a modular architecture with clear separation of concerns:

### Core Components

1. **EventBus** (`src/ReflectionEventing/EventBus.cs`)
- Central event dispatching mechanism
- Manages consumer registration and event publication
- Supports multiple processing modes

2. **IConsumer<T>** Interface
- Event consumers implement this interface
- Provides `ConsumeAsync(T payload, CancellationToken)` method
- Allows multiple consumers per event type

3. **Consumer Providers**
- Abstract consumer resolution from specific DI containers
- Each DI integration has its own provider implementation
- Supports dependency injection for consumers

4. **Consumer Types Providers**
- Hashed lookup for efficient consumer discovery
- Supports polymorphic event handling
- Uses reflection to find matching consumers

5. **Event Queues** (`src/ReflectionEventing/Queues/`)
- Channel-based event queue implementation
- Background processing support
- Failed event handling

## Design Patterns

### Dependency Injection
- Core abstraction independent of specific DI container
- Adapter pattern for each DI framework
- Consumers resolved from DI container at runtime

### Builder Pattern
- `EventBusBuilder` for configuring the event bus
- Fluent API for adding consumers and options
- Extension methods for each DI integration

### Observer Pattern
- Event bus as subject
- Consumers as observers
- Decoupled event publishers and subscribers

### Strategy Pattern
- Different processing modes (sequential, parallel, queued)
- Pluggable consumer type resolution strategies
- Flexible error handling strategies

### Factory Pattern
- Consumer provider factories for each DI container
- EventBus instantiation through builders

## Processing Modes

1. **Sequential** - Events processed one at a time in order
2. **Parallel** - Multiple events processed concurrently
3. **Queued** - Events placed in queue for background processing

## Key Design Principles

### Inversion of Control (IoC)
- Event publishers don't know about consumers
- Consumers registered via DI container
- Loose coupling between components

### Single Responsibility
- EventBus: Event routing
- Consumer Providers: DI integration
- Consumer Types Providers: Type resolution
- Event Queues: Background processing

### Open/Closed Principle
- Core library closed for modification
- Open for extension via DI integrations
- Custom consumer types providers can be implemented

### Interface Segregation
- Small, focused interfaces (`IEventBus`, `IConsumer<T>`)
- Separate concerns (provider vs types provider)

### Dependency Inversion
- Depend on abstractions (`IEventBus`, `IConsumerProvider`)
- DI integrations depend on core abstractions

## Threading and Async
- Async/await throughout
- CancellationToken support
- Channel-based queuing for thread-safe event processing
- Task-based parallelism for concurrent event handling

## Error Handling
- EventBusException for bus-specific errors
- QueueException for queue-specific errors
- Failed events captured and can be reprocessed
- Graceful degradation on consumer failures

## Performance Considerations
- Hashed lookup for consumer types (O(1) average case)
- Channel-based queuing for efficient producer-consumer pattern
- AOT compilation support for .NET 8.0+
- Trimming support to reduce app size
Loading
Loading