Post data
editPost data
editThe low level client allows you to post a string or byte[] array directly. On top of this,
if you pass a collection of string or object they will be serialized using Elasticsearch’s special bulk/multi format.
Implicit Conversion
editEven though the argument for PostData on the low level client takes a PostData,
You can rely on implicit conversion to abstract the notion of PostData for the most common two use cases:
-
A
string -
A
byte[]array
Let’s demonstrate each with some assertive examples
PostData fromString = @string; PostData fromByteArray = bytes; fromByteArray.WrittenBytes.Should().BeSameAs(bytes);
The Type property is representative of the original type from which post data is constructed
fromString.Type.Should().Be(PostType.LiteralString); fromByteArray.Type.Should().Be(PostType.ByteArray);
and passing a PostData instance to a method that accepts PostData
as an argument does not wrap it again
fromString = MethodThatAcceptsPostData(fromString); fromByteArray = MethodThatAcceptsPostData(fromByteArray); fromString.Type.Should().Be(PostType.LiteralString); fromByteArray.Type.Should().Be(PostType.ByteArray);
Other types of PostData
editYou can also pass the following objects directly to the low level client.
-
A Serializable
object -
A collection of
objectas multi line json -
A collection of
stringas multi line json
Let’s demonstrate how to use the static helper on PostData for these:
PostData fromObject = PostData.Serializable(@object); PostData fromListOfString = PostData.MultiJson(collectionOfStrings); PostData fromListOfObject = PostData.MultiJson(collectionOfObjects);
The Type property is representative of the original type from which post data is constructed
fromListOfString.Type.Should().Be(PostType.EnumerableOfString); fromListOfObject.Type.Should().Be(PostType.EnumerableOfObject); fromObject.Type.Should().Be(PostType.Serializable);
and passing a PostData instance to a method that accepts PostData as an argument does not wrap it again
fromListOfString = MethodThatAcceptsPostData(fromListOfString); fromListOfObject = MethodThatAcceptsPostData(fromListOfObject); fromObject = MethodThatAcceptsPostData(fromObject); fromListOfString.Type.Should().Be(PostType.EnumerableOfString); fromListOfObject.Type.Should().Be(PostType.EnumerableOfObject); fromObject.Type.Should().Be(PostType.Serializable);
Each of the implicitly converted types behaves slightly differently.
For string, the UTF-8 bytes are sent in the request and the WrittenBytes property is assigned
the bytes
await Post(() => @string, writes: Utf8Bytes(@string), writtenBytesIsSet: true, settings: settings);
Similarly, for byte[], the bytes are sent verbatim and the WrittenBytes property is assigned
the bytes
await Post(() => bytes, writes: bytes, writtenBytesIsSet: true, settings: settings);
On platforms that support ReadOnlyMemory<byte> you can use PostData.ReadOnlyMemory to pass this directly
await Post(() => PostData.ReadOnlyMemory(bytes.AsMemory()), writes: bytes, writtenBytesIsSet: false, settings: settings);
When passing a collection of string, the client assumes that it’s a collection of valid serialized json,
so joins each with newline feeds, ensuring there is a trailing linefeed. As with string and byte[],
the WrittenBytes property is assigned the UTF-8 bytes of the collection of strings if DisableDirectStreaming is set on ConnectionConfiguration
await Post(() => PostData.MultiJson(collectionOfStrings), writes: utf8BytesOfListOfStrings, writtenBytesIsSet: false, settings: settings);
When passing a collection of object, the client assumes that it’s a collection of objects
that needs to be serialized individually to json and joined with newline feeds. As with the collection of strings, the client ensures that
there is a trailing linefeed.
await Post(() => PostData.MultiJson(collectionOfObjects), writes: utf8BytesOfCollectionOfObjects, writtenBytesIsSet: false, settings: settings);
In all other cases, Post data is serialized as is and WrittenBytes is not assigned
await Post(() => PostData.Serializable(@object), writes: utf8ObjectBytes, writtenBytesIsSet: false, settings: settings);
If you want even more control over how your data is written to the stream consider PostData.StreamHandler
which allows you to inject your own writer routines
var streamHandler = PostData.StreamHandler(bytes,
(b, s) => s.Write(b.AsSpan()),
async (b, s, ctx) => await s.WriteAsync(b.AsMemory(), ctx)
);
await Post(() => streamHandler, writes: bytes, writtenBytesIsSet: false, settings: settings);
Forcing WrittenBytes to be set
editIf you want to maintain a copy of the request that went out, you can set DisableDirectStreaming on ConnectionConfiguration.
In doing so, the serialized bytes are first written to a private MemoryStream so that the client can get hold of the serialized bytes
settings = new ConnectionConfiguration().DisableDirectStreaming(); await Post(() => PostData.MultiJson(collectionOfObjects), writes: utf8BytesOfCollectionOfObjects, writtenBytesIsSet: true, settings: settings); await Post(() => PostData.MultiJson(collectionOfStrings), writes: utf8BytesOfListOfStrings, writtenBytesIsSet: true, settings: settings); await Post(() => PostData.ReadOnlyMemory(bytes.AsMemory()), writes: bytes, writtenBytesIsSet: true, settings: settings); await Post(() => streamHandler, writes: bytes, writtenBytesIsSet: true, settings: settings);
This behavior can also be observed when serializing a simple object using DisableDirectStreaming enabled
await Post(() => PostData.Serializable(@object), writes: utf8ObjectBytes, writtenBytesIsSet: true, settings: settings);