Skip to content
11 changes: 10 additions & 1 deletion examples/Workflow/WorkflowConsoleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,16 @@
using var host = builder.Build();
host.Start();

using var daprClient = new DaprClientBuilder().Build();
DaprClient daprClient;
string apiToken = Environment.GetEnvironmentVariable("DAPR_API_TOKEN");
if (!string.IsNullOrEmpty(apiToken))
{
daprClient = new DaprClientBuilder().UseDaprApiToken(apiToken).Build();
}
else
{
daprClient = new DaprClientBuilder().Build();
}
Comment on lines +50 to +59

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need the using. After the initialization, you can just wrap the while in this:

using (daprClient)
{
    // Loop here.
}


// Wait for the sidecar to become available
while (!await daprClient.CheckHealthAsync())
Expand Down
64 changes: 62 additions & 2 deletions src/Dapr.Workflow/WorkflowServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
namespace Dapr.Workflow
{
using System;
using Grpc.Net.Client;
using Microsoft.DurableTask.Client;
using Microsoft.DurableTask.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System.Net.Http;

/// <summary>
/// Contains extension methods for using Dapr Workflow with dependency injection.
Expand Down Expand Up @@ -57,7 +59,19 @@ public static IServiceCollection AddDaprWorkflow(

if (TryGetGrpcAddress(out string address))
{
builder.UseGrpc(address);
string? apiToken = Environment.GetEnvironmentVariable("DAPR_API_TOKEN");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, please use var where you can.

if (!string.IsNullOrEmpty(apiToken))
{
serviceCollection.ConfigureDurableGrpcClient(apiToken);
HttpClient client = new HttpClient();
Comment thread
halspang marked this conversation as resolved.
Outdated
client.DefaultRequestHeaders.Add("Dapr-Api-Token", apiToken);
builder.UseGrpc(CreateChannel(client));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to repeat the code in the ConfigureDurableGrpcClient do we need both methods?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The address variable should be passed to the builder, otherwise if users configured Dapr to use a non-localhost endpoint, this will not be propagated correctly to the underlying Durable Task client. Good find by @alicejgibbons

}
else
{
builder.UseGrpc(address);
}

}
else
{
Expand Down Expand Up @@ -85,7 +99,19 @@ public static IServiceCollection AddDaprWorkflowClient(this IServiceCollection s
{
if (TryGetGrpcAddress(out string address))
{
builder.UseGrpc(address);
string? apiToken = Environment.GetEnvironmentVariable("DAPR_API_TOKEN");
if (!string.IsNullOrEmpty(apiToken))
{
services.ConfigureDurableGrpcClient(apiToken);
HttpClient client = new HttpClient();
Comment thread
halspang marked this conversation as resolved.
Outdated
client.DefaultRequestHeaders.Add("Dapr-Api-Token", apiToken);
builder.UseGrpc(CreateChannel(client));
}
else
{
builder.UseGrpc(address);
}

}
else
{
Expand Down Expand Up @@ -126,6 +152,40 @@ static bool TryGetGrpcAddress(out string address)
address = string.Empty;
return false;
}

static GrpcChannel CreateChannel(HttpClient client)
{
string address = "localhost";
string? daprPortStr = Environment.GetEnvironmentVariable("DAPR_GRPC_PORT");
if (int.TryParse(daprPortStr, out int daprGrpcPort))
{
// There is a bug in the Durable Task SDK that requires us to change the format of the address
// depending on the version of .NET that we're targeting. For now, we work around this manually.
#if NET6_0_OR_GREATER
address = $"http://localhost:{daprGrpcPort}";
#else
address = $"localhost:{daprGrpcPort}";
#endif
}
GrpcChannelOptions options = new() { HttpClient = client};
return GrpcChannel.ForAddress(address, options);
}
}

static class DaprDurableGrpcExtensions
{
const string ClientName = "durabletask-grpc";

public static IServiceCollection ConfigureDurableGrpcClient(this IServiceCollection services, string apiToken)
{
services.AddHttpClient(ClientName)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my understanding: Why do we need to add HttpClient while configuring Grpc Client?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under the hood, the gRPC client uses the HttpClient. It's all HTTP/2 for transport iirc.

.ConfigureHttpClient(client =>
{
client.DefaultRequestHeaders.Add("Dapr-Api-Token", apiToken);
});
return services;
}

}
}