Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
id: data-conversion
title: Payload conversion - .NET SDK
sidebar_label: Payload conversion
toc_max_heading_level: 3
tags:
- Data Converters
- .NET SDK
- Temporal SDKs
description: Customize how Temporal serializes application objects using Payload Converters in the .NET SDK.
---

import { CaptionedImage } from '@site/src/components';

## Payload conversion

Temporal SDKs provide a default [Payload Converter](/payload-converter) that can be customized to convert a custom data type to [Payload](/dataconversion#payload) and back.

### Conversion sequence {/* #conversion-sequence */}

The order in which your encoding Payload Converters are applied depend on the order given to the Data Converter.
You can set multiple encoding Payload Converters to run your conversions.
When the Data Converter receives a value for conversion, it passes through each Payload Converter in sequence until the converter that handles the data type does the conversion.

Payload Converters can be customized independently of a Payload Codec.
Temporal's Converter architecture looks like this:

<CaptionedImage
src="/img/info/converter-architecture.png"
title="Temporal converter architecture"
/>

## Custom Payload Converter {/* #custom-payload-converter */}

Data converters are used to convert raw Temporal payloads to/from actual .NET types.
A custom data converter can be set via the `DataConverter` option when creating a client. Data converters are a combination of payload converters, payload codecs, and failure converters.
Payload converters convert .NET values to/from serialized bytes. Payload codecs convert bytes to bytes (e.g. for compression or encryption). Failure converters convert exceptions to/from serialized failures.

Data converters are in the `Temporalio.Converters` namespace.
The default data converter uses a default payload converter, which supports the following types:

- `null`
- `byte[]`
- `Google.Protobuf.IMessage` instances
- Anything that `System.Text.Json` supports
- `IRawValue` as unconverted raw payloads

Custom converters can be created for all uses. For example, to create client with a data converter that converts all C#
property names to camel case, you would:

```csharp
using System.Text.Json;
using Temporalio.Client;
using Temporalio.Converters;

public class CamelCasePayloadConverter : DefaultPayloadConverter
{
public CamelCasePayloadConverter()
: base(new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })
{
}
}

var client = await TemporalClient.ConnectAsync(new()
{
TargetHost = "localhost:7233",
Namespace = "my-namespace",
DataConverter = DataConverter.Default with { PayloadConverter = new CamelCasePayloadConverter() },
});
```
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
---
id: converters-and-encryption
title: Converters and encryption - .NET SDK
sidebar_label: Converters and encryption
description: Use a custom Payload Codec and Converter in the .NET SDK to modify Temporal Data Conversion behavior, including examples for encryption and camel case conversion.
keywords:
- sdk
- dotnet
- data encryption
- codec server
- converter
id: data-encryption
title: Payload encryption - .NET SDK
sidebar_label: Payload encryption
toc_max_heading_level: 3
tags:
- .Net SDK
- Temporal SDKs
- Security
- Codec Server
- Data Converters
- Encryption
- Codec Server
- .NET SDK
- Temporal SDKs
description: Encrypt data sent to and from the Temporal Service using a custom Payload Codec in the .NET SDK.
---

import { CaptionedImage } from '@site/src/components';

Temporal's security model is designed around client-side encryption of Payloads.
A client may encrypt Payloads before sending them to the server, and decrypt them after receiving them from the server.
This provides a high degree of confidentiality because the Temporal Server itself has absolutely no knowledge of the actual data.
Expand Down Expand Up @@ -75,7 +67,7 @@ public class EncryptionCodec : IPayloadCodec
}
```

**Set Data Converter to use custom Payload Codec**
### Set Data Converter to use custom Payload Codec

When creating a client, the default `DataConverter` can be updated with the payload codec like so:

Expand All @@ -91,69 +83,10 @@ var myClient = await TemporalClient.ConnectAsync(new("localhost:7233")

For reference, see the [Encryption](https://github.com/temporalio/samples-dotnet/tree/main/src/Encryption) sample.

### Using a Codec Server
## Using a Codec Server

A Codec Server is an HTTP server that uses your custom Codec logic to decode your data remotely.
The Codec Server is independent of the Temporal Cluster and decodes your encrypted payloads through predefined endpoints.
You create, operate, and manage access to your Codec Server in your own environment.
The Temporal CLI and the Web UI in turn provide built-in hooks to call the Codec Server to decode encrypted payloads on demand.
Refer to the [Codec Server](/production-deployment/data-encryption) documentation for information on how to design and deploy a Codec Server.

## Payload conversion

Temporal SDKs provide a default [Payload Converter](/payload-converter) that can be customized to convert a custom data type to [Payload](/dataconversion#payload) and back.

### Conversion sequence {/* #conversion-sequence */}

The order in which your encoding Payload Converters are applied depend on the order given to the Data Converter.
You can set multiple encoding Payload Converters to run your conversions.
When the Data Converter receives a value for conversion, it passes through each Payload Converter in sequence until the converter that handles the data type does the conversion.

Payload Converters can be customized independently of a Payload Codec.
Temporal's Converter architecture looks like this:

<CaptionedImage
src="/img/info/converter-architecture.png"
title="Temporal converter architecture"
/>

### Custom Payload Converter {/* #custom-payload-converter */}

Data converters are used to convert raw Temporal payloads to/from actual .NET types.
A custom data converter can be set via the `DataConverter` option when creating a client. Data converters are a combination of payload converters, payload codecs, and failure converters.
Payload converters convert .NET values to/from serialized bytes. Payload codecs convert bytes to bytes (e.g. for compression or encryption). Failure converters convert exceptions to/from serialized failures.

Data converters are in the `Temporalio.Converters` namespace.
The default data converter uses a default payload converter, which supports the following types:

- `null`
- `byte[]`
- `Google.Protobuf.IMessage` instances
- Anything that `System.Text.Json` supports
- `IRawValue` as unconverted raw payloads

Custom converters can be created for all uses. For example, to create client with a data converter that converts all C#
property names to camel case, you would:

```csharp
using System.Text.Json;
using Temporalio.Client;
using Temporalio.Converters;

public class CamelCasePayloadConverter : DefaultPayloadConverter
{
public CamelCasePayloadConverter()
: base(new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })
{
}
}

var client = await TemporalClient.ConnectAsync(new()
{
TargetHost = "localhost:7233",
Namespace = "my-namespace",
DataConverter = DataConverter.Default with { PayloadConverter = new CamelCasePayloadConverter() },
});
```

<!-- ### Custom Type Data Conversion TODO(cretz): Develop https://github.com/temporalio/samples-dotnet/issues/38 first -->
36 changes: 36 additions & 0 deletions docs/develop/dotnet/best-practices/data-handling/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: data-handling
title: Data handling - .NET SDK
sidebar_label: Data handling
description:
Learn how Temporal handles data through the Data Converter, including payload conversion, encryption, and large
payload storage.
toc_max_heading_level: 3
tags:
- .NET SDK
- Temporal SDKs
- Data Converters
---

import { CaptionedImage } from '@site/src/components';

All data sent to and from the Temporal Service passes through the **Data Converter**. The Data Converter has three
layers that handle different concerns:

<CaptionedImage
src="/diagrams/data-converter-flow-with-external-storage.svg"
srcDark="/diagrams/data-converter-flow-dark.svg"
title="The Flow of Data through a Data Converter"
alt="The Flow of Data through a Data Converter"
/>

Of these three layers, only the PayloadConverter is required. Temporal uses a default PayloadConverter that handles JSON
serialization. The PayloadCodec and ExternalStorage layers are optional. You only need to customize these layers when
your application requires non-JSON types, encryption, or payload offloading.

| | [PayloadConverter](/develop/dotnet/best-practices/data-handling/data-conversion) | [PayloadCodec](/develop/dotnet/best-practices/data-handling/data-encryption) |
| ------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------- |
| **Purpose** | Serialize application data to bytes | Transform encoded payloads (encrypt, compress) |
| **Default** | JSON serialization | None (passthrough) |

For a deeper conceptual explanation, see the [Data Conversion encyclopedia](/dataconversion) and [External Storage](/external-storage).
2 changes: 1 addition & 1 deletion docs/develop/dotnet/best-practices/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ import * as Components from '@site/src/components';
- [Error handling](/develop/dotnet/best-practices/error-handling)
- [Testing](/develop/dotnet/best-practices/testing-suite)
- [Debugging](/develop/dotnet/best-practices/debugging)
- [Converters and encryption](/develop/dotnet/best-practices/converters-and-encryption)
- [Converters and encryption](/develop/dotnet/best-practices/data-handling)
2 changes: 1 addition & 1 deletion docs/develop/dotnet/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ From there, you can dive deeper into any of the Temporal primitives to start bui
- [Error handling](/develop/dotnet/best-practices/error-handling)
- [Testing](/develop/dotnet/best-practices/testing-suite)
- [Debugging](/develop/dotnet/best-practices/debugging)
- [Converters and encryption](/develop/dotnet/best-practices/converters-and-encryption)
- [Converters and encryption](/develop/dotnet/best-practices/data-handling)

## Temporal .NET technical resources
Comment thread
Duncanma marked this conversation as resolved.

Expand Down
107 changes: 107 additions & 0 deletions docs/develop/java/best-practices/data-handling/data-conversion.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
id: data-conversion
title: Payload conversion - Java SDK
sidebar_label: Payload conversion
toc_max_heading_level: 3
tags:
- Data Converters
- Java SDK
- Temporal SDKs
description: Customize how Temporal serializes application objects using Payload Converters in the Java SDK.
---

import { CaptionedImage } from '@site/src/components';

Payload Converters serialize your application objects into a `Payload` and deserialize them back.
A `Payload` is a binary form with metadata that Temporal uses to transport data.

By default, Temporal uses a Payload Converter that handles `null`, byte arrays, protobuf messages, and anything JSON-serializable.
You only need a custom Payload Converter when your application uses types that aren't natively supported.

## Default supported types

The default Data Converter supports converting multiple types including:

- `null`
- Byte arrays
- Protobuf JSON: if a value is an instance of a Protobuf message, it is encoded with proto3 JSON
- [Jackson JSON](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/jackson.html)
- Anything that can be converted to JSON

## Using custom Payload conversion {/* #custom-payload-conversion */}

Temporal SDKs provide a [Payload Converter](/payload-converter) that can be customized to convert a custom data type to [Payload](/dataconversion#payload) and back.

Implementing custom Payload conversion is optional.
It is needed only if the [default Data Converter](/default-custom-data-converters#default-data-converter) does not support your custom values.

To support custom Payload conversion, create a [custom Payload Converter](/payload-converter#composite-data-converters) and configure the Data Converter to use it in your Client options.

The order in which your encoding Payload Converters are applied depend on the order given to the Data Converter.
You can set multiple encoding Payload Converters to run your conversions.
When the Data Converter receives a value for conversion, it passes through each Payload Converter in sequence until the converter that handles the data type does the conversion.

Payload Converters can be customized independently of a Payload Codec.
Temporal's Converter architecture looks like this:

<CaptionedImage
src="/img/info/converter-architecture.png"
title="Temporal converter architecture"
/>

Create a custom implementation of a [PayloadConverter](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/PayloadConverter.html) interface and use the `withPayloadConverterOverrides` method to implement the custom object conversion with `DefaultDataConverter`.

`PayloadConverter` serializes and deserializes method parameters that need to be sent over the wire.
You can create a custom implementation of `PayloadConverter` for custom formats, as shown in the following example:

```java
/** Payload Converter specific to your custom object */
public class YourCustomPayloadConverter implements PayloadConverter {
//...
@Override
public String getEncodingType() {
return "json/plain"; // The encoding type determines which default conversion behavior to override.
}

@Override
public Optional<Payload> toData(Object value) throws DataConverterException {
// Add your convert-to logic here.
}

@Override
public <T> T fromData(Payload content, Class<T> valueClass, Type valueType)
throws DataConverterException {
// Add your convert-from logic here.
}
//...
}
```

You can also use [specific implementation classes](https://www.javadoc.io/static/io.temporal/temporal-sdk/1.18.1/io/temporal/common/converter/package-summary.html) provided in the Java SDK.

For example, to create a custom `JacksonJsonPayloadConverter`, use the following:

```java
//...
private static JacksonJsonPayloadConverter yourCustomJacksonJsonPayloadConverter() {
ObjectMapper objectMapper = new ObjectMapper();
// Add your custom logic here.
return new JacksonJsonPayloadConverter(objectMapper);
}
//...
```

To set your custom Payload Converter, use it with [withPayloadConverterOverrides](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/DefaultDataConverter.html#withPayloadConverterOverrides(io.temporal.common.converter.PayloadConverter...)) with a new instance of `DefaultDataConverter` in your `WorkflowClient` options that you use in your Worker process and to start your Workflow Executions.

The following example shows how to set a custom `YourCustomPayloadConverter` Payload Converter.

```java
//...
DefaultDataConverter ddc =
DefaultDataConverter.newDefaultInstance()
.withPayloadConverterOverrides(new YourCustomPayloadConverter());

WorkflowClientOptions workflowClientOptions =
WorkflowClientOptions.newBuilder().setDataConverter(ddc).build();
//...
```
Loading