5.5 KiB
.NET 10 C# Client Detailed Design
Purpose
Provide an idiomatic .NET 10 C# client library for MXAccess Gateway, plus a test CLI and unit tests. This client is for modern .NET callers and must not load MXAccess COM.
Follow the C# Style Guide for handwritten code and the Protobuf Style Guide for generated contract inputs.
Projects
Recommended layout:
clients/dotnet/
MxGateway.Client/
MxGateway.Client.csproj
GatewayClient.cs
MxGatewaySession.cs
MxGatewayClientOptions.cs
Authentication/
Conversion/
Errors/
Generated/
MxGateway.Client.Cli/
MxGateway.Client.Cli.csproj
Program.cs
Commands/
MxGateway.Client.Tests/
MxGateway.Client.Tests.csproj
MxGateway.Client.IntegrationTests/
MxGateway.Client.IntegrationTests.csproj
Target framework:
<TargetFramework>net10.0</TargetFramework>
Expected packages:
Grpc.Net.ClientGoogle.ProtobufGrpc.Toolsfor generationMicrosoft.Extensions.Logging.AbstractionsSystem.CommandLineor similar for CLI- test framework: xUnit or NUnit
Library API
Suggested public types:
public sealed class MxGatewayClient : IAsyncDisposable
{
public static MxGatewayClient Create(MxGatewayClientOptions options);
public Task<MxGatewaySession> OpenSessionAsync(
OpenSessionOptions? options = null,
CancellationToken cancellationToken = default);
public Task<MxCommandReply> InvokeAsync(
MxCommandRequest request,
CancellationToken cancellationToken = default);
}
public sealed class MxGatewaySession : IAsyncDisposable
{
public string SessionId { get; }
public Task<int> RegisterAsync(string clientName, CancellationToken ct = default);
public Task UnregisterAsync(int serverHandle, CancellationToken ct = default);
public Task<int> AddItemAsync(int serverHandle, string item, CancellationToken ct = default);
public Task<int> AddItem2Async(int serverHandle, string item, string context, CancellationToken ct = default);
public Task AdviseAsync(int serverHandle, int itemHandle, CancellationToken ct = default);
public Task UnAdviseAsync(int serverHandle, int itemHandle, CancellationToken ct = default);
public Task WriteAsync(int serverHandle, int itemHandle, MxValue value, int userId, CancellationToken ct = default);
public IAsyncEnumerable<MxEvent> StreamEventsAsync(CancellationToken ct = default);
public Task CloseAsync(CancellationToken ct = default);
}
Generated protobuf types should remain available under a generated namespace. Handwritten wrappers should not hide raw replies.
Options
public sealed class MxGatewayClientOptions
{
public required Uri Endpoint { get; init; }
public required string ApiKey { get; init; }
public bool UseTls { get; init; }
public string? CaCertificatePath { get; init; }
public string? ServerNameOverride { get; init; }
public TimeSpan ConnectTimeout { get; init; } = TimeSpan.FromSeconds(10);
public TimeSpan DefaultCallTimeout { get; init; } = TimeSpan.FromSeconds(30);
public ILoggerFactory? LoggerFactory { get; init; }
}
API key may be loaded from MXGATEWAY_API_KEY by the CLI, not implicitly by the
library constructor unless a helper explicitly says it does that.
Auth Interceptor
Use a gRPC call credentials/interceptor layer to attach:
authorization: Bearer <api key>
The interceptor must redact the key in logs and exceptions.
Streaming
Expose StreamEventsAsync as IAsyncEnumerable<MxEvent>. On cancellation,
cancel the gRPC stream and surface OperationCanceledException only when the
caller initiated cancellation.
Do not reorder events.
Error Handling
Recommended exceptions:
MxGatewayException
MxGatewayAuthenticationException
MxGatewayAuthorizationException
MxGatewaySessionException
MxGatewayWorkerException
MxGatewayCommandException
MxAccessException
For command replies that include MXAccess HRESULT/status, prefer returning the reply and exposing helper methods:
reply.EnsureProtocolSuccess();
reply.EnsureMxAccessSuccess();
Test CLI
Project: MxGateway.Client.Cli.
Command examples:
mxgw-dotnet version
mxgw-dotnet smoke --endpoint http://localhost:5000 --api-key-env MXGATEWAY_API_KEY --item TestChildObject.TestInt
mxgw-dotnet stream-events --session-id <id> --json
mxgw-dotnet write --session-id <id> --server-handle 1 --item-handle 1 --type int32 --value 123
The CLI should use System.CommandLine or a similarly testable parser. JSON
output should be deterministic and redact API keys.
Unit Tests
Use an in-process fake gRPC service with Grpc.AspNetCore.Server test host or
mock the generated client behind an internal interface.
Required tests:
- auth metadata is attached,
- API key is redacted,
- options build plaintext and TLS channels correctly,
RegisterAsyncbuilds the right command payload,AddItem2Asyncincludes context,WriteAsyncconverts scalar and array values,- command reply status helpers preserve MXAccess HRESULT,
StreamEventsAsyncyields ordered events,- stream cancellation disposes the call,
- CLI parsing and JSON output.
Integration Tests
Use xUnit traits or categories. Skip unless:
MXGATEWAY_INTEGRATION=1
MXGATEWAY_ENDPOINT=<endpoint>
MXGATEWAY_API_KEY=<key>
MXGATEWAY_TEST_ITEM=<item>
Integration smoke should open, register, add, advise, stream for bounded time, and close.