Send headers as metadata to sidecar (#397)

* Send headers as metadata to sidecar

* Add HTTP headers test

* Allow different kinds of dictionaries
This commit is contained in:
Sander Molenkamp 2020-09-25 01:07:44 +02:00 committed by GitHub
parent 55e168fac3
commit 100dbe9794
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 4 deletions

View File

@ -249,6 +249,7 @@ namespace Dapr.Client
{
var protoHTTPExtension = new Autogenerated.HTTPExtension();
var contentType = "";
Metadata headers = null;
if (httpExtension != null)
{
@ -262,6 +263,15 @@ namespace Dapr.Client
}
}
if (httpExtension.Headers != null)
{
headers = new Metadata();
foreach (var (key, value) in httpExtension.Headers)
{
headers.Add(key, value);
}
}
contentType = httpExtension.ContentType ?? Constants.ContentTypeApplicationJson;
}
else
@ -280,15 +290,16 @@ namespace Dapr.Client
var request = new Autogenerated.InvokeServiceRequest()
{
Id = appId,
Message = invokeRequest,
};
return await this.MakeGrpcCallHandleError(
options => client.InvokeServiceAsync(request, options),
headers,
cancellationToken);
}
#endregion
#region State Apis
@ -660,9 +671,23 @@ namespace Dapr.Client
/// <param name="callFunc"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task<TResponse> MakeGrpcCallHandleError<TResponse>(Func<CallOptions, AsyncUnaryCall<TResponse>> callFunc, CancellationToken cancellationToken = default)
private Task<TResponse> MakeGrpcCallHandleError<TResponse>(Func<CallOptions, AsyncUnaryCall<TResponse>> callFunc, CancellationToken cancellationToken = default)
{
var callOptions = new CallOptions(headers: new Metadata(), cancellationToken: cancellationToken);
return MakeGrpcCallHandleError<TResponse>(callFunc, null, cancellationToken);
}
/// <summary>
/// Makes Grpc call using the cancellationToken and handles Errors.
/// All common exception handling logic will reside here.
/// </summary>
/// <typeparam name="TResponse"></typeparam>
/// <param name="callFunc"></param>
/// <param name="headers"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task<TResponse> MakeGrpcCallHandleError<TResponse>(Func<CallOptions, AsyncUnaryCall<TResponse>> callFunc, Metadata headers, CancellationToken cancellationToken = default)
{
var callOptions = new CallOptions(headers: headers ?? new Metadata(), cancellationToken: cancellationToken);
// add token for dapr api token based authentication
var daprApiToken = Environment.GetEnvironmentVariable("DAPR_API_TOKEN");

View File

@ -20,6 +20,7 @@ namespace Dapr.Client.Http
{
this.Verb = HTTPVerb.Post;
this.QueryString = new Dictionary<string, string>();
this.Headers = new Dictionary<string, string>();
}
/// <summary>
@ -35,7 +36,11 @@ namespace Dapr.Client.Http
/// <summary>
/// This represents a collection of query strings.
/// </summary>
public Dictionary<string, string> QueryString { get; set; }
public IDictionary<string, string> QueryString { get; set; }
/// <summary>
/// This represents a collection of HTTP headers.
/// </summary>
public IDictionary<string, string> Headers { get; set; }
}
}

View File

@ -17,6 +17,7 @@ namespace Dapr.Client.Test
using Grpc.Core;
using Grpc.Net.Client;
using Xunit;
using System.Linq;
public class InvokeApiTest
{
@ -80,6 +81,35 @@ namespace Dapr.Client.Test
envelope.Message.HttpExtension.Querystring.Count.Should().Be(0);
}
[Fact]
public void InvokeMethodAsync_HeadersSpecifiedByUser_ValidateRequest()
{
// Configure Client
var httpClient = new TestHttpClient();
var daprClient = new DaprClientBuilder()
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
.Build();
var headers = new Dictionary<string, string>();
headers.Add("Authorization", "Bearer foo");
headers.Add("X-Custom", "bar");
var httpExtension = new Http.HTTPExtension()
{
Verb = HTTPVerb.Post,
Headers = headers
};
var task = daprClient.InvokeMethodAsync<Response>("app1", "mymethod", httpExtension);
// Get Request and validate
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
entry.Request.Headers.Authorization.Scheme.Should().Be("Bearer");
entry.Request.Headers.Authorization.Parameter.Should().Be("foo");
entry.Request.Headers.GetValues("X-Custom").FirstOrDefault().Should().Be("bar");
}
[Fact]
public async Task InvokeMethodAsync_CanInvokeMethodWithReturnTypeAndData()
{