Low level Transport example
This page demonstrates how to use the low level transport to send requests.
public class MyRequestParameters : RequestParameters
{
public bool Pretty
{
get => Q("pretty");
init => Q("pretty", value);
}
}
using Elastic.Transport;
var body = """
{
"name": "my-api-key",
"expiration": "1d",
"...": "..."
}
""";
MyRequestParameters requestParameters = new()
{
Pretty = true
};
var pathAndQuery = requestParameters.CreatePathWithQueryStrings("/_security/api_key",
client.ElasticsearchClientSettings);
var endpointPath = new EndpointPath(Elastic.Transport.HttpMethod.POST, pathAndQuery);
// Or, if the path does not contain query parameters:
// new EndpointPath(Elastic.Transport.HttpMethod.POST, "my_path")
var response = await client.Transport
.RequestAsync(
endpointPath,
PostData.String(body),
null,
null,
cancellationToken: default)
.ConfigureAwait(false);
The OnBeforeRequest
callback in IElasticsearchClientSettings
can be used to dynamically modify requests.
var settings = new ElasticsearchClientSettings(new Uri("http://localhost:9200))
.OnBeforeRequest(OnBeforeRequest);
RequestConfiguration? globalRequestConfiguration = null;
ConditionalWeakTable? globalRequestConfigurations = null;
void OnBeforeRequest(ElasticsearchClient client, Request request, EndpointPath endpointPath, ref PostData? postData, ref IRequestConfiguration? requestConfiguration)
{
// Each time a request is made, the transport creates a new `BoundConfiguration` for every `IRequestConfiguration`
// that is not in the cache (based on reference equality).
// To prevent frequent allocations of our mutated request configurations (and the secondary allocations for
// `BoundConfiguration`), we have to maintain a custom cache that maps every original request configuration to the
// mutated one.
if (requestConfiguration is null)
{
globalRequestConfiguration = Interlocked.CompareExchange(
ref globalRequestConfiguration,
new RequestConfiguration
{
UserAgent = UserAgent.Create("my-custom-user-agent")
},
null) ?? globalRequestConfiguration;
requestConfiguration = globalRequestConfiguration;
return;
}
if (requestConfiguration is not RequestConfiguration rc)
{
// Only `RequestConfiguration` (not all implementations of `IRequestConfiguration`) gets cached in the
// internal cache.
requestConfiguration = MutateRequestConfiguration(requestConfiguration);
return;
}
// ReSharper disable InconsistentlySynchronizedField
var cache = (Interlocked.CompareExchange(
ref globalRequestConfigurations,
new ConditionalWeakTable(),
null
) ?? globalRequestConfigurations);
if (cache.TryGetValue(rc, out var mutatedRequestConfiguration))
{
requestConfiguration = mutatedRequestConfiguration;
return;
}
mutatedRequestConfiguration = MutateRequestConfiguration(rc);
#if NET8_0_OR_GREATER
cache.TryAdd(rc, mutatedRequestConfiguration);
#else
lock (cache)
{
cache.Add(rc, mutatedRequestConfiguration);
}
#endif
// ReSharper restore InconsistentlySynchronizedField
return;
RequestConfiguration MutateRequestConfiguration(IRequestConfiguration requestConfiguration)
{
return new RequestConfiguration(requestConfiguration)
{
UserAgent = UserAgent.Create("my-custom-user-agent")
};
}
}
- Register the
OnBeforeRequest
callback.