Class ApiClient
Client for the Virtufin API Gateway: dynamic per-service RPC dispatch (service names as
dynamic members, e.g. client.workmanager.SomeMethod()), plus direct methods for
state, pub/sub, triggers and config.
public class ApiClient : DynamicObject, IDynamicMetaObjectProvider, IDisposable
- Inheritance
-
ApiClient
- Implements
- Inherited Members
Examples
using var client = new ApiClient();
var workers = await client.workmanager.ListWorkers();
// Equivalent to:
var workers = await client.InvokeAsync("workmanager", "ListWorkers");
Remarks
Before 0.7.0 this was two classes: a narrow ApiClient (host/port only, no TLS or
API key) whose .Gateway property returned the real, full-featured
GatewayClient. They are merged here — one class, matching this SDK's Python and
TypeScript counterparts more closely than either the two-class or the auth-less shape did
alone. .Gateway is kept, returning this, purely so existing
client.Gateway.<service>.<Method>(...) call sites keep compiling.
client.workmanager triggers TryGetMember(GetMemberBinder, out object?), which creates or returns a
cached ServiceClient for "workmanager". service.ListWorkers() triggers
TryGetMember(GetMemberBinder, out object?), which returns a callable that invokes via the
Gateway's InvokeJson RPC.
Constructors
ApiClient(GrpcChannel)
Creates a new ApiClient from a pre-built gRPC channel -- the escape hatch for anything the host/port/tls/apiKey constructor can't express (a custom Interceptor, a non-default HttpMessageHandler, etc.). Host and HttpPort are not meaningful from a raw channel and are left at their defaults ("localhost", 0).
public ApiClient(GrpcChannel channel)
Parameters
channelGrpcChannelThe gRPC channel to use for communication.
ApiClient(string, int?, bool, string?)
Creates a new ApiClient.
public ApiClient(string host = "localhost", int? grpcPort = null, bool tls = false, string? apiKey = null)
Parameters
hoststringThe host address (default: "localhost").
grpcPortint?The gRPC port (default: DefaultGrpcPort). Previously named
httpPortand, when omitted, defaulted to DefaultHttpPort -- the wrong constant for a channel this class only ever builds as gRPC. No known caller relied on the default (every one passes a port explicitly), but fixed here regardless.tlsboolUse an HTTPS channel, verified against system CA roots.
apiKeystringSent as
x-api-keyon every call, via a default header on the channel's underlying HttpClient. Null sends no key.
Properties
Gateway
Returns this same client. Kept only so client.Gateway.<service>.<Method>(...)
-- the pattern used throughout this org's C# workers and examples before 0.7.0 -- keeps
compiling unmodified. New code should call directly on the client, e.g.
client.workmanager.ListWorkers() instead of client.Gateway.workmanager.ListWorkers().
[Obsolete("ApiClient now exposes gateway methods directly; this property is kept only for source compatibility.")]
public ApiClient Gateway { get; }
Property Value
Host
The host address of the gateway.
public string Host { get; }
Property Value
HttpPort
The gRPC port of the gateway.
public int HttpPort { get; }
Property Value
Methods
Close()
Closes the client synchronously.
public void Close()
CloseAsync()
Closes the client asynchronously.
public Task CloseAsync()
Returns
DeleteBulkStateAsync(string, IEnumerable<string>, bool, ChangeNotification?, CancellationToken)
Deletes multiple state entries for a service.
public Task<DeleteBulkStateResponse> DeleteBulkStateAsync(string service, IEnumerable<string> keys, bool publishChange = false, ChangeNotification? change = null, CancellationToken cancellationToken = default)
Parameters
servicestringkeysIEnumerable<string>publishChangeboolIf true, a single state.change event is published for the whole bulk. Default false.
changeChangeNotificationOptional. See SaveStateAsync(string, string, string, string?, bool, bool, ChangeNotification?, CancellationToken) for what this selects.
cancellationTokenCancellationToken
Returns
- Task<DeleteBulkStateResponse>
DeleteStateAsync(string, string, bool, bool, ChangeNotification?, CancellationToken)
Deletes a state entry and broadcasts a delete event to subscribers asynchronously.
public Task<DeleteStateResponse> DeleteStateAsync(string service, string key, bool publishChange = false, bool includeValue = false, ChangeNotification? change = null, CancellationToken cancellationToken = default)
Parameters
servicestringThe service name.
keystringThe state key.
publishChangeboolIf true, a state.change event is published. Default false.
includeValueboolIf true, the last value is included in the state change event payload. Only relevant when publishChange=true.
changeChangeNotificationOptional. See SaveStateAsync(string, string, string, string?, bool, bool, ChangeNotification?, CancellationToken) for what this selects.
cancellationTokenCancellationTokenCancellation token.
Returns
- Task<DeleteStateResponse>
DeleteStateResponse with success status.
DeleteTriggerAsync(string, CancellationToken)
Deletes a scheduled trigger.
public Task<DeleteTriggerResponse> DeleteTriggerAsync(string name, CancellationToken cancellationToken = default)
Parameters
namestringcancellationTokenCancellationToken
Returns
- Task<DeleteTriggerResponse>
Dispose()
Disposes of the client resources.
public void Dispose()
DisposeAsync()
Disposes of the client resources asynchronously.
public ValueTask DisposeAsync()
Returns
GetBulkStateAsync(string, IEnumerable<string>, CancellationToken)
Gets multiple state values for a service and list of keys.
public Task<List<StateItemDto>> GetBulkStateAsync(string service, IEnumerable<string> keys, CancellationToken cancellationToken = default)
Parameters
servicestringkeysIEnumerable<string>cancellationTokenCancellationToken
Returns
GetConfigServiceAsync(string, CancellationToken)
Gets one service's configuration. Throws RpcException with
NotFound if the name is not registered.
public Task<GetConfigServiceResponse> GetConfigServiceAsync(string name, CancellationToken cancellationToken = default)
Parameters
namestringcancellationTokenCancellationToken
Returns
- Task<GetConfigServiceResponse>
GetService(string)
Gets a client for a specific service.
public ServiceClient GetService(string name)
Parameters
namestringThe service name.
Returns
- ServiceClient
A ServiceClient for the service.
Remarks
ServiceClients are cached internally. Calling this method multiple times with the same service name returns the same cached instance.
GetStateAsync(string, string, CancellationToken)
Gets a single state value asynchronously by service and key.
public Task<(string Value, string Etag)> GetStateAsync(string service, string key, CancellationToken cancellationToken = default)
Parameters
servicestringThe service name.
keystringThe state key.
cancellationTokenCancellationTokenCancellation token.
Returns
GetTriggerAsync(string, CancellationToken)
Retrieves a scheduled trigger's details.
public Task<GetTriggerResponse> GetTriggerAsync(string name, CancellationToken cancellationToken = default)
Parameters
namestringcancellationTokenCancellationToken
Returns
- Task<GetTriggerResponse>
InvokeAsync(string, string, Dictionary<string, object?>?)
Invokes a method on a service asynchronously.
public Task<Dictionary<string, object?>> InvokeAsync(string service, string method, Dictionary<string, object?>? requestData = null)
Parameters
servicestringThe service name.
methodstringThe method name.
requestDataDictionary<string, object>Optional request data as dictionary.
Returns
- Task<Dictionary<string, object>>
The response as a dictionary.
Remarks
The polymorphic Dictionary<string, object?>
payload is (de)serialized via Virtufin.Api.Client.ApiClient.JsonOptions,
which sets an explicit DefaultJsonTypeInfoResolver
so reflection-based dispatch works regardless of the
process-wide IsReflectionEnabledByDefault flag.
See Virtufin.Api.Client.ApiClient.JsonOptions for the AOT caveat.
Exceptions
- InvalidOperationException
Thrown when the invocation fails.
ListConfigServicesAsync(CancellationToken)
Lists every registered service, including non-dialable entries (those that exist only to resolve Dapr component names).
public Task<ListConfigServicesResponse> ListConfigServicesAsync(CancellationToken cancellationToken = default)
Parameters
cancellationTokenCancellationToken
Returns
- Task<ListConfigServicesResponse>
Remarks
Contrast ListServicesAsync(), which returns only the backends the gateway can actually invoke.
ListMethodsAsync(string)
Lists all methods for a given service asynchronously.
public Task<List<Dictionary<string, object?>>> ListMethodsAsync(string service)
Parameters
servicestringThe service name.
Returns
- Task<List<Dictionary<string, object>>>
List of method information dictionaries.
ListServicesAsync()
Lists all available services asynchronously.
public Task<List<string>> ListServicesAsync()
Returns
ListTriggersAsync(CancellationToken)
Lists all scheduled triggers.
public Task<ListTriggersResponse> ListTriggersAsync(CancellationToken cancellationToken = default)
Parameters
cancellationTokenCancellationToken
Returns
- Task<ListTriggersResponse>
PublishEventAsync(string, CloudEvent, CancellationToken)
Publishes a CloudEvent to a topic asynchronously.
public Task<PublishResponse> PublishEventAsync(string topic, CloudEvent cloudevent, CancellationToken cancellationToken = default)
Parameters
topicstringThe topic name.
cloudeventCloudEventThe CloudEvent proto to publish.
cancellationTokenCancellationTokenCancellation token.
Returns
- Task<PublishResponse>
PublishResponse with success status.
PublishWithResultAsync(string, CloudEvent, string, TimeSpan?, string?, CancellationToken)
Publishes to a topic and waits for a correlated response on a reply topic.
Implements the request-reply pattern over pub/sub using correlation IDs.
Sets correlationid and replytopic as CloudEvent attributes
before publishing.
public Task<SubscribeResponse> PublishWithResultAsync(string topic, CloudEvent cloudevent, string replyTopic, TimeSpan? timeout = null, string? correlationId = null, CancellationToken cancellationToken = default)
Parameters
topicstringThe topic to publish the request to.
cloudeventCloudEventThe CloudEvent proto to publish.
replyTopicstringThe topic to listen for responses on.
timeoutTimeSpan?Maximum time to wait for a response (default: 30s).
correlationIdstringOptional correlation ID (auto-generated if null).
cancellationTokenCancellationTokenCancellation token.
Returns
- Task<SubscribeResponse>
The correlated SubscribeResponse.
Exceptions
- TimeoutException
Thrown if no response arrives within the timeout.
QueryStateAsync(string, string, int, CancellationToken)
Gets all state key-value pairs asynchronously for a service.
public Task<List<StateItemDto>> QueryStateAsync(string service, string query, int limit = 0, CancellationToken cancellationToken = default)
Parameters
servicestringThe service name.
querystringThe Dapr JSON query string.
limitintMax results (0 = no limit).
cancellationTokenCancellationTokenCancellation token.
Returns
- Task<List<StateItemDto>>
List of state items with key, value, etag.
SaveStateAsync(string, string, string, string?, bool, bool, ChangeNotification?, CancellationToken)
Saves state and broadcasts a change event to subscribers asynchronously.
public Task<SaveStateResponse> SaveStateAsync(string service, string key, string value, string? etag = null, bool publishChange = false, bool includeValue = false, ChangeNotification? change = null, CancellationToken cancellationToken = default)
Parameters
servicestringThe service name.
keystringThe state key.
valuestringThe state value.
etagstringOptional etag for concurrency.
publishChangeboolIf true, a state.change event is published. Default false.
includeValueboolIf true, the value is included in the state change event payload. Only relevant when publishChange=true.
changeChangeNotificationOptional. With
publishChange, selects where the notification goes. Unset means the Tier 0state.changetopic, correct for infra state. For domain state (positions, portfolios, orders) supply aChangeNotificationcarrying both a topic and a CloudEvent: the API publishes that event verbatim after the write and skipsstate.change. It cannot build the event itself -- it has the key and the bytes but not the scenario, world markers, clock type, or your service identity. Tier 0 events carry no version, so consuming the value without a read-back assumes writes to that key are serialized; carry a monotonic token in your own event if you need ordering. Publication is at-most-once and not atomic with the write.cancellationTokenCancellationTokenCancellation token.
Returns
- Task<SaveStateResponse>
SaveStateResponse with success status.
ScheduleTriggerAsync(string, string, string?, string?, int, string?, CancellationToken)
Schedules a recurring trigger. When it fires, the API publishes an empty
CloudEvent to targetTopic.
public Task<ScheduleTriggerResponse> ScheduleTriggerAsync(string name, string targetTopic, string? schedule = null, string? dueTime = null, int repeats = 0, string? ttl = null, CancellationToken cancellationToken = default)
Parameters
namestringTrigger name, unique per deployment.
targetTopicstringTopic the fired trigger publishes to.
schedulestringA 6-field cron expression or an
@everyduration.dueTimestringOptional first-fire time.
repeatsintOptional repeat count; 0 means unlimited.
ttlstringOptional time-to-live.
cancellationTokenCancellationTokenCancellation token.
Returns
- Task<ScheduleTriggerResponse>
Remarks
Errors are in-band: the gRPC status is OK and failure is signalled by
status.success == false. Check it.
Subscribe(IEnumerable<string>?, CancellationToken)
Subscribes to one or more pub/sub topics.
public AsyncServerStreamingCall<SubscribeResponse> Subscribe(IEnumerable<string>? topics = null, CancellationToken cancellationToken = default)
Parameters
topicsIEnumerable<string>Topics to subscribe to. Filtering is by topic only --
SubscribeRequestcarries no service or event-type filter, so discriminate further oncloudevent.type. An empty list is not "all topics": the server defaults it tostate.change, so name your topics explicitly. (servicesandeventTypesparameters were removed -- they were accepted, documented as filters, and silently discarded.)cancellationTokenCancellationTokenCancellation token.
Returns
- AsyncServerStreamingCall<SubscribeResponse>
The async call handle. Dispose to cancel subscription.
SubscribeAsync(IStreamEventHandler, IEnumerable<string>?, CancellationToken)
Subscribes to events with a handler callback.
public Task SubscribeAsync(IStreamEventHandler handler, IEnumerable<string>? topics = null, CancellationToken cancellationToken = default)
Parameters
handlerIStreamEventHandlerHandler to receive events.
topicsIEnumerable<string>Topics to subscribe to. Filtering is by topic only --
SubscribeRequestcarries no service or event-type filter, so discriminate further oncloudevent.type. An empty list is not "all topics": the server defaults it tostate.change, so name your topics explicitly. (servicesandeventTypesparameters were removed -- they were accepted, documented as filters, and silently discarded.)cancellationTokenCancellationTokenCancellation token.
Returns
- Task
Task that completes when subscription is cancelled.
SubscribeToTopic(string, CancellationToken)
Subscribes to a pub/sub topic and streams events.
public AsyncServerStreamingCall<SubscribeResponse> SubscribeToTopic(string topic, CancellationToken cancellationToken = default)
Parameters
topicstringThe topic name.
cancellationTokenCancellationTokenCancellation token.
Returns
- AsyncServerStreamingCall<SubscribeResponse>
Async streaming call for SubscribeResponse. Dispose to cancel.
TryGetMember(GetMemberBinder, out object?)
Dynamic property access returns a ServiceClient for the named service.
public override bool TryGetMember(GetMemberBinder binder, out object? result)
Parameters
binderGetMemberBinderresultobject
Returns
UnsubscribeFromTopicAsync(string, CancellationToken)
Unsubscribes from a pub/sub topic.
public Task<UnsubscribeResponse> UnsubscribeFromTopicAsync(string subscriptionId, CancellationToken cancellationToken = default)
Parameters
subscriptionIdstringThe subscription ID to cancel.
cancellationTokenCancellationTokenCancellation token.
Returns
- Task<UnsubscribeResponse>
UnsubscribeResponse with success status.