HostLoom.Analyzers
0.4.0
See the version list below for details.
dotnet add package HostLoom.Analyzers --version 0.4.0
NuGet\Install-Package HostLoom.Analyzers -Version 0.4.0
<PackageReference Include="HostLoom.Analyzers" Version="0.4.0" />
<PackageVersion Include="HostLoom.Analyzers" Version="0.4.0" />
<PackageReference Include="HostLoom.Analyzers" />
paket add HostLoom.Analyzers --version 0.4.0
#r "nuget: HostLoom.Analyzers, 0.4.0"
#:package HostLoom.Analyzers@0.4.0
#addin nuget:?package=HostLoom.Analyzers&version=0.4.0
#tool nuget:?package=HostLoom.Analyzers&version=0.4.0
HostLoom.Analyzers
Roslyn analyzers for correct asynchronous and dependency-injection usage of HostLoom. The package contains compiler analyzers only: it adds no runtime assembly or dependency to the application.
dotnet add package HostLoom.Analyzers
For central package management:
<PackageReference Include="HostLoom.Analyzers" PrivateAssets="all" />
Rules
HLM0001
Pass an available cancellation token to HostLoom asynchronous calls. The analyzer recognizes both
a CancellationToken parameter and an IPipeContext.CancellationToken available from an enclosing
pipeline filter or helper. The cache and lock contracts (ICache, IDistributedLock,
ILockHandle) are recognized by name, so the rule covers them whether the call goes through the
real package or a test stub of the interface.
await client.GetResponseAsync(
"orders",
request,
cancellationToken: cancellationToken
);
HLM0002
Await HostLoom asynchronous operations instead of blocking through .Result, .Wait(), or
.GetAwaiter().GetResult(). The rule also recognizes .AsTask() over a HostLoom ValueTask, and
covers the cache and lock contracts, whose members all return ValueTask.
HLM0003
Register implementations of IRequestHandler<,>, IEventHandler<>, and IRequestBehavior<,> as
scoped services. HostLoom creates a dependency-injection scope per delivery; a singleton handler or
behavior can share mutable state between deliveries or capture scoped dependencies. AddHandler,
AddSubscriber, and AddBehavior already apply the correct scoped lifetime.
HLM0004
Assign every settable member of a mapped destination. An explicit map makes a forgotten member a silent data loss rather than a compile error — nothing requires the member to be written — which is the one axis on which explicit mapping is less safe than the convention mapping it replaces. A member supplied through the destination's constructor counts as assigned, so positional records and contracts with real constructors need nothing extra.
Omitting a member is often correct. Name each one, so that a member added to the contract later is still reported rather than excused by a blanket marker:
[UnmappedMembers(nameof(CfaTransfer.CardMask), nameof(CfaTransfer.ProviderId))]
public sealed class TransferModelToCfaTransferMapper : IMapper<TransferModel, CfaTransfer>
HLM0005
Keep a Map body in a shape completeness can be verified in. Two are recognised:
- the destination constructed and returned directly, with an object initializer;
- one local constructed, assigned into across any number of statements and branches, and returned.
A body outside both — the local passed to a method, built across two locals, or returned from somewhere else — is reported rather than skipped, so that "not checked" is never mistaken for "checked and complete". Conditional assignment counts as assigned: the rule targets forgotten members, and evidence that the author considered one is the whole signal.
Known blind spot. A map whose destination is a type parameter — a generic map class closed
through MappingBuilder.Add<TSource, TDestination>(factory) — cannot have its members enumerated,
so it is skipped silently and reports neither rule. Completeness of a generic map is not checked.
HLM0006
Do not capture the scoped IMapper dispatcher in a singleton. AddHostLoomMapping registers the
non-generic dispatcher scoped, so a singleton or an IHostedService that takes one is a captive
dependency — and the failure is asymmetric: it throws at host build where scope validation is
enabled, the generic host's default in Development, and succeeds where it is not. Left to run time
it is a Development-only failure that Production would not reproduce.
Inject the closed IMapper<TSource, TDestination> instead, which is transient and carries no such
restriction, or take IServiceScopeFactory and resolve per unit of work. The rule reports only the
non-generic dispatcher; the closed map it points at is never reported.
HLM0007
Hash a secret before it becomes part of a cache or lock key. A key is written to the backend,
appears in logs, and is tagged on spans, so a key built from a token, secret, password, or API key
copies the credential into all three. The rule reports an interpolation hole, a concatenation
operand, or a string.Format, string.Concat, or string.Join argument of the key (or keys)
argument of an ICache or IDistributedLock member that references a parameter, local, field, or
property whose name contains token, secret, password, refreshToken, or apiKey. Wrap the
value in CacheKey.FromSensitive or LockKey.FromSensitive, which hashes it so the key stays
unique without carrying the secret:
await cache.GetOrCreateAsync(
$"session:{CacheKey.FromSensitive(refreshToken)}",
token => LoadSessionAsync(token),
TimeSpan.FromMinutes(5),
cancellationToken
);
A key that is entirely a FromSensitive call is never reported. A CancellationToken operand is
ignored even though its name contains token.
HLM0008
Forward the cancellation token a get-or-create factory receives. GetOrCreateAsync hands the
caller's token to the factory so the work it starts stops with the request; a factory that names
the token and never uses it keeps running after the caller has gone, holding the per-key guard
while it does. The rule reports a lambda, anonymous method, or method group whose
CancellationToken parameter is never referenced in its body, including from nested lambdas. Name
the parameter _ to state that the factory has nothing to cancel.
await cache.GetOrCreateAsync("catalog", token => LoadCatalogAsync(token), options, cancellationToken);
await cache.GetOrCreateAsync("constant", _ => ValueTask.FromResult(42), options, cancellationToken);
Configuration
All rules are warnings by default and use the HLM diagnostic prefix. Standard .editorconfig
configuration can change a rule's severity:
dotnet_diagnostic.HLM0001.severity = error
Generated code is ignored, and analyzer execution is safe for concurrent compiler execution.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.20.0 | 226 | 10/31/2026 |
| 0.19.0 | 109 | 10/29/2026 |
| 0.18.0 | 135 | 10/27/2026 |
| 0.17.0 | 149 | 10/25/2026 |
| 0.16.1 | 134 | 10/22/2026 |
| 0.16.0 | 178 | 10/14/2026 |
| 0.15.1 | 128 | 10/12/2026 |
| 0.15.0 | 183 | 10/4/2026 |
| 0.14.0 | 106 | 10/4/2026 |
| 0.13.0 | 138 | 9/28/2026 |
| 0.12.0 | 141 | 9/27/2026 |
| 0.11.0 | 138 | 9/25/2026 |
| 0.10.0 | 131 | 9/22/2026 |
| 0.9.0 | 113 | 9/22/2026 |
| 0.8.0 | 145 | 9/19/2026 |
| 0.7.0 | 125 | 9/17/2026 |
| 0.6.0 | 126 | 9/6/2026 |
| 0.5.0 | 120 | 9/5/2026 |
| 0.4.0 | 120 | 9/3/2026 |
| 0.3.0 | 130 | 8/28/2026 |