Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
12b61f9
Trimming warning approval (#7800)
danielmarbach Jun 4, 2026
4bfea9c
Remove the container tests since they are no longer shipped and effec…
danielmarbach Jun 8, 2026
46a4cbf
Support structured logging in downstream providers (#7804)
adam-mccoy Jun 8, 2026
6ecfa7f
Update dependency Particular.AnalyzerTesting to 2.1.0 (#7808)
dependencyupdates[bot] Jun 9, 2026
09a753a
Fix NSB0033 incorrectly reporting mixed handler style when helper ove…
SimonCropp Jun 11, 2026
69650ff
Update .NET Packages (#7809)
dependencyupdates[bot] Jun 11, 2026
e02c646
Update dependency Particular.Licensing.Sources to 7.1.1 (#7810)
dependencyupdates[bot] Jun 11, 2026
42c08d4
Ensure RunningEndpointInstance.DisposeAsync completes when host is di…
SimonCropp Jun 11, 2026
d6b43fa
Support FromKeyedServicesAttribute (#7822)
danielmarbach Jun 17, 2026
2ddfd86
Optimize ContextBag with InlineArray-based slot storage (#7823)
danielmarbach Jun 18, 2026
5f3aac9
Trimming safe mapping by using guarding against IsDynamicCodeSupporte…
danielmarbach Jun 18, 2026
09b7b07
Update actions/checkout action to v7 (#7828)
dependencyupdates[bot] Jun 18, 2026
7b295cc
Prepare tests for header pooling (#7826)
danielmarbach Jun 21, 2026
5d3b483
Support AOT and trimming compliance in SystemJson serializer and Lear…
danielmarbach Jun 22, 2026
11d7707
Update dependency Microsoft.NET.Test.Sdk to 18.7.0 (#7830)
dependencyupdates[bot] Jun 23, 2026
1104eeb
Resolve globally registered endpoint-keyed services inside keyed endp…
danielmarbach Jun 26, 2026
d072c26
Update actions/setup-dotnet action to v5.4.0 (#7832)
dependencyupdates[bot] Jun 26, 2026
57ee8bd
Update dependency Particular.Licensing.Sources to 7.2.0 (#7853)
dependencyupdates[bot] Jul 14, 2026
951482b
Update dependency Microsoft.NET.Test.Sdk to 18.8.0 (#7854)
dependencyupdates[bot] Jul 14, 2026
fd790f6
Update dependency Particular.Licensing.Sources to 7.3.0 (#7858)
dependencyupdates[bot] Jul 14, 2026
c747104
Add support for nullable reference types - Pipeline folder (#7847)
soujay Jul 15, 2026
7d5d476
Add support for nullable reference types - Hosting folder (#7848)
soujay Jul 15, 2026
10e35b0
Add support for nullable reference types - Logging (#7849)
soujay Jul 15, 2026
d9bfa0e
Add support for nullable reference types - OpenTelemetry (#7850)
soujay Jul 15, 2026
92e4bd1
Add support for nullable types - Support (#7851)
soujay Jul 15, 2026
b047937
Update actions/setup-dotnet action to v6 (#7866)
dependencyupdates[bot] Jul 16, 2026
240373b
Delete guidelines directory (#7865)
tamararivera Jul 16, 2026
a5d96a5
Update dependency Particular.AnalyzerTesting to 2.2.0 (#7870)
dependencyupdates[bot] Jul 17, 2026
89c91b0
Update actions/checkout action to v7.0.1 (#7876)
dependencyupdates[bot] Jul 20, 2026
7e27407
Add blank line after #nullable enable to match repo convention
mchamberlin77 Jul 20, 2026
5ae7725
Merge pull request #7877 from Particular/nullable-enable-blank-line-f…
mchamberlin77 Jul 20, 2026
a3ef2ec
Add support for nullable reference types - Recoverability (#7855)
mchamberlin77 Jul 21, 2026
bf62951
Add support for nullable reference types - UnitOfWork (#7856)
mchamberlin77 Jul 21, 2026
685e7c0
Add support for nullable reference types - ServicePlatform (#7863)
mchamberlin77 Jul 22, 2026
fd96308
Update dependency GitHubActionsTestLogger to 3.0.5 (#7881)
dependencyupdates[bot] Jul 25, 2026
42ec962
Add support for nullable reference types - Utils (#7862)
mchamberlin77 Jul 27, 2026
a1cd285
Add support for nullable types - StaticHeaders (#7852)
soujay Jul 27, 2026
506b78d
Add support for nullable reference types - Serialization (#7859)
soujay Jul 27, 2026
63ac7b8
Add AOT-safe startup diagnostics serialization (#7882)
danielmarbach Jul 28, 2026
316a523
Add DynamicallyAccessedMembers attribute to AddEnvelopeHandler method…
danielmarbach Jul 29, 2026
0613483
Enhance trimmability by introducing TypeKey for keyed service factori…
danielmarbach Jul 29, 2026
ff1f607
Add support for nullable reference types - Reliability (#7886)
bording Jul 31, 2026
8f02760
GitHubSync update - master (#7893)
internalautomation[bot] Jul 31, 2026
974a5c2
Optimize DispatchProperties and ReceiveProperties storage (#7843)
danielmarbach Aug 4, 2026
83ee9be
Preserve the native properties on delayed retries (#7900)
lailabougria Aug 5, 2026
d3682cb
Add test to track usage of legacy NServiceBus.Logging API (#7902)
danielmarbach Aug 5, 2026
016bb5e
Add acceptance tests to track nullable enabled directives (#7869)
mchamberlin77 Aug 5, 2026
0c2dc73
Update dependency Particular.Licensing.Sources to 7.4.0 (#7891)
dependencyupdates[bot] Aug 5, 2026
01b76ac
Rename binlog file for nullable warnings (#7903)
danielmarbach Aug 6, 2026
5de16fc
Update .NET Packages (#7857)
dependencyupdates[bot] Aug 6, 2026
0f4a6fd
Remove binlog generation from nullable and trimming warnings tests (#…
danielmarbach Aug 6, 2026
1d53488
Refine TODO comment for nullable changes (#7905)
mchamberlin77 Aug 6, 2026
110d7e9
Update .NET Packages to 10.0.11 (#7909)
dependencyupdates[bot] Aug 11, 2026
e64390f
Update dependency Microsoft.NET.Test.Sdk to 18.9.0 (#7913)
dependencyupdates[bot] Aug 14, 2026
81b375b
Update dependency Microsoft.Extensions.Diagnostics.Testing to 10.9.0 …
dependencyupdates[bot] Aug 14, 2026
833fcfb
Add trimming-safe messaging overloads and migration analyzer (#7889)
danielmarbach Aug 24, 2026
3618b60
Update dependency NUnit3TestAdapter to 6.3.0 (#7915)
dependencyupdates[bot] Aug 24, 2026
0b42387
Prepare Core for unsafe context changes in v11 (#7916)
danielmarbach Aug 27, 2026
7660e88
Support trimming-safe message metadata without assembly scanning (#7…
danielmarbach Sep 2, 2026
62b6c62
RollingLogger race condition due to file system failures (#7921)
danielmarbach Sep 3, 2026
433a688
Update dependency Particular.AnalyzerTesting to 2.3.0
dependencyupdates[bot] Sep 3, 2026
ed66391
Use the new analyzer functionality
danielmarbach Sep 3, 2026
7bb5a57
Logical mutators trimming and AOT improvements (#7925)
danielmarbach Sep 4, 2026
ccc94cb
Update Particular/run-tests-action action to v1.8.0 (#7930)
dependencyupdates[bot] Sep 8, 2026
3a1d278
Update dependency Microsoft.NET.Test.Sdk to 18.10.0 (#7935)
dependencyupdates[bot] Sep 9, 2026
70666de
Update Particular/run-tests-action action to v1.9.0 (#7938)
dependencyupdates[bot] Sep 9, 2026
65114c9
Remove pi session artifact (#7939)
danielmarbach Sep 10, 2026
4f1fe24
Say that the cancellation token fired instead of printing an infinite…
ramonsmits Sep 10, 2026
d2b5ed9
Bound acceptance tests by the test's CancelAfter budget instead of th…
danielmarbach Sep 10, 2026
65ebb29
Support for trimming and AOT (#7929)
danielmarbach Sep 11, 2026
9106cc6
Update dependency NUnit.Analyzers to 4.15.0 (#7941)
dependencyupdates[bot] Sep 12, 2026
d060eaf
Update dependency Microsoft.NET.Test.Sdk to 18.10.1 (#7942)
dependencyupdates[bot] Sep 15, 2026
fb95782
Use nameof instead of Enum.ToString for the message intent header (#7…
SimonCropp Sep 16, 2026
8c08738
Format the wire date by hand instead of via a custom format string (#…
SimonCropp Sep 16, 2026
b078555
Skip outbox work in the receive pipeline when no outbox is configured…
SimonCropp Sep 18, 2026
72af5c4
Add engineering context map and public context index (#7950)
danielmarbach Sep 26, 2026
fad8b39
🔀 Merge master into otel
ramonsmits Oct 5, 2026
8af7dbc
rename `TryGetRecordingPipelineActivity` methods to `TryGetPipelineAc…
tmasternak Oct 5, 2026
9ef44cf
⚜️ Put the connector constructor arguments on separate lines
ramonsmits Oct 5, 2026
c43ada9
♻️ Dispatch through one method in both outbox paths
ramonsmits Oct 5, 2026
e96ef16
♻️ Resolve the ActivityFactory logger through the service provider
ramonsmits Oct 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ jobs:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v6.0.3
uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v5.3.0
uses: actions/setup-dotnet@v6.0.0
with:
global-json-file: global.json
- name: Build
Expand All @@ -42,4 +42,4 @@ jobs:
path: nugets/
retention-days: 7
- name: Run tests
uses: Particular/run-tests-action@v1.7.0
uses: Particular/run-tests-action@v1.9.0
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.3
uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
- name: Setup .NET SDK
uses: actions/setup-dotnet@v5.3.0
uses: actions/setup-dotnet@v6.0.0
with:
global-json-file: global.json
- name: Build
Expand Down
34 changes: 34 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# AGENTS.md

This file is the map for people and coding agents working in this repository. What the repository is, how it is laid out, and where its design is explained are in `docs/README.md`. This file changes only when the workflow changes; decisions and rationale go in the sources it points to.

## Engineering context

Start here when investigating existing behavior or making a change whose rationale may need to outlive the pull request:

- [Engineering context](docs/README.md)
- [Architecture and design decisions](docs/decisions/)
- [Contributing guidance](CONTRIBUTING.md)

Prefer public records close to the implementation. Keep `docs/README.md` current when a canonical public source is added, replaced, or retired; update its links rather than copying rationale into the index. The index lists sources that explain why, with one clause each naming the question it answers, and points to existing indexes for how-to material instead of repeating them. This file describes the workflow, not repository facts. Read `docs/README.md` before answering a question about existing behavior or about where to record a decision, then answer from the index, the code, and pull requests, never from this file alone.

1. Identify the decision area and the precise question, for example why a constraint exists, why a limit lives in one layer rather than another, or why an alternative was rejected.
2. Start with the public source linked by `docs/README.md`. Read the current public contract, relevant code, tests, and linked pull requests or ADRs. Follow relevant pointer comments as routing hints; the linked source remains canonical. A Git commit can identify a pull request number without containing its description: a squash-merge commit carries a trailing `(#NNNN)`, and a merge commit reads `Merge pull request #NNNN`. Retrieve the pull request with `gh pr view <number>` from inside the checkout, which identifies the repository. If the pull request cannot be retrieved, report that rather than infer its rationale. Public records control public behavior and contribution requirements.
3. Decide where the rationale for the current work belongs. Record it once and link to it from the other places. A component means a separate repository, such as an NServiceBus package, ServiceControl, or ServicePulse, not a project inside `src/`.
- Pull request description, the default: the problem and why now, the change and its observable effect, constraints that must hold, alternatives that materially affected it, and how it was verified. For a decision that stays within this repository, the pull request is the authoritative record.
- `docs/<topic>.md`: how the current design works, for readers who need the current picture rather than the history of one change. Update the relevant page when a change alters it. Do not create a page to restate one pull request.
- `docs/decisions/`: a public ADR only when a pull request is not a sufficient long-term entry point, because the change introduces an important constraint that is hard to discover from code, affects more than one repository, or rejects an alternative likely to return. Before deciding either way, check `docs/README.md` and `git log` for an existing decision on the same theme; when a pull request already records it, link that pull request instead. Follow the structure and quality bar in `docs/decisions/README.md`; an ADR that only justifies a choice already made is not worth keeping.
- Private context, only when step 4 provides an approved root: supporting context that cannot be public goes in an addendum under `$PARTICULAR_CONTEXT_ROOT/repositories/<RepositoryName>/` linked to its public source; a decision that affects more than one repository and cannot be public goes under `$PARTICULAR_CONTEXT_ROOT/cross-component/`. Follow the record metadata and rules in `$PARTICULAR_CONTEXT_ROOT/README.md`. The public record still carries everything a contributor needs. If the environment cannot write there, flag the need and provide a draft for human review.
- Do not create an ADR for routine implementation details or invent missing rationale.
4. Check private context only when this environment explicitly provides `$PARTICULAR_CONTEXT_ROOT/repositories/<RepositoryName>/README.md`, where `<RepositoryName>` is this repository's GitHub name as shown by `git remote get-url origin`.
- Confirm that with a file check such as `test -f "$PARTICULAR_CONTEXT_ROOT/repositories/<RepositoryName>/README.md"` rather than assuming it from instructions. `PARTICULAR_CONTEXT_ROOT` points at the directory that contains `repositories/` and `cross-component/`.
- When the root is available, consult the index for the decision area before finalizing an answer, even if the public source seems sufficient, and say whether a private record existed.
- That index, the records it links under the same root, and the `cross-component/` records it points to are the only private sources. Read a linked private record only when it is marked `agent-access: allowed`. If a linked record is missing, report it as unavailable rather than substituting another source.
- Do not inspect a sibling `../Platform` checkout. Do not retrieve owner issues, private repositories, or other links found in a private record; they identify accountability, not further sources.
- Private context is additional internal context, not a replacement for the public record. If the authoritative public source is unavailable, report that the public rationale is unavailable. Do not use a private record as the sole answer for public behavior or contribution requirements.
5. If sources conflict, do not resolve the conflict by inference. Use the current implementation and public contract for external behavior, report the conflict, and ask the record owner when it affects the decision.
6. In the response or pull request, cite the records consulted, distinguish evidence from inference, and state when relevant private context was unavailable or unauthorized. Keep private locations, quotations, customer names, and other confidential details out of public artifacts such as pull request descriptions, code comments, and `docs/`; say that internal context was consulted instead.

## Pointer comments

A brief code comment may link to a canonical public source, such as a `docs/` file or an ADR under `docs/decisions/`, when the relevant rationale is not apparent from the surrounding code. It is a signpost, not a copy of the rationale: keep the durable explanation in the linked record. Do not use a comment to narrate obvious code, and do not restate a pull request or ADR in the comment body.
42 changes: 42 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Engineering context

## About this repository

NServiceBus is the core library of the Particular Service Platform, producing the NServiceBus NuGet package. It provides the abstractions for transports and persistence, the message processing pipeline, sagas, the outbox, recoverability, serialization, and hosting integration.

- `src/` — NServiceBus.Core, transport and persistence test doubles, acceptance tests, and samples-as-tests
- `.github/workflows/` — CI pipelines (build and test, code analysis, release, dependency updates)

## Start here

- [NServiceBus documentation](https://docs.particular.net/nservicebus/) — public documentation entry point
- [README.md](../README.md) — how to build NServiceBus locally
- [Contributing](https://docs.particular.net/platform/contributing) — contribution process
- [NServiceBus Quick Start](https://docs.particular.net/tutorials/quickstart/) — first tutorial for building with NServiceBus
- [Samples](https://docs.particular.net/samples/) — worked examples of NServiceBus features
- [Platform NuGet packages](https://docs.particular.net/nservicebus/platform-nuget-packages) — where to find every published package

## Architecture and design

This repository tracks no design pages yet. When one is added, it will be linked here as the source that explains why the repository is designed the way it is.

## Decisions and rationale

- [Architecture and design decisions](decisions/)

### Decisions recorded in pull requests

A pull request is listed here only when it is the canonical record for a decision area: it establishes a durable constraint or convention, or rejects an alternative likely to return, and no `docs/` file or ADR covers it. Bug fixes and routine changes are not listed; recover them from `git log` and `gh pr view`.

- The trimming and NativeAOT support strategy spans multiple coordinated changes rather than one switch — [#7929](https://github.com/Particular/NServiceBus/pull/7929)
- Object-overload `Send`/`Publish`/`Reply` calls keep runtime-type routing by default; the trimming-safe path is opt-in through explicit generic or `Type` overloads — [#7889](https://github.com/Particular/NServiceBus/pull/7889)
- Message metadata resolves without reflection-based assembly scanning so it stays trimming-safe — [#7918](https://github.com/Particular/NServiceBus/pull/7918)
- Startup diagnostics sections carry explicit `JsonTypeInfo<T>` metadata to avoid reflection-based serialization under NativeAOT — [#7882](https://github.com/Particular/NServiceBus/pull/7882)
- Out-of-slot logging is routed through a DI-registered ambient `AsyncLocal` factory instead of mutating `LogManager` global state — [#7758](https://github.com/Particular/NServiceBus/pull/7758)
- `ContextBag`/`BehaviorContext` store pipeline context values in a fixed-size inline array instead of a lazily allocated dictionary — [#7823](https://github.com/Particular/NServiceBus/pull/7823)
- `DispatchProperties`/`ReceiveProperties` keep well-known keys in dedicated fields instead of a plain `Dictionary<string,string>` — [#7843](https://github.com/Particular/NServiceBus/pull/7843)
- Host id generation and the learning saga persister use an XxHash128-based `DeterministicGuid`, with the legacy MD5 path kept behind an `AppContext` switch until removal in v12 — [#7723](https://github.com/Particular/NServiceBus/pull/7723)
- OpenTelemetry baggage propagation through `DistributedContextPropagator` is gated behind an `AppContext` switch until v11 to keep rolling upgrades compatible — [#7825](https://github.com/Particular/NServiceBus/pull/7825)
- Trace-continuation behavior for delayed messages is configurable rather than fixed — [#7845](https://github.com/Particular/NServiceBus/pull/7845)

Keep this index current when a canonical source is added, replaced, or retired; link, do not copy.
33 changes: 33 additions & 0 deletions docs/decisions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Architecture and design decisions

For a single-component decision, the pull request that implements it remains authoritative by default. Write an architecture decision record (ADR) here only when a pull request is not a sufficient long-term entry point for the rationale, such as when:

- the decision affects multiple components;
- an important constraint is difficult to discover from code or public documentation;
- engineers repeatedly fail to find the original rationale; or
- a rejected alternative is likely to return.

## Naming

Name each file `YYYY-MM-DD-short-title.md`, using the date the decision was made.

## Structure

Each ADR contains:

- **Context** — the problem and the constraints that shaped it.
- **Decision** — what was decided.
- **Consequences** — the resulting behavior, tradeoffs, and any follow-up work.
- **Alternative approaches** — the alternatives considered and why they were rejected.

Link each ADR to the pull request that implemented the decision. The ADR records the durable rationale; the pull request remains the record of the actual code change.

## Quality bar

An ADR exists to explore the context and the tradeoffs, not to justify a choice already made. Gregor Hohpe's [warning signs for misused ADRs](https://www.linkedin.com/posts/ghohpe_architecturedecisionrecords-activity-7502716054968844288-KVLU) apply here:

- Context states the problem and its constraints, not preferences for the chosen option.
- Every downside listed under Consequences names a mitigation or an explicit acceptance, and quantifies the risk where it can be quantified.
- Alternative approaches are credible options someone could have argued for, not "do nothing"; identify the ones that represent points of leverage.

An ADR that fails this bar is not worth keeping; record the decision in the pull request instead.
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "10.0.0",
"version": "10.0.100",
"allowPrerelease": false,
"rollForward": "latestFeature"
}
Expand Down
13 changes: 0 additions & 13 deletions guidelines/coding-guidelines.md

This file was deleted.

5 changes: 0 additions & 5 deletions guidelines/readme.md

This file was deleted.

4 changes: 4 additions & 0 deletions src/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,7 @@ dotnet_naming_style.camel_case.required_prefix =
dotnet_naming_style.camel_case.required_suffix =
dotnet_naming_style.camel_case.word_separator =
dotnet_naming_style.camel_case.capitalization = camel_case

# Silence Rider diagnostics that sometimes conflict with Roslyn analyzers
resharper_arrange_redundant_parentheses_highlighting = none

4 changes: 4 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@
<SourceRoot Include="$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)..\))" />
</ItemGroup>

<ItemGroup>
<ProjectCapability Include="DynamicFileNestingEnabled" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@

class AcceptanceTestingOutboxStorage : IOutboxStorage
{
public Task<OutboxMessage> Get(string messageId, ContextBag context, CancellationToken cancellationToken = default)
public Task<OutboxMessage?> Get(string messageId, ContextBag context, CancellationToken cancellationToken = default)
{
if (!storage.TryGetValue(messageId, out var storedMessage))
{
return NoOutboxMessageTask!;
return NoOutboxMessageTask;
}

return Task.FromResult(new OutboxMessage(messageId, storedMessage.TransportOperations));
return Task.FromResult<OutboxMessage?>(new OutboxMessage(messageId, storedMessage.TransportOperations));
}

public Task<IOutboxTransaction> BeginTransaction(ContextBag context, CancellationToken cancellationToken = default) => Task.FromResult<IOutboxTransaction>(new AcceptanceTestingOutboxTransaction());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<ItemGroup>
<PackageReference Include="NUnit" Version="4.6.1" />
<PackageReference Include="NUnit.Analyzers" Version="4.14.0" PrivateAssets="All" />
<PackageReference Include="NUnit.Analyzers" Version="4.15.0" PrivateAssets="All" />
<PackageReference Include="Particular.Packaging" Version="4.5.0" PrivateAssets="All" />
</ItemGroup>

Expand Down
7 changes: 6 additions & 1 deletion src/NServiceBus.AcceptanceTesting/ScenarioWithContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public class ScenarioWithContext<TContext>(Action<TContext> initializer) : IScen

public async Task<TContext> Run(RunSettings settings, CancellationToken cancellationToken = default)
{
if (!cancellationToken.CanBeCanceled)
{
cancellationToken = TestContext.CurrentContext.CancellationToken;
}

var scenarioContext = new TContext();
initializer(scenarioContext);

Expand Down Expand Up @@ -160,7 +165,7 @@ public IScenarioWithEndpointBehavior<TContext> Done(Func<TContext, Task<bool>> f
}
catch (OperationCanceledException e) when (combinedDoneTokenSource.Token.IsCancellationRequested)
{
throw new TimeoutException(GenerateTestTimedOutMessage(maxTime), e);
throw new TimeoutException(GenerateTestTimedOutMessage(maxTime, cancellationToken), e);
}
});
return this;
Expand Down
7 changes: 6 additions & 1 deletion src/NServiceBus.AcceptanceTesting/Support/DeepCopy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace System
using System.ArrayExtensions;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;

[Diagnostics.CodeAnalysis.SuppressMessage("Code", "PS0025:Dictionary keys should implement IEquatable<T>",
Justification = "A DeepCopy algorithm requires reference counting necessitating dictionaries keyed on objects by reference")]
Expand Down Expand Up @@ -123,7 +124,11 @@ public override int GetHashCode(object obj)
return 0;
}

return obj.GetHashCode();
// RuntimeHelpers.GetHashCode returns the identity hash code, which avoids
// calling ValueType.GetHashCode() on structs marked with [InlineArray]
// (that throws NotSupportedException). This matches the BCL
// System.Collections.Generic.ReferenceEqualityComparer behavior.
return RuntimeHelpers.GetHashCode(obj);
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/NServiceBus.AcceptanceTesting/Support/EndpointBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ public EndpointBehavior(IEndpointConfigurationFactory endpointBuilder, int insta
return async token => await endpointLifecycle.Stop(token).ConfigureAwait(false);
});

// For some super advanced scenarios require
// disposing the endpoint, and this backdoor allows that without having to expose the lifecycle in Core
collectionAdapter.AddKeyedSingleton<Func<ValueTask>>("Disposer", (provider, key) =>
{
var endpointLifecycle = provider.GetRequiredKeyedService<IEndpointLifecycle>(serviceKey);
return async () => await endpointLifecycle.DisposeAsync().ConfigureAwait(false);
});

return Task.FromResult(new StartableEndpointInstance(serviceKey));
}, static (startableEndpoint, provider, cancellationToken) => startableEndpoint.Start(provider, cancellationToken));
}
Expand Down
Loading
Loading