DcsvIo.D2.Result.Grpc
0.1.1
dotnet add package DcsvIo.D2.Result.Grpc --version 0.1.1
NuGet\Install-Package DcsvIo.D2.Result.Grpc -Version 0.1.1
<PackageReference Include="DcsvIo.D2.Result.Grpc" Version="0.1.1" />
<PackageVersion Include="DcsvIo.D2.Result.Grpc" Version="0.1.1" />
<PackageReference Include="DcsvIo.D2.Result.Grpc" />
paket add DcsvIo.D2.Result.Grpc --version 0.1.1
#r "nuget: DcsvIo.D2.Result.Grpc, 0.1.1"
#:package DcsvIo.D2.Result.Grpc@0.1.1
#addin nuget:?package=DcsvIo.D2.Result.Grpc&version=0.1.1
#tool nuget:?package=DcsvIo.D2.Result.Grpc&version=0.1.1
DcsvIo.D2.Result.Grpc
Faithful in-memory → wire → in-memory D2Result round-trip over a gRPC
D2ResultProto response envelope. Every service handler returns a D2Result
as-is; the framework wraps it; the consumer re-materializes an equal D2Result
on the other side — zero caller try-catch for business failures.
Install
dotnet add package DcsvIo.D2.Result.Grpc
Core API
// Server side: wrap
var response = new FindThingsResponse
{
Result = result.ToProto(),
};
response.Data.AddRange(things);
return response;
// Consumer side: re-materialize
var res = await client.FindThings(req).HandleAsync(r => r.Result, r => r.Data);
if (res.Category == ErrorCategory.NotFound) { /* typed, no registry lookup */ }
res.StatusCode == HttpStatusCode.Conflict; // exact HTTP status, not a lossy gRPC bucket
Key properties
- Full fidelity: every field —
Success,StatusCode(exact integer),ErrorCode,Category,Messages(key + params),InputErrors,TraceId,Data— round-trips equal. - Typed
ErrorCategory: populated by factories at generation time.ErrorCategory.NotFoundis available directly on the rebuilt result; no runtime registry lookup on the hot path. TKMessageProto: structured message carrier (key+map<string,string> params). Full parameter fidelity — aTKMessagewith substitution bindings survives the round-trip unchanged.- Transport fault fail-open:
RpcException→ServiceUnavailable;Cancelled→Canceled; any otherException→UnhandledException. User-facing messages stay the factory TK constants — never raw transport strings. - PII-safe logging:
[LoggerMessage]signatures do NOT acceptException. Transport detail is logged viaSanitizedExceptionRender.TypeName+FirstFrame+StatusCode— neverex.Message(which can embed AMQP URIs, JWT contents, configured secrets). IsTransientGrpcException: classifiesDeadlineExceeded,ResourceExhausted,Aborted,Internal,Unavailableas transient for retry callers.
Wire mechanism boundary
Two mechanisms coexist on every gRPC call — each has a distinct role and must not be conflated:
| Mechanism | What it carries | gRPC status on the wire | Who reads it |
|---|---|---|---|
D2ResultProto response envelope (this lib) |
Business results — both success and failure. A handler returning NotFound() or ValidationFailed() produces a normal gRPC OK response; the failure detail rides inside the D2ResultProto result envelope field. |
gRPC OK (status 0) + response body |
HandleAsync / ToD2Result<T> — caller gets a clean D2Result with zero try-catch for business failures |
RpcException + D2GrpcTrailers (host-supplied auth/transport binding) |
Transport/auth rejections — JWT validation failure, JWKS unavailable, scope insufficient. These are genuine transport-layer faults, not handler outcomes. | Non-OK gRPC status (Unauthenticated (16) or Unavailable (14)) + trailers (d2_error_code / d2_messages / traceId) |
Auth middleware on the server side; retry/circuit-breaker on the client side |
Boundary rule: a 401 from the JWT interceptor is RpcException(Unauthenticated) — never a D2ResultProto{ success=false, status_code=401 }. A 404 from a handler is D2ResultProto{ success=false, status_code=404 } — never an RpcException. The two paths are structurally separate and must stay that way.
Proto contract
The shared d2_result.proto contract is the single source of truth. Generated
D2ResultProto / TKMessageProto / InputErrorProto types live in namespace
D2.Services.Protos.Common.V1.
Dependencies
DcsvIo.D2.Result— result-core (D2Result,InputError,TKMessagesurface)DcsvIo.D2.ErrorCodes.Category—ErrorCategory,ErrorCategoryWireDcsvIo.D2.Utilities—Falsey()null-guardDcsvIo.D2.I18n.Abstractions—TKMessagector (InternalsVisibleTo)Google.Protobuf— proto runtimeGrpc.Net.Client—AsyncUnaryCall<T>,RpcException
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- DcsvIo.D2.ErrorCodes.Category (>= 0.1.1)
- DcsvIo.D2.I18n.Abstractions (>= 0.1.1)
- DcsvIo.D2.Result (>= 0.1.1)
- DcsvIo.D2.Utilities (>= 0.1.1)
- dotenv.net (>= 4.0.2)
- Google.Protobuf (>= 3.30.2)
- Grpc.Net.Client (>= 2.71.0)
- JetBrains.Annotations (>= 2025.2.4)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.