Skip to content

Commit 794850e

Browse files
authored
Merge pull request #31 from SuessLabs/feature/IpcReceiptedEvents-PreCleanup
[v1.2] Cleanup and Refactor
2 parents a721573 + 4e90b69 commit 794850e

25 files changed

Lines changed: 414 additions & 200 deletions

.github/workflows/build-github.yml

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,54 @@
1-
21
name: Build, Test, Pack, Zip, and Publish
32

43
on:
54
push:
65
branches: [ master, develop ]
6+
# tags:
7+
# - 'v*'
78
pull_request:
89
branches: [ master, develop ]
910

11+
env:
12+
# Update to desired major.minor. This is the base version family.
13+
BASE_VERSION: "2.1"
14+
PATH_SLNX: "src\\Lite.EventIpc.slnx"
15+
PATH_LIB: "src\\Lite.EventIpc\\Lite.EventIpc.csproj"
16+
PATH_ARTIFACTS: ${{github.workspace}}\artifacts
1017

1118
jobs:
1219
build-test-pack:
1320
runs-on: windows-latest
1421

15-
env:
16-
# Update to desired major.minor. This is the base version family.
17-
BASE_VERSION: "1.1"
18-
22+
## This job runs if the ref is a branch
23+
##if: startsWith(github.ref, 'refs/heads/')
1924
steps:
2025
# 1. Checkout source
21-
- name: Checkout repository
22-
uses: actions/checkout@v4
26+
- name: 1. Checkout repository
27+
uses: actions/checkout@v5
2328
with:
2429
fetch-depth: 0 # ensure tags/commits info is available when we expand logic later
2530

2631
# 2. Setup .NET SDK
27-
- name: Setup .NET
32+
- name: 2. Setup .NET
2833
uses: actions/setup-dotnet@v4
2934
with:
3035
dotnet-version: '10.0.x' # Change to your target version
3136

3237
# 3. Restore dependencies
33-
- name: Restore dependencies
34-
run: dotnet restore
38+
- name: 3. Restore dependencies
39+
run: dotnet restore ${{env.PATH_SLNX}}
3540

3641
# 4. Build solution
37-
- name: Build
38-
run: dotnet build --configuration Release --no-restore
42+
- name: 4. Build
43+
run: dotnet build ${{env.PATH_SLNX}} --configuration Release --no-restore
3944

4045
# 5. Run tests
41-
- name: Test
42-
run: dotnet test --configuration Release --no-build --verbosity normal
46+
- name: 5. Test
47+
run: dotnet test ${{env.PATH_SLNX}} --configuration Release --no-build --verbosity normal
4348

4449
# 6. Determin SemVersion package version
45-
- name: Determine version
50+
# "$run" is based on GitHub Action's Workflow "Runs" counter.
51+
- name: 6. Determine version
4652
shell: pwsh
4753
run: |
4854
$branch = "${{ github.ref_name }}"
@@ -73,8 +79,10 @@ jobs:
7379
if ($prerelease) { Write-Host "Version suffix=$prerelease" }
7480
7581
# 7. Pack NuGet
76-
- name: Pack NuGet
77-
run: dotnet pack --configuration Release --no-build --output ./artifacts
82+
- name: 7. Pack NuGet
83+
# Optionally, "--include-symbols"
84+
run: dotnet pack ${{env.PATH_LIB}} --configuration Release --no-build --output ${{env.PATH_ARTIFACTS}}
85+
# dotnet pack source/Lite.EventIpc/Lite.EventIpc.csproj --configuration Release --no-build --output ./artifacts
7886
#- name: Pack NuGet
7987
# shell: pwsh
8088
# run: |
@@ -88,25 +96,33 @@ jobs:
8896
# --output ./artifacts
8997

9098

91-
# 8. Create ZIP of artifacts
92-
- name: Create ZIP archive
93-
run: |
94-
mkdir ./zip
95-
powershell Compress-Archive -Path ./artifacts/* -DestinationPath ./zip/artifacts.zip
99+
## 8. Create ZIP of artifacts
100+
##- name: 8. Create ZIP archive
101+
## run: |
102+
## mkdir ./zip
103+
## powershell Compress-Archive -Path ./artifacts/* -DestinationPath ./zip/artifacts.zip
96104

97-
#shell: pwsh
98-
#run: |
99-
# New-Item -ItemType Directory -Force -Path ./zip | Out-Null
100-
# Compress-Archive -Path ./artifacts/* -DestinationPath ./zip/artifacts.zip
105+
## #shell: pwsh
106+
## #run: |
107+
## # New-Item -ItemType Directory -Force -Path ./zip | Out-Null
108+
## # Compress-Archive -Path ./artifacts/* -DestinationPath ./zip/artifacts.zip
101109

102-
# 9. Upload ZIP as workflow artifact
103-
- name: Upload ZIP
104-
uses: actions/upload-artifact@v4
105-
with:
106-
name: nuget-package-zip
107-
path: ./zip/artifacts.zip
110+
## 9. Upload ZIP as workflow artifact
111+
##- name: 9. Upload ZIP
112+
## uses: actions/upload-artifact@v4
113+
## with:
114+
## name: nuget-package-zip
115+
## path: ./zip/artifacts.zip
108116

109117
## 10) Publish to NuGet.org (master branch, push events only)
118+
- name: 8) NuGet Push Package
119+
env:
120+
NUGET_API_URL: "https://api.nuget.org/v3/index.json"
121+
122+
## Optionally pass, `--skip-duplicate` if a pkg version already exists on NuGet.org
123+
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
124+
run: dotnet nuget push ${{env.PATH_ARTIFACTS}}\*.nupkg -k ${{secrets.NUGET_AUTH_TOKEN}} -s ${{env.NUGET_API_URL}}
125+
110126
#- name: Publish to NuGet.org
111127
# if: github.ref_name == 'master' && github.event_name == 'push'
112128
# env:

readme.md

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
# Lite Event Aggregator and IPC Tranporter
1+
# Lite Event Aggregator and IPC Transporter
22

3-
Lite.EventIPC is a cross-platform local Event Aggregator and remote IPC service library for C#. The pattern is used for decoupling publishers and subscribers in a single or multiple applications. The library can be easily extended for custom IPC transports using the `IEventTransport` interface to suit your needs (_need I say, DBus?_)
3+
Lite.EventIPC is a cross-platform local Event Aggregator and remote IPC (inter-process communication) service library for C#. The pattern is used for decoupling publishers and subscribers in a single or multiple applications. The library can be easily extended for custom IPC transports using the `IEventTransport` interface to suit your needs (_need I say, DBus?_)
44

55
The Event Aggregator service in C# pattern is useful for decoupling publishers and subscribers in an application.
66

77
## Features
88

99
This implementation is features:
1010

11-
* Simple and thread-safe
11+
* Simple, thread-safe, and async friendly
12+
* Local subscribe/publish event aggregator
13+
* `Subscribe` and `Publish` - for one-way events
14+
* `SubscribeRequest` and `RequestAsync` - for publishing with an awaited response (_including timeouts_)
1215
* Uses **weak references** to avoid memory leaks
1316
* Cleans up dead references during `Publish`.
1417
* Prevents memory leaks when subscribers are no longer needed.
1518
* DI-friendly with extensions and hosted service
16-
* Optional IPC transport mechanisms for inter-process communication (IPC) with **JSON serialization**:
19+
* Built-in IPC transport mechanisms (_inter-process communication_) with **JSON serialization**:
1720
* Named Pipe Transport
1821
* Memory-Mapped File Transport (_Windows OS only_)
1922
* TCP/IP Transport
@@ -23,14 +26,16 @@ This implementation is features:
2326

2427
## Usage
2528

29+
### Basic Subscribe/Publish
30+
2631
```cs
32+
using Lite.EventIpc;
2733

2834
public class UserCreatedEvent
2935
{
3036
public string UserName { get; set; }
3137
}
3238

33-
3439
static void Main()
3540
{
3641
var eventAggregator = new EventAggregator();
@@ -44,6 +49,62 @@ static void Main()
4449
}
4550
```
4651

52+
### Publish Requests with Awaited Responses
53+
54+
Subscribing to a **request** event allows users to respond with a different object. This is useful for RPC-like communication.
55+
56+
```cs
57+
using Lite.EventIpc;
58+
59+
public async Task SubscribeWithResponse()
60+
{
61+
// Subscribe to Ping events that respond with Pong
62+
_eventAggregator.SubscribeRequest<Ping, Pong>(EventSubscribe_PingAsync);
63+
64+
// Send a Ping request event and await the Pong response
65+
Ping ping = new Ping("HELLO!");
66+
Pong? response = await _eventAggregator.RequestAsync<Ping, Pong>(ping);
67+
68+
if (response is not null)
69+
{
70+
// Received PONG!
71+
}
72+
}
73+
74+
private async Task<Pong> EventSubscribe_PingAsync(Ping ping)
75+
{
76+
var response = "Received PING loud and clear";
77+
return new Pong(response);
78+
}
79+
```
80+
81+
### Handling Request Event Timeouts
82+
83+
Borrowing from the previous example, you can specify a timeout when sending a request event. If no subscriber responds within the timeout period, `null` is returned.
84+
85+
```cs
86+
public async Task SubscribeWithResponse()
87+
{
88+
// ...
89+
90+
// Send a Ping request event and await the Pong response
91+
Ping ping = new Ping("HELLO!");
92+
var timeout = TimeSpan.FromMilliseconds(3000);
93+
94+
Pong? response = null;
95+
try
96+
{
97+
response = await _eventAggregator.RequestAsync<Ping, Pong>(ping, timeout);
98+
}
99+
catch (TimeoutException)
100+
{
101+
// Handle timeout (no response received in time)
102+
}
103+
104+
// ...
105+
}
106+
```
107+
47108
## Architecture
48109

49110
### Why Weak References

src/.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ indent_style = space
4343
# VSSPELL: Spell checker settings for all files
4444
vsspell_section_id = 001
4545
#vsspell_ignored_words_001 = \transform|csharp|Guid|ble|html|htmlx|hunspells|jquery|json|mimetype|nav|plaintext|resheader|Suess|Soll|uuid|xaml|xml
46-
vsspell_ignored_words_001 = File:IgnoredWords.dic
46+
vsspell_ignored_words_001 = File:spelling-ignored.dic
4747
vsspell_dictionary_languages_001 = en-US
4848
vsspell_exclusion_expressions_001 = [a-z]{2}-([A-Z]{2}|Cyrl|Latn)(?@@PND@@/Options/None)\\\\\w+(?@@PND@@/Options/None)
4949

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<SatelliteResourceLanguages>en</SatelliteResourceLanguages> <!-- Excludes all satellite assemblies -->
1313

1414
<Company>Xeno Innovations, Inc.</Company>
15-
<Copyright>Copyright 2025 Xeno Innovations, Inc.</Copyright>
15+
<Copyright>Copyright 2025-$([System.DateTime]::Now.ToString(yyyy)) Xeno Innovations, Inc.</Copyright>
1616
<Authors>Damian Suess</Authors>
1717
</PropertyGroup>
1818

src/Directory.Packages.props

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
<ItemGroup>
77
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="5.0.0-1.25277.114" />
88
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
9-
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
9+
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.1" />
10+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
11+
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.1" />
1012
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
13+
<PackageVersion Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.3.2" />
1114
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="2.0.2" />
1215
<PackageVersion Include="MSTest" Version="3.10.4" />
1316
<PackageVersion Include="MSTest.TestAdapter" Version="4.0.2" />

src/Lite.EventIpc.Tests/BaseTestClass.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,42 @@
22
// See the LICENSE file in the project root for more information.
33

44
using Microsoft.Extensions.Logging;
5+
using Microsoft.Extensions.Logging.Console;
56

67
namespace Lite.EventIpc.Tests;
78

89
[TestClass]
10+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MSTEST0016:Test class should have test method", Justification = "Its a base class")]
911
public class BaseTestClass
1012
{
11-
/// <summary>Default timeout.. don't wait too long.</summary>
12-
public const int DefaultTimeout = 50;
13+
/// <summary>Timeout 200 milliseconds.</summary>
14+
public const int Timeout200 = 200;
1315

14-
public const int DefaultTimeout200 = 200;
16+
/// <summary>Timeout 50 milliseconds.</summary>
17+
public const int Timeout50 = 50;
1518

1619
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "This is a parent class")]
17-
protected ILogger<EventAggregator>? _logger;
20+
protected ILogger<EventAggregator> _logger;
21+
22+
public BaseTestClass()
23+
{
24+
_logger = CreateConsoleLogger<EventAggregator>(LogLevel.Trace);
25+
}
1826

1927
public TestContext TestContext { get; set; }
2028

21-
protected ILogger<T> CreateConsoleLogger<T>(LogLevel minimumLevel = LogLevel.Debug)
29+
protected static ILogger<T> CreateConsoleLogger<T>(LogLevel minimumLevel = LogLevel.Debug)
2230
{
2331
var factory = LoggerFactory.Create(config =>
2432
{
2533
//// config.AddConsole();
26-
config.AddConsole(options =>
34+
config.AddSimpleConsole(options =>
2735
{
28-
options.TimestampFormat = "[HH:mm:ss.fff] ";
36+
options.TimestampFormat = "HH:mm:ss.fff ";
2937
options.UseUtcTimestamp = false;
3038
options.IncludeScopes = true;
39+
options.SingleLine = true;
40+
options.ColorBehavior = LoggerColorBehavior.Enabled;
3141
});
3242
config.SetMinimumLevel(minimumLevel);
3343
});

src/Lite.EventIpc.Tests/IpcReceiptedTransporters/MemoryMappedTests.cs

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)