Skip to content

Commit

Permalink
Merge branch 'master' into chore/#1239_PackageCleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
philliphoff authored Apr 8, 2024
2 parents 2c4fc91 + 64c2f48 commit ee1a0a5
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,8 @@ namespace MyActorService

app.UseRouting();

app.UseEndpoints(endpoints =>
{
// Register actors handlers that interface with the Dapr runtime.
endpoints.MapActorsHandlers();
});
// Register actors handlers that interface with the Dapr runtime.
app.MapActorsHandlers();
}
}
}
Expand Down
25 changes: 23 additions & 2 deletions daprdocs/content/en/dotnet-sdk-docs/dotnet-client/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ The .NET SDK allows you to interface with all of the [Dapr building blocks]({{<

### Invoke a service

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

{{< tabs SDK HTTP>}}

{{% codetab %}}
```csharp
using var client = new DaprClientBuilder().Build();
using var client = new DaprClientBuilder().
UseTimeout(TimeSpan.FromSeconds(2)). // Optionally, set a timeout
Build();

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

// To set a timeout on the HTTP client:
client.Timeout = TimeSpan.FromSeconds(2);

var deposit = new Transaction { Id = "17", Amount = 99m };
var response = await client.PostAsJsonAsync("/deposit", deposit, cancellationToken);
var account = await response.Content.ReadFromJsonAsync<Account>(cancellationToken: cancellationToken);
Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
```
{{% /codetab %}}

{{< /tabs >}}

#### gRPC
You can use the `DaprClient` to invoke your services over gRPC.
{{% codetab %}}
```csharp
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
var invoker = DaprClient.CreateInvocationInvoker(appId: myAppId, daprEndpoint: serviceEndpoint);
var client = new MyService.MyServiceClient(invoker);

var options = new CallOptions(cancellationToken: cts.Token, deadline: DateTime.UtcNow.AddSeconds(1));
await client.MyMethodAsync(new Empty(), options);

Assert.Equal(StatusCode.DeadlineExceeded, ex.StatusCode);
```
{{% /codetab %}}


- For a full guide on service invocation visit [How-To: Invoke a service]({{< ref howto-invoke-discover-services.md >}}).

### Save & get application state
Expand Down
21 changes: 20 additions & 1 deletion src/Dapr.Client/DaprClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public DaprClientBuilder()
// property exposed for testing purposes
internal GrpcChannelOptions GrpcChannelOptions { get; private set; }
internal string DaprApiToken { get; private set; }
internal TimeSpan Timeout { get; private set; }

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

/// <summary>
/// Sets the timeout for the HTTP client used by the <see cref="DaprClient" />.
/// </summary>
/// <param name="timeout"></param>
/// <returns></returns>
public DaprClientBuilder UseTimeout(TimeSpan timeout)
{
this.Timeout = timeout;
return this;
}

/// <summary>
/// Builds a <see cref="DaprClient" /> instance from the properties of the builder.
/// </summary>
Expand All @@ -162,9 +174,16 @@ public DaprClient Build()

var channel = GrpcChannel.ForAddress(this.GrpcEndpoint, this.GrpcChannelOptions);
var client = new Autogenerated.Dapr.DaprClient(channel);



var apiTokenHeader = DaprClient.GetDaprApiTokenHeader(this.DaprApiToken);
var httpClient = HttpClientFactory is object ? HttpClientFactory() : new HttpClient();

if (this.Timeout > TimeSpan.Zero)
{
httpClient.Timeout = this.Timeout;
}

return new DaprClientGrpc(channel, client, httpClient, httpEndpoint, this.JsonSerializerOptions, apiTokenHeader);
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/Dapr.Client/StateQueryResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ You may obtain a copy of the License at
limitations under the License.
*/

#nullable enable
using System.Collections.Generic;

namespace Dapr.Client
Expand Down Expand Up @@ -75,9 +76,9 @@ public StateQueryItem(string key, TValue data, string etag, string error)
public string Key { get; }

/// <summary>
/// The data of the the key from the matched query.
/// The data of the key from the matched query.
/// </summary>
public TValue Data { get; }
public TValue? Data { get; }

/// <summary>
/// The ETag for the key from the matched query.
Expand Down
6 changes: 3 additions & 3 deletions src/Dapr.Workflow/WorkflowContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,9 @@ public abstract Task<TResult> CallChildWorkflowAsync<TResult>(
/// exception will be surfaced to the parent workflow, just like it is when an activity task fails with an
/// exception. Child workflows also support automatic retry policies.
/// </para><para>
/// Because child workflows are independent of their parents, terminating a parent workflow does not affect
/// any child workflows. You must terminate each child workflow independently using its instance ID, which
/// is specified by <see cref="ChildWorkflowTaskOptions.InstanceId" />.
/// Terminating a parent workflow terminates all the child workflows created by the workflow instance. See the documentation at
/// https://docs.dapr.io/developing-applications/building-blocks/workflow/workflow-features-concepts/#child-workflows regarding
/// the terminate workflow API for more information.
/// </para>
/// </remarks>
/// <param name="workflowName">The name of the workflow to call.</param>
Expand Down
11 changes: 11 additions & 0 deletions test/Dapr.AspNetCore.Test/DaprClientBuilderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System;
using System.Text.Json;
using Dapr.Client;
using Grpc.Core;
using Grpc.Net.Client;
using Xunit;

Expand Down Expand Up @@ -110,5 +111,15 @@ public void DaprClientBuilder_ApiTokenNotSet_EmptyApiTokenHeader()
var entry = DaprClient.GetDaprApiTokenHeader(builder.DaprApiToken);
Assert.Equal(default, entry);
}

[Fact]
public void DaprClientBuilder_SetsTimeout()
{
var builder = new DaprClientBuilder();
builder.UseTimeout(TimeSpan.FromSeconds(2));
builder.Build();
Assert.Equal(2, builder.Timeout.Seconds);
}
}

}
1 change: 1 addition & 0 deletions test/Dapr.E2E.Test.App.Grpc/Proto/message.proto
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ service Messager {
rpc GetMessage(GetMessageRequest) returns (MessageResponse);
// Send a series of broadcast messages.
rpc StreamBroadcast(stream Broadcast) returns (stream MessageResponse);
rpc DelayedResponse(google.protobuf.Empty) returns (google.protobuf.Empty);
}

message SendMessageRequest {
Expand Down
7 changes: 7 additions & 0 deletions test/Dapr.E2E.Test.App.Grpc/Services/MessagerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// limitations under the License.
// ------------------------------------------------------------------------

using System;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
Expand Down Expand Up @@ -44,5 +45,11 @@ public override async Task StreamBroadcast(IAsyncStreamReader<Broadcast> request
await responseStream.WriteAsync(new MessageResponse { Message = request.Message });
}
}

public override async Task<Empty> DelayedResponse(Empty request, ServerCallContext context)
{
await Task.Delay(TimeSpan.FromSeconds(2));
return new Empty();
}
}
}
9 changes: 9 additions & 0 deletions test/Dapr.E2E.Test.App/Controllers/TestController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,14 @@ public ActionResult<Account> AccountDetailsRequiresApiToken(Transaction transact
};
return account;
}

[Authorize("Dapr")]
[HttpGet("DelayedResponse")]
public async Task<IActionResult> DelayedResponse()
{
await Task.Delay(TimeSpan.FromSeconds(2));
return Ok();
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Xunit;
using Xunit.Abstractions;
Expand Down Expand Up @@ -77,5 +78,21 @@ public async Task TestGrpcProxyStreamingBroadcast()
await responseTask;
}
}

[Fact]
public async Task TestGrpcServiceInvocationWithTimeout()
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
var invoker = DaprClient.CreateInvocationInvoker(appId: this.AppId, daprEndpoint: this.GrpcEndpoint);
var client = new Messager.MessagerClient(invoker);

var options = new CallOptions(cancellationToken: cts.Token, deadline: DateTime.UtcNow.AddSeconds(1));
var ex = await Assert.ThrowsAsync<RpcException>(async () =>
{
await client.DelayedResponseAsync(new Empty(), options);
});

Assert.Equal(StatusCode.DeadlineExceeded, ex.StatusCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@
namespace Dapr.E2E.Test
{
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Xunit;

public partial class E2ETests
Expand Down Expand Up @@ -58,6 +63,25 @@ public async Task TestServiceInvocationRequiresApiToken()
Assert.Equal("1", account.Id);
Assert.Equal(150, account.Balance);
}

[Fact]
public async Task TestHttpServiceInvocationWithTimeout()
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
using var client = new DaprClientBuilder()
.UseHttpEndpoint(this.HttpEndpoint)
.UseTimeout(TimeSpan.FromSeconds(1))
.Build();

await Assert.ThrowsAsync<TaskCanceledException>(async () =>
{
await client.InvokeMethodAsync<HttpResponseMessage>(
appId: this.AppId,
methodName: "DelayedResponse",
httpMethod: new HttpMethod("GET"),
cancellationToken: cts.Token);
});
}
}

internal class Transaction
Expand Down

0 comments on commit ee1a0a5

Please sign in to comment.