RESP010: share a long-lived client
RespireClient multiplexes connections and is safe to share across concurrent
operations. Creating and disposing one for each request repeats connection setup
and prevents reuse of its connection pools and caches.
async Task<string?> ReadAsync()
{
// RESP010
await using var client = await RespireClient.ConnectAsync("localhost");
return await client.GetStringAsync("key");
}
Create the client during application startup, or register it with
dependency injection, then inject
IRespireClient into request handlers. The application owns its disposal.
Task<string?> ReadAsync(IRespireClient client)
=> client.GetStringAsync("key").AsTask();
The bundled warning recognizes Create, ConnectAsync, and ConnectAnyAsync
inside loops, and in using / await using declarations or statements inside
methods. It leaves field initializers, factories returning a client, and the
application entry point's outer lifetime alone. Loop checks stop at nested
function boundaries. Top-level using declarations are outside the ownership
check, but client creation in top-level loops is still checked.
The ownership check also follows a local initialized by a creation call into a
later using statement or declaration in the same block, provided the local is
not written in the intervening statements or the disposal statement. It does not
follow chains of aliases or disposal inside a nested function or another block.
It does not infer DI service scopes, trace custom factories,
or prove how frequently a method runs.
For a deliberate isolated client (for example, a connectivity probe), suppress
the warning locally with #pragma warning disable RESP010 and restore it after
the creation. An application-lifetime owner method other than Main may also
need this suppression. No automatic code fix is offered: moving ownership into
application startup requires choosing its configuration and disposal lifetime.
To change its severity in .editorconfig:
dotnet_diagnostic.RESP010.severity = suggestion