# elastic-transport-net **Repository Path**: mirrors_elastic/elastic-transport-net ## Basic Information - **Project Name**: elastic-transport-net - **Description**: Transport classes and utilities shared among .NET Elastic client libraries - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-10-23 - **Last Updated**: 2025-08-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # `Elastic.Transport` Transport classes and utilities shared among .NET Elastic client libraries This library was lifted from [elasticsearch-net](https://github.com/elastic/elasticsearch-net) and then transformed to be used across all Elastic services rather than only Elasticsearch. Provides the clients connectivity components, exposes a (potentially) cluster aware request pipeline that can be resilient to nodes dropping in & out of rotation. This package is heavily optimized for the Elastic (elastic.co) product suite and Elastic Cloud (cloud.elastic.co) SAAS offering. The transport is designed to fail over fast and in constant time. If a `Node` is considered bad it will fail-over only immediately given the overall request timeout allows for it. It's an explicit non-goal to introduce full (incremental) retry mechanisms. This library is too generic to be making these decisions and should be pushed on to the products/libraries making use of `Elastic.Transport` ## Usage This library can be used on its own but is typically used as the heart of a facade client that models all the API endpoints. In its most direct and terse form you can use the following to create requests. ```c# var settings = new TransportConfiguration(new Uri("http://localhost:9200")); var transport = new Transport(settings); var response = transport.Get("/"); var headResponse = transport.Head("/"); ``` `Get` and `Head` are extension methods to the only method `HttpTransport` dictates namely `Request()` and its async variant. Wrapping clients most likely will list out all `components` explicitly and use `Transport` ```c# var pool = new StaticConnectionPool(new[] {new Node(new Uri("http://localhost:9200"))}); var connection = new HttpConnection(); var serializer = LowLevelRequestResponseSerializer.Instance; var product = ElasticsearchProductRegistration.Default; var settings = new TransportConfiguration(pool, connection, serializer, product); var transport = new Transport(settings); var response = transport.Request(HttpMethod.GET, "/"); ``` This allows implementers to extend `TransportConfiguration` with product/service specific configuration. ### Components `HttpTransport` itself only defines `Request()` and `RequestAsync()` and all wrapping clients accept an `HttpTransport`. The `HttpTransport` implementation that this library ships models a request pipeline that can deal with a large variety of topologies ![request-pipeline.png](request-pipeline.png) Whilst complex every effort is made to only walk paths if we are certain they provide value. It introduces two special API calls * `sniff` a request to the service/product that should inform the client about the active topology. * `ping` the fastest request the transport can do to validate a `Node` is alive. If you instantiate `Transport` you can pass an instance of `IProductRegistation` to provide implementations for `sniff` and `ping`. ```c# var settings = new TransportConfiguration(new Uri("http://localhost:9200")); var transport = new Transport(settings); ``` Will use the `DefaultProductRegistration` wich opts out of `sniff` and `ping` However this library ship with a default implementation to fill in the blanks for `Elasticsearch` so we can create a transport for Elasticsearch that support `sniff` and `ping` as followed ```c# var uri = new Uri("http://localhost:9200"); var settings = new TransportConfiguration(uri, ElasticsearchProductRegistration.Default); var transport = new Transport(settings); ``` ### Injection All components are optional and ship with sane defaults. Typically client users only provide the `IConnectionPool` to the transport configuration ##### TransportConfiguration: * `IConnectionPool` a registry of `Nodes` the transport will ask for a view it can iterate over. ONLY if a connection pool indicates it supports receiving new nodes will the transport sniff. * `IConnection` Abstraction for the actual IO the transport needs to perform. * `HttpTransportSerializer` Allows you to inject your own serializer, the default uses `System.Text.Json` * `IProductRegistration` Product specific implementations and metadata provider #### Transport * `ITransportConfigurationValues` A transport configuration instance, explictly designed for clients to introduce subclasses of * `RequestPipelineFactory` A factory creating `RequestPipeline` instances * `DateTimeProvider` Abstraction around the static `DateTime.Now` so we can test algorithms without waiting on the clock on the wall. * `MemoryStreamFactory` A factory creating `MemoryStream` instances. ### Observability The default `HttpTransport` implementation ships with various `DiagnosticSources` to make the whole flow through the request pipeline auditable and debuggable. Every response returned by `Transport` has to implement `TransportResponse` which has one property `ApiCall` of type `ApiCallDetails` which in turns holds all information relevant to the request and response. `NOTE:` it also exposes `response.ApiCallDetails.DebugInformation` always holds a human readable string to indicate what happened. Further more `DiagnosticSources` exists for various purposes e.g (de)serialization times, time to first byte & various counters ## Mocking response objects for testing `TestableResponseFactory` can be used to create response objects for use in unit tests. Example code using the [Moq](https://github.com/moq/moq) library: ```cs var response = TestableResponseFactory.CreateSuccessfulResponse>(new(), 200); var mock = new Mock(); mock .Setup(m => m.SearchAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(response); ```