Skip to content

Commit 101b026

Browse files
WhitWaldomsfussellalicejgibbons
authored
Added .NET SDK examples to serialization document (#4596)
* Added .NET SDK examples to serialization document + modernized it some Signed-off-by: Whit Waldo <[email protected]> * Update sdk-serialization.md Updated formatting and grammar Signed-off-by: Mark Fussell <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Co-authored-by: Alice Gibbons <[email protected]> Signed-off-by: Whit Waldo <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Co-authored-by: Alice Gibbons <[email protected]> Signed-off-by: Whit Waldo <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Co-authored-by: Alice Gibbons <[email protected]> Signed-off-by: Whit Waldo <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Co-authored-by: Alice Gibbons <[email protected]> Signed-off-by: Whit Waldo <[email protected]> * Updated serialization package links + added reference to actor serialization documentation Signed-off-by: Whit Waldo <[email protected]> * Added input binding examples for .NET Signed-off-by: Whit Waldo <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Co-authored-by: Alice Gibbons <[email protected]> Signed-off-by: Whit Waldo <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Co-authored-by: Alice Gibbons <[email protected]> Signed-off-by: Whit Waldo <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Co-authored-by: Alice Gibbons <[email protected]> Signed-off-by: Whit Waldo <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Co-authored-by: Alice Gibbons <[email protected]> Signed-off-by: Whit Waldo <[email protected]> * Update daprdocs/content/en/developing-applications/local-development/sdk-serialization.md Signed-off-by: Mark Fussell <[email protected]> * Updated to use the correct method for service invocation Signed-off-by: Whit Waldo <[email protected]> --------- Signed-off-by: Whit Waldo <[email protected]> Signed-off-by: Mark Fussell <[email protected]> Co-authored-by: Mark Fussell <[email protected]> Co-authored-by: Alice Gibbons <[email protected]>
1 parent 1688963 commit 101b026

File tree

1 file changed

+198
-14
lines changed

1 file changed

+198
-14
lines changed

daprdocs/content/en/developing-applications/local-development/sdk-serialization.md

+198-14
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,40 @@ aliases:
88
- '/developing-applications/sdks/serialization/'
99
---
1010

11-
An SDK for Dapr should provide serialization for two use cases. First, for API objects sent through request and response payloads. Second, for objects to be persisted. For both these use cases, a default serialization is provided. In the Java SDK, it is the [DefaultObjectSerializer](https://dapr.github.io/java-sdk/io/dapr/serializer/DefaultObjectSerializer.html) class, providing JSON serialization.
11+
Dapr SDKs provide serialization for two use cases. First, for API objects sent through request and response payloads. Second, for objects to be persisted. For both of these cases, a default serialization method is provided in each language SDK.
12+
13+
| Language SDK | Default Serializer |
14+
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
15+
| [.NET]({{< ref dotnet >}}) | [DataContracts](https://learn.microsoft.com/dotnet/framework/wcf/feature-details/using-data-contracts) for remoted actors, [System.Text.Json](https://www.nuget.org/packages/System.Text.Json) otherwise. Read more about .NET serialization [here]({{< ref dotnet-actors-serialization >}}) | |
16+
| [Java]({{< ref java >}}) | [DefaultObjectSerializer](https://dapr.github.io/java-sdk/io/dapr/serializer/DefaultObjectSerializer.html) for JSON serialization |
17+
| [JavaScript]({{< ref js >}}) | JSON |
1218

1319
## Service invocation
1420

21+
{{< tabs ".NET" "Java" >}}
22+
23+
<!-- .NET -->
24+
{{% codetab %}}
25+
26+
```csharp
27+
using var client = (new DaprClientBuilder()).Build();
28+
await client.InvokeMethodAsync("myappid", "saySomething", "My Message");
29+
```
30+
31+
{{% /codetab %}}
32+
33+
<!-- Java -->
34+
{{% codetab %}}
35+
1536
```java
1637
DaprClient client = (new DaprClientBuilder()).build();
17-
client.invokeService("myappid", "saySomething", "My Message", HttpExtension.POST).block();
38+
client.invokeMethod("myappid", "saySomething", "My Message", HttpExtension.POST).block();
1839
```
1940

20-
In the example above, the app will receive a `POST` request for the `saySomething` method with the request payload as `"My Message"` - quoted since the serializer will serialize the input String to JSON.
41+
{{% /codetab %}}
42+
43+
In the example above, the app `myappid` receives a `POST` request for the `saySomething` method with the request payload as
44+
`"My Message"` - quoted since the serializer will serialize the input String to JSON.
2145

2246
```text
2347
POST /saySomething HTTP/1.1
@@ -30,11 +54,35 @@ Content-Length: 12
3054

3155
## State management
3256

57+
{{< tabs ".NET" "Java" >}}
58+
59+
<!-- .NET -->
60+
{{% codetab %}}
61+
62+
```csharp
63+
using var client = (new DaprClientBuilder()).Build();
64+
var state = new Dictionary<string, string>
65+
{
66+
{ "key": "MyKey" },
67+
{ "value": "My Message" }
68+
};
69+
await client.SaveStateAsync("MyStateStore", "MyKey", state);
70+
```
71+
72+
{{% /codetab %}}
73+
74+
<!-- Java -->
75+
{{% codetab %}}
76+
3377
```java
3478
DaprClient client = (new DaprClientBuilder()).build();
3579
client.saveState("MyStateStore", "MyKey", "My Message").block();
3680
```
37-
In this example, `My Message` will be saved. It is not quoted because Dapr's API will internally parse the JSON request object before saving it.
81+
82+
{{% /codetab %}}
83+
84+
In this example, `My Message` is saved. It is not quoted because Dapr's API internally parse the JSON request
85+
object before saving it.
3886

3987
```JSON
4088
[
@@ -47,12 +95,45 @@ In this example, `My Message` will be saved. It is not quoted because Dapr's API
4795

4896
## PubSub
4997

98+
{{< tabs ".NET" "Java" >}}
99+
100+
<!-- .NET -->
101+
{{% codetab %}}
102+
103+
```csharp
104+
using var client = (new DaprClientBuilder()).Build();
105+
await client.PublishEventAsync("MyPubSubName", "TopicName", "My Message");
106+
```
107+
108+
The event is published and the content is serialized to `byte[]` and sent to Dapr sidecar. The subscriber receives it as a [CloudEvent](https://github.com/cloudevents/spec). Cloud event defines `data` as String. The Dapr SDK also provides a built-in deserializer for `CloudEvent` object.
109+
110+
```csharp
111+
public async Task<IActionResult> HandleMessage(string message)
112+
{
113+
//ASP.NET Core automatically deserializes the UTF-8 encoded bytes to a string
114+
return new Ok();
115+
}
116+
```
117+
118+
or
119+
120+
```csharp
121+
app.MapPost("/TopicName", [Topic("MyPubSubName", "TopicName")] (string message) => {
122+
return Results.Ok();
123+
}
124+
```
125+
126+
{{% /codetab %}}
127+
128+
<!-- Java -->
129+
{{% codetab %}}
130+
50131
```java
51132
DaprClient client = (new DaprClientBuilder()).build();
52133
client.publishEvent("TopicName", "My Message").block();
53134
```
54135

55-
The event is published and the content is serialized to `byte[]` and sent to Dapr sidecar. The subscriber will receive it as a [CloudEvent](https://github.com/cloudevents/spec). Cloud event defines `data` as String. Dapr SDK also provides a built-in deserializer for `CloudEvent` object.
136+
The event is published and the content is serialized to `byte[]` and sent to Dapr sidecar. The subscriber receives it as a [CloudEvent](https://github.com/cloudevents/spec). Cloud event defines `data` as String. The Dapr SDK also provides a built-in deserializer for `CloudEvent` objects.
56137

57138
```java
58139
@PostMapping(path = "/TopicName")
@@ -62,9 +143,50 @@ The event is published and the content is serialized to `byte[]` and sent to Dap
62143
}
63144
```
64145

146+
{{% /codetab %}}
147+
65148
## Bindings
66149

67-
In this case, the object is serialized to `byte[]` as well and the input binding receives the raw `byte[]` as-is and deserializes it to the expected object type.
150+
For output bindings the object is serialized to `byte[]` whereas the input binding receives the raw `byte[]` as-is and deserializes it to the expected object type.
151+
152+
{{< tabs ".NET" "Java" >}}
153+
154+
<!-- .NET -->
155+
{{% codetab %}}
156+
157+
* Output binding:
158+
```csharp
159+
using var client = (new DaprClientBuilder()).Build();
160+
await client.InvokeBindingAsync("sample", "My Message");
161+
```
162+
163+
* Input binding (controllers):
164+
```csharp
165+
[ApiController]
166+
public class SampleController : ControllerBase
167+
{
168+
[HttpPost("propagate")]
169+
public ActionResult<string> GetValue([FromBody] int itemId)
170+
{
171+
Console.WriteLine($"Received message: {itemId}");
172+
return $"itemID:{itemId}";
173+
}
174+
}
175+
```
176+
177+
* Input binding (minimal API):
178+
```csharp
179+
app.MapPost("value", ([FromBody] int itemId) =>
180+
{
181+
Console.WriteLine($"Received message: {itemId}");
182+
return ${itemID:{itemId}";
183+
});
184+
* ```
185+
186+
{{% /codetab %}}
187+
188+
<!-- Java -->
189+
{{% codetab %}}
68190

69191
* Output binding:
70192
```java
@@ -80,15 +202,49 @@ In this case, the object is serialized to `byte[]` as well and the input binding
80202
System.out.println(message);
81203
}
82204
```
205+
206+
{{% /codetab %}}
207+
83208
It should print:
84209
```
85210
My Message
86211
```
87212

88213
## Actor Method invocation
89-
Object serialization and deserialization for invocation of Actor's methods are same as for the service method invocation, the only difference is that the application does not need to deserialize the request or serialize the response since it is all done transparently by the SDK.
214+
Object serialization and deserialization for Actor method invocation are same as for the service method invocation,
215+
the only difference is that the application does not need to deserialize the request or serialize the response since it
216+
is all done transparently by the SDK.
217+
218+
For Actor methods, the SDK only supports methods with zero or one parameter.
219+
220+
{{< tabs ".NET" "Java" >}}
90221

91-
For Actor's methods, the SDK only supports methods with zero or one parameter.
222+
The .NET SDK supports two different serialization types based on whether you're using strongly-typed (DataContracts)
223+
or weakly-typed (DataContracts or System.Text.JSON) actor client. [This document]({{< ref dotnet-actors-serialization >}})
224+
can provide more information about the differences between each and additional considerations to keep in mind.
225+
226+
<!-- .NET -->
227+
{{% codetab %}}
228+
229+
* Invoking an Actor's method using the weakly-typed client and System.Text.JSON:
230+
```csharp
231+
var proxy = this.ProxyFactory.Create(ActorId.CreateRandom(), "DemoActor");
232+
await proxy.SayAsync("My message");
233+
```
234+
235+
* Implementing an Actor's method:
236+
```csharp
237+
public Task SayAsync(string message)
238+
{
239+
Console.WriteLine(message);
240+
return Task.CompletedTask;
241+
}
242+
```
243+
244+
{{% /codetab %}}
245+
246+
<!-- Java -->
247+
{{% codetab %}}
92248

93249
* Invoking an Actor's method:
94250
```java
@@ -105,13 +261,37 @@ public String say(String something) {
105261
return "OK";
106262
}
107263
```
264+
265+
{{% /codetab %}}
266+
108267
It should print:
109268
```
110269
My Message
111270
```
112271

113272
## Actor's state management
114-
Actors can also have state. In this case, the state manager will serialize and deserialize the objects using the state serializer and handle it transparently to the application.
273+
Actors can also have state. In this case, the state manager will serialize and deserialize the objects using the state
274+
serializer and handle it transparently to the application.
275+
276+
<!-- .NET -->
277+
{{% codetab %}}
278+
279+
```csharp
280+
public Task SayAsync(string message)
281+
{
282+
// Reads state from a key
283+
var previousMessage = await this.StateManager.GetStateAsync<string>("lastmessage");
284+
285+
// Sets the new state for the key after serializing it
286+
await this.StateManager.SetStateAsync("lastmessage", message);
287+
return previousMessage;
288+
}
289+
```
290+
291+
{{% /codetab %}}
292+
293+
<!-- Java -->
294+
{{% codetab %}}
115295

116296
```java
117297
public String actorMethod(String message) {
@@ -124,12 +304,17 @@ public String actorMethod(String message) {
124304
}
125305
```
126306

307+
{{% /codetab %}}
308+
127309
## Default serializer
128310

129311
The default serializer for Dapr is a JSON serializer with the following expectations:
130312

131-
1. Use of basic [JSON data types](https://www.w3schools.com/js/js_json_datatypes.asp) for cross-language and cross-platform compatibility: string, number, array, boolean, null and another JSON object. Every complex property type in application's serializable objects (DateTime, for example), should be represented as one of the JSON's basic types.
132-
2. Data persisted with the default serializer should be saved as JSON objects too, without extra quotes or encoding. The example below shows how a string and a JSON object would look like in a Redis store.
313+
1. Use of basic [JSON data types](https://www.w3schools.com/js/js_json_datatypes.asp) for cross-language and cross-platform compatibility: string, number, array,
314+
boolean, null and another JSON object. Every complex property type in application's serializable objects (DateTime,
315+
for example), should be represented as one of the JSON's basic types.
316+
2. Data persisted with the default serializer should be saved as JSON objects too, without extra quotes or encoding.
317+
The example below shows how a string and a JSON object would look like in a Redis store.
133318
```bash
134319
redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||message
135320
"This is a message to be saved and retrieved."
@@ -140,7 +325,8 @@ redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928
140325
```
141326
3. Custom serializers must serialize object to `byte[]`.
142327
4. Custom serializers must deserialize `byte[]` to object.
143-
5. When user provides a custom serializer, it should be transferred or persisted as `byte[]`. When persisting, also encode as Base64 string. This is done natively by most JSON libraries.
328+
5. When user provides a custom serializer, it should be transferred or persisted as `byte[]`. When persisting, also
329+
encode as Base64 string. This is done natively by most JSON libraries.
144330
```bash
145331
redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||message
146332
"VGhpcyBpcyBhIG1lc3NhZ2UgdG8gYmUgc2F2ZWQgYW5kIHJldHJpZXZlZC4="
@@ -149,5 +335,3 @@ redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928
149335
redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||mydata
150336
"eyJ2YWx1ZSI6Ik15IGRhdGEgdmFsdWUuIn0="
151337
```
152-
153-
*As of now, the [Java SDK](https://github.com/dapr/java-sdk/) is the only Dapr SDK that implements this specification. In the near future, other SDKs will also implement the same.*

0 commit comments

Comments
 (0)