Skip to content

Commit ae7e915

Browse files
committed
Rework packaging to simplify consumption
Fixes #164
1 parent 9387347 commit ae7e915

39 files changed

+119
-172
lines changed

Merq.sln

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.2.32616.157
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Merq", "src\Merq\Merq.csproj", "{C6B16D17-4F6A-4457-8497-92068E53DE39}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Merq.Abstractions", "src\Merq.Abstractions\Merq.Abstractions.csproj", "{C6B16D17-4F6A-4457-8497-92068E53DE39}"
77
EndProject
8-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Merq.Core", "src\Merq.Core\Merq.Core.csproj", "{33BDD9D1-3E01-49C1-AB46-50941DFFD5D4}"
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Merq", "src\Merq\Merq.csproj", "{33BDD9D1-3E01-49C1-AB46-50941DFFD5D4}"
99
EndProject
1010
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Merq.VisualStudio", "src\Merq.VisualStudio\Merq.VisualStudio.csproj", "{4497EC4D-62B4-4B20-8A4F-15F10B0452FB}"
1111
EndProject
1212
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Merq.Tests", "src\Merq.Tests\Merq.Tests.csproj", "{A82ADE56-3DF7-435F-830A-4970D508CAFC}"
1313
EndProject
14-
Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Merq.DependencyInjection", "src\Merq.DependencyInjection\Merq.DependencyInjection.msbuildproj", "{9A13A6CD-08DD-496B-ACB7-A52CEC8E1FD0}"
15-
EndProject
1614
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Merq.VisualStudio.Tests", "src\Merq.VisualStudio.Tests\Merq.VisualStudio.Tests.csproj", "{DA774F3B-698B-4BF0-9116-27656BBDA965}"
1715
EndProject
1816
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Merq.CodeAnalysis", "src\Merq.CodeAnalysis\Merq.CodeAnalysis.csproj", "{932B8838-FB30-4861-A7B9-713430F2867A}"
@@ -59,10 +57,6 @@ Global
5957
{A82ADE56-3DF7-435F-830A-4970D508CAFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
6058
{A82ADE56-3DF7-435F-830A-4970D508CAFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
6159
{A82ADE56-3DF7-435F-830A-4970D508CAFC}.Release|Any CPU.Build.0 = Release|Any CPU
62-
{9A13A6CD-08DD-496B-ACB7-A52CEC8E1FD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63-
{9A13A6CD-08DD-496B-ACB7-A52CEC8E1FD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
64-
{9A13A6CD-08DD-496B-ACB7-A52CEC8E1FD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
65-
{9A13A6CD-08DD-496B-ACB7-A52CEC8E1FD0}.Release|Any CPU.Build.0 = Release|Any CPU
6660
{DA774F3B-698B-4BF0-9116-27656BBDA965}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
6761
{DA774F3B-698B-4BF0-9116-27656BBDA965}.Debug|Any CPU.Build.0 = Debug|Any CPU
6862
{DA774F3B-698B-4BF0-9116-27656BBDA965}.Release|Any CPU.ActiveCfg = Release|Any CPU

readme.md

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -280,20 +280,11 @@ The same analyzers and code fixes are provided for the opposite anti-pattern,
280280
known as [sync over async](https://devblogs.microsoft.com/pfxteam/should-i-expose-synchronous-wrappers-for-asynchronous-methods/),
281281
where a synchronous command is executed asynchronously.
282282

283-
<!-- #core -->
284-
285-
## Message Bus
286-
287-
The default implementation lives in a separate package [Merq.Core](https://www.nuget.org/packages/Merq.Core)
288-
so that application components can take a dependency on just the interfaces.
289-
290-
[![Version](https://img.shields.io/nuget/vpre/Merq.Core.svg?color=royalblue)](https://www.nuget.org/packages/Merq.Core)
291-
[![Downloads](https://img.shields.io/nuget/dt/Merq.Core.svg?color=green)](https://www.nuget.org/packages/Merq.Core)
283+
## Hosting
292284

293-
<!-- #implementation -->
294285
The default implementation of the message bus interface `IMessageBus` has
295286
no external dependencies and can be instantiated via the `MessageBus` constructor
296-
directly.
287+
directly by an application host.
297288

298289
The bus locates command handlers and event producers via the passed-in
299290
`IServiceProvider` instance in the constructor:
@@ -308,14 +299,9 @@ bus.Execute(new MyCommand());
308299
bus.Observe<MyEvent>().Subscribe(e => Console.WriteLine(e.Message));
309300
```
310301

302+
Merq integrates out of the box with [dependency injection for .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection), making it straightforward to
303+
properly register the bus and all command handlers and event producers.
311304

312-
<!-- #implementation -->
313-
314-
When using [dependency injection for .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection),
315-
the [Merq.DependencyInjection](https://www.nuget.org/packages/Merq.DependencyInjection) package
316-
provides a simple mechanism for registering the message bus:
317-
318-
<!-- #di -->
319305
```csharp
320306
var builder = WebApplication.CreateBuilder(args);
321307
...
@@ -324,7 +310,9 @@ builder.Services.AddMessageBus();
324310

325311
All command handlers and event producers need to be registered with the
326312
services collection as usual, using the main interface for the component,
327-
such as `ICommandHandler<T>` and `IObservable<TEvent>`.
313+
such as `ICommandHandler<T>` and `IObservable<TEvent>`. In addition, if
314+
you use the `IMessageBus.CanExecute<T>` method, handlers need to also be
315+
registered with the `ICanExecute<T>` interface.
328316

329317
> NOTE: *Merq* makes no assumptions about the lifetime of the registered
330318
> components, so it's up to the consumer to register them with the desired
@@ -346,7 +334,10 @@ This allows to simply mark all command handlers and event producers as
346334
builder.Services.AddServices();
347335
```
348336

349-
### Telemetry and Monitoring
337+
This package emits all registrations at compile-time using source generators,
338+
so run-time performance is not affected at all.
339+
340+
## Telemetry and Monitoring
350341

351342
The core implementation of the `IMessageBus` is instrumented with `ActivitySource` and
352343
`Metric`, providing out of the box support for [Open Telemetry](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs)-based monitoring, as well
@@ -384,35 +375,7 @@ Example rendering from the included sample console app:
384375

385376
![dotnet-counters screenshot](https://raw.githubusercontent.com/devlooped/Merq/main/assets/img/dotnet-counters.png)
386377
387-
## Duck Typing Support
388-
389-
<!-- #duck -->
390-
Being able to loosely couple both events (and their consumers) and command execution (from their
391-
command handler implementations) is a key feature of Merq. To take this decoupling to the extreme,
392-
Merq allows a similar capability as allowed by the TypeScript/JavaScript in VSCode: you can just
393-
copy/paste an event/command definition as *source* into your assembly, and perform the regular
394-
operations with it (like `Observe` an event and `Execute` a command), in a "duck typing" manner.
395-
396-
As long as the types' full name match, the conversion will happen automatically. Since this
397-
functionality isn't required in many scenarios, and since there are a myriad ways to implement
398-
such an object mapping functionality, the `Merq.Core` package only provides the hooks to enable
399-
this, but does not provide any built-in implementation for it. In other words, no duck typing
400-
is performed by default.
401-
402-
The [Merq.AutoMapper](https://www.nuget.org/packages/Merq.AutoMapper) package provides one such
403-
implementation, based on the excelent [AutoMapper](https://automapper.org/) library. It can be
404-
registered with the DI container as follows:
405-
406-
```csharp
407-
builder.Services.AddMessageBus<AutoMapperMessageBus>();
408-
// register all services, including handlers and producers
409-
builder.Services.AddServices();
410-
```
411-
412-
<!-- #duck -->
413-
414-
<!-- #perf -->
415-
# Performance
378+
## Performance
416379

417380
The performance of Merq is on par with the best implementations of the
418381
the same pattern, for example [MediatR](https://www.nuget.org/packages/mediatr).
@@ -438,7 +401,42 @@ Intel Core i9-10900T CPU 1.90GHz, 1 CPU, 20 logical and 10 physical cores
438401

439402
<!-- ./src/Merq.Benchmarks/BenchmarkDotNet.Artifacts/results/Merq.MerqVsMediatR.Benchmark-report-github.md -->
440403

441-
<!-- #perf -->
404+
## Abstractions
405+
406+
[![Version](https://img.shields.io/nuget/vpre/Merq.Abstractions.svg?color=royalblue)](https://www.nuget.org/packages/Merq.Abstractions)
407+
[![Downloads](https://img.shields.io/nuget/dt/Merq.Abstractions.svg?color=green)](https://www.nuget.org/packages/Merq.Abstractions)
408+
409+
<!-- #abstractions -->
410+
The [Merq.Abstractions](https://www.nuget.org/packages/Merq.Abstractions)
411+
contains just the interfaces for [Merq](https://www.nuget.org/packages/Merq) for scenarios where
412+
messages are shared across multiple assemblies or defined separately from the main app host.
413+
<!-- #abstractions -->
414+
415+
## Duck Typing
416+
417+
Being able to loosely couple both events (and their consumers) and command execution (from their
418+
command handler implementations) is a key feature of Merq. To take this decoupling to the extreme,
419+
Merq allows a similar capability as allowed by the TypeScript/JavaScript in VSCode: you can just
420+
copy/paste an event/command definition as *source* into your assembly, and perform the regular
421+
operations with it (like `Observe` an event and `Execute` a command), in a "duck typing" manner.
422+
423+
As long as the types' full name match, the conversion will happen automatically. Since this
424+
functionality isn't required in many scenarios, and since there are a myriad ways to implement
425+
such an object mapping functionality, the `Merq.Core` package only provides the hooks to enable
426+
this, but does not provide any built-in implementation for it. In other words, no duck typing
427+
is performed by default.
428+
429+
The [Merq.AutoMapper](https://www.nuget.org/packages/Merq.AutoMapper) package provides one such
430+
implementation, based on the excelent [AutoMapper](https://automapper.org/) library. It can be
431+
registered with the DI container as follows:
432+
433+
```csharp
434+
builder.Services.AddMessageBus<AutoMapperMessageBus>();
435+
// register all services, including handlers and producers
436+
builder.Services.AddServices();
437+
```
438+
439+
<!-- #core -->
442440

443441
<!-- #ci -->
444442

File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)