Skip to content

Commit 765374b

Browse files
authored
Merge branch 'master' into fix-workflow-docs
2 parents f15bd8b + bdca3b3 commit 765374b

File tree

8 files changed

+112
-3
lines changed

8 files changed

+112
-3
lines changed

daprdocs/content/en/dotnet-sdk-docs/dotnet-client/_index.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@ The .NET SDK allows you to interface with all of the [Dapr building blocks]({{<
2121

2222
### Invoke a service
2323

24+
#### HTTP
2425
You can either use the `DaprClient` or `System.Net.Http.HttpClient` to invoke your services.
2526

2627
{{< tabs SDK HTTP>}}
2728

2829
{{% codetab %}}
2930
```csharp
30-
using var client = new DaprClientBuilder().Build();
31+
using var client = new DaprClientBuilder().
32+
UseTimeout(TimeSpan.FromSeconds(2)). // Optionally, set a timeout
33+
Build();
3134

3235
// Invokes a POST method named "deposit" that takes input of type "Transaction"
3336
var data = new { id = "17", amount = 99m };
@@ -40,15 +43,33 @@ Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance)
4043
```csharp
4144
var client = DaprClient.CreateInvokeHttpClient(appId: "routing");
4245

46+
// To set a timeout on the HTTP client:
47+
client.Timeout = TimeSpan.FromSeconds(2);
48+
4349
var deposit = new Transaction { Id = "17", Amount = 99m };
4450
var response = await client.PostAsJsonAsync("/deposit", deposit, cancellationToken);
4551
var account = await response.Content.ReadFromJsonAsync<Account>(cancellationToken: cancellationToken);
4652
Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
4753
```
4854
{{% /codetab %}}
49-
5055
{{< /tabs >}}
5156

57+
#### gRPC
58+
You can use the `DaprClient` to invoke your services over gRPC.
59+
{{% codetab %}}
60+
```csharp
61+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
62+
var invoker = DaprClient.CreateInvocationInvoker(appId: myAppId, daprEndpoint: serviceEndpoint);
63+
var client = new MyService.MyServiceClient(invoker);
64+
65+
var options = new CallOptions(cancellationToken: cts.Token, deadline: DateTime.UtcNow.AddSeconds(1));
66+
await client.MyMethodAsync(new Empty(), options);
67+
68+
Assert.Equal(StatusCode.DeadlineExceeded, ex.StatusCode);
69+
```
70+
{{% /codetab %}}
71+
72+
5273
- For a full guide on service invocation visit [How-To: Invoke a service]({{< ref howto-invoke-discover-services.md >}}).
5374

5475
### Save & get application state

src/Dapr.Client/DaprClientBuilder.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public DaprClientBuilder()
5757
// property exposed for testing purposes
5858
internal GrpcChannelOptions GrpcChannelOptions { get; private set; }
5959
internal string DaprApiToken { get; private set; }
60+
internal TimeSpan Timeout { get; private set; }
6061

6162
/// <summary>
6263
/// Overrides the HTTP endpoint used by <see cref="DaprClient" /> for communicating with the Dapr runtime.
@@ -136,6 +137,17 @@ public DaprClientBuilder UseDaprApiToken(string apiToken)
136137
return this;
137138
}
138139

140+
/// <summary>
141+
/// Sets the timeout for the HTTP client used by the <see cref="DaprClient" />.
142+
/// </summary>
143+
/// <param name="timeout"></param>
144+
/// <returns></returns>
145+
public DaprClientBuilder UseTimeout(TimeSpan timeout)
146+
{
147+
this.Timeout = timeout;
148+
return this;
149+
}
150+
139151
/// <summary>
140152
/// Builds a <see cref="DaprClient" /> instance from the properties of the builder.
141153
/// </summary>
@@ -162,9 +174,16 @@ public DaprClient Build()
162174

163175
var channel = GrpcChannel.ForAddress(this.GrpcEndpoint, this.GrpcChannelOptions);
164176
var client = new Autogenerated.Dapr.DaprClient(channel);
165-
177+
178+
166179
var apiTokenHeader = DaprClient.GetDaprApiTokenHeader(this.DaprApiToken);
167180
var httpClient = HttpClientFactory is object ? HttpClientFactory() : new HttpClient();
181+
182+
if (this.Timeout > TimeSpan.Zero)
183+
{
184+
httpClient.Timeout = this.Timeout;
185+
}
186+
168187
return new DaprClientGrpc(channel, client, httpClient, httpEndpoint, this.JsonSerializerOptions, apiTokenHeader);
169188
}
170189
}

test/Dapr.AspNetCore.Test/DaprClientBuilderTest.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using System;
1515
using System.Text.Json;
1616
using Dapr.Client;
17+
using Grpc.Core;
1718
using Grpc.Net.Client;
1819
using Xunit;
1920

@@ -110,5 +111,15 @@ public void DaprClientBuilder_ApiTokenNotSet_EmptyApiTokenHeader()
110111
var entry = DaprClient.GetDaprApiTokenHeader(builder.DaprApiToken);
111112
Assert.Equal(default, entry);
112113
}
114+
115+
[Fact]
116+
public void DaprClientBuilder_SetsTimeout()
117+
{
118+
var builder = new DaprClientBuilder();
119+
builder.UseTimeout(TimeSpan.FromSeconds(2));
120+
builder.Build();
121+
Assert.Equal(2, builder.Timeout.Seconds);
122+
}
113123
}
124+
114125
}

test/Dapr.E2E.Test.App.Grpc/Proto/message.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ service Messager {
2525
rpc GetMessage(GetMessageRequest) returns (MessageResponse);
2626
// Send a series of broadcast messages.
2727
rpc StreamBroadcast(stream Broadcast) returns (stream MessageResponse);
28+
rpc DelayedResponse(google.protobuf.Empty) returns (google.protobuf.Empty);
2829
}
2930

3031
message SendMessageRequest {

test/Dapr.E2E.Test.App.Grpc/Services/MessagerService.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
// limitations under the License.
1212
// ------------------------------------------------------------------------
1313

14+
using System;
1415
using System.Threading.Tasks;
1516
using Google.Protobuf.WellKnownTypes;
1617
using Grpc.Core;
@@ -44,5 +45,11 @@ public override async Task StreamBroadcast(IAsyncStreamReader<Broadcast> request
4445
await responseStream.WriteAsync(new MessageResponse { Message = request.Message });
4546
}
4647
}
48+
49+
public override async Task<Empty> DelayedResponse(Empty request, ServerCallContext context)
50+
{
51+
await Task.Delay(TimeSpan.FromSeconds(2));
52+
return new Empty();
53+
}
4754
}
4855
}

test/Dapr.E2E.Test.App/Controllers/TestController.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,14 @@ public ActionResult<Account> AccountDetailsRequiresApiToken(Transaction transact
6565
};
6666
return account;
6767
}
68+
69+
[Authorize("Dapr")]
70+
[HttpGet("DelayedResponse")]
71+
public async Task<IActionResult> DelayedResponse()
72+
{
73+
await Task.Delay(TimeSpan.FromSeconds(2));
74+
return Ok();
75+
}
76+
6877
}
6978
}

test/Dapr.E2E.Test/ServiceInvocation/E2ETests.GrpcProxyInvocationTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using System.Threading;
1616
using System.Threading.Tasks;
1717
using Dapr.Client;
18+
using Google.Protobuf.WellKnownTypes;
1819
using Grpc.Core;
1920
using Xunit;
2021
using Xunit.Abstractions;
@@ -77,5 +78,21 @@ public async Task TestGrpcProxyStreamingBroadcast()
7778
await responseTask;
7879
}
7980
}
81+
82+
[Fact]
83+
public async Task TestGrpcServiceInvocationWithTimeout()
84+
{
85+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
86+
var invoker = DaprClient.CreateInvocationInvoker(appId: this.AppId, daprEndpoint: this.GrpcEndpoint);
87+
var client = new Messager.MessagerClient(invoker);
88+
89+
var options = new CallOptions(cancellationToken: cts.Token, deadline: DateTime.UtcNow.AddSeconds(1));
90+
var ex = await Assert.ThrowsAsync<RpcException>(async () =>
91+
{
92+
await client.DelayedResponseAsync(new Empty(), options);
93+
});
94+
95+
Assert.Equal(StatusCode.DeadlineExceeded, ex.StatusCode);
96+
}
8097
}
8198
}

test/Dapr.E2E.Test/ServiceInvocation/E2ETests.ServiceInvocationTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@
1313
namespace Dapr.E2E.Test
1414
{
1515
using System;
16+
using System.Net;
17+
using System.Net.Http;
1618
using System.Net.Http.Json;
19+
using System.Net.Sockets;
1720
using System.Threading;
1821
using System.Threading.Tasks;
1922
using Dapr.Client;
23+
using Google.Protobuf.WellKnownTypes;
24+
using Grpc.Core;
2025
using Xunit;
2126

2227
public partial class E2ETests
@@ -58,6 +63,25 @@ public async Task TestServiceInvocationRequiresApiToken()
5863
Assert.Equal("1", account.Id);
5964
Assert.Equal(150, account.Balance);
6065
}
66+
67+
[Fact]
68+
public async Task TestHttpServiceInvocationWithTimeout()
69+
{
70+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
71+
using var client = new DaprClientBuilder()
72+
.UseHttpEndpoint(this.HttpEndpoint)
73+
.UseTimeout(TimeSpan.FromSeconds(1))
74+
.Build();
75+
76+
await Assert.ThrowsAsync<TaskCanceledException>(async () =>
77+
{
78+
await client.InvokeMethodAsync<HttpResponseMessage>(
79+
appId: this.AppId,
80+
methodName: "DelayedResponse",
81+
httpMethod: new HttpMethod("GET"),
82+
cancellationToken: cts.Token);
83+
});
84+
}
6185
}
6286

6387
internal class Transaction

0 commit comments

Comments
 (0)