Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/Dapr.Client/DaprClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public abstract class DaprClient : IDisposable
/// </summary>
/// <param name="appId">
/// An optional <c>app-id</c>. If specified, the <c>app-id</c> will be configured as the value of
/// <see cref="HttpClient.BaseAddress" /> so that relative URIs can be used.
/// <see cref="HttpClient.BaseAddress" /> so that relative URIs can be used. It is mandatory to set this parameter if your app-id contains at least one upper letter.
/// If some requests use absolute URL with an app-id which contains at least one upper letter, it will not work, the workaround is to create one HttpClient for each app-id with the app-ip parameter set.
/// </param>
/// <param name="daprEndpoint">The HTTP endpoint of the Dapr process to use for service invocation calls.</param>
/// <param name="daprApiToken">The token to be added to all request headers to Dapr runtime.</param>
Expand All @@ -80,7 +81,8 @@ public static HttpClient CreateInvokeHttpClient(string appId = null, string dapr
var handler = new InvocationHandler()
{
InnerHandler = new HttpClientHandler(),
DaprApiToken = daprApiToken
DaprApiToken = daprApiToken,
DefaultAppId = appId,
};

if (daprEndpoint is string)
Expand Down Expand Up @@ -210,7 +212,7 @@ public abstract Task PublishEventAsync(
string topicName,
Dictionary<string, string> metadata,
CancellationToken cancellationToken = default);

/// <summary>
/// // Bulk Publishes multiple events to the specified topic.
/// </summary>
Expand Down
20 changes: 18 additions & 2 deletions src/Dapr.Client/InvocationHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Copyright 2021 The Dapr Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -82,6 +82,12 @@ public string DaprEndpoint
}
}

/// <summary>
/// Gets or sets the default AppId used for service invocation
/// </summary>
/// <returns>The AppId used for service invocation</returns>
public string? DefaultAppId { get; set; }

// Internal for testing
internal string? DaprApiToken
{
Expand Down Expand Up @@ -128,13 +134,23 @@ internal bool TryRewriteUri(Uri? uri, [NotNullWhen(true)] out Uri? rewritten)
return false;
}

string host;

if (this.DefaultAppId is not null && uri.Host.Equals(this.DefaultAppId, StringComparison.InvariantCultureIgnoreCase))
{
host = this.DefaultAppId;
}
else
{
host = uri.Host;
}

var builder = new UriBuilder(uri)
{
Scheme = this.parsedEndpoint.Scheme,
Host = this.parsedEndpoint.Host,
Port = this.parsedEndpoint.Port,
Path = $"/v1.0/invoke/{uri.Host}/method" + uri.AbsolutePath,
Path = $"/v1.0/invoke/{host}/method" + uri.AbsolutePath,
};

rewritten = builder.Uri;
Expand Down
2 changes: 1 addition & 1 deletion test/Dapr.Client.Test/DaprClientTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Copyright 2021 The Dapr Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
86 changes: 72 additions & 14 deletions test/Dapr.Client.Test/InvocationHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// Copyright 2021 The Dapr Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,8 +30,8 @@ public class InvocationHandlerTests
public void DaprEndpoint_InvalidScheme()
{
var handler = new InvocationHandler();
var ex = Assert.Throws<ArgumentException>(() =>
{
var ex = Assert.Throws<ArgumentException>(() =>
{
handler.DaprEndpoint = "ftp://localhost:3500";
});

Expand All @@ -43,7 +43,7 @@ public void DaprEndpoint_InvalidUri()
{
var handler = new InvocationHandler();
Assert.Throws<UriFormatException>(() =>
{
{
handler.DaprEndpoint = "";
});

Expand Down Expand Up @@ -79,30 +79,63 @@ public void TryRewriteUri_FailsForRelativeUris()
}

[Theory]
[InlineData("http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
public void TryRewriteUri_RewritesUriToDaprInvoke(string uri, string expected)
[InlineData(null, "http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("bank", "http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("Bank", "http://bank", "https://some.host:3499/v1.0/invoke/Bank/method/")]
[InlineData("invalid", "http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://Bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("Bank", "http://Bank", "https://some.host:3499/v1.0/invoke/Bank/method/")]
[InlineData("bank", "http://Bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("invalid", "http://Bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("bank", "http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("invalid", "http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://Bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("Bank", "http://Bank:3939", "https://some.host:3499/v1.0/invoke/Bank/method/")]
[InlineData("invalid", "http://Bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("app-id.with.dots", "http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("invalid", "http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData(null, "http://App-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("App-id.with.dots", "http://App-id.with.dots", "https://some.host:3499/v1.0/invoke/App-id.with.dots/method/")]
[InlineData("invalid", "http://App-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData(null, "http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("bank", "http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("invalid", "http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://Bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("Bank", "http://Bank:3939/", "https://some.host:3499/v1.0/invoke/Bank/method/")]
[InlineData("invalid", "http://Bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData(null, "http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("bank", "http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("invalid", "http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData(null, "http://Bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("Bank", "http://Bank:3939/some/path", "https://some.host:3499/v1.0/invoke/Bank/method/some/path")]
[InlineData("invalid", "http://Bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData(null, "http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
[InlineData("bank", "http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
[InlineData("invalid", "http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
[InlineData(null, "http://Bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
[InlineData("Bank", "http://Bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/Bank/method/some/path?q=test&p=another#fragment")]
[InlineData("invalid", "http://Bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
public void TryRewriteUri_WithNoAppId_RewritesUriToDaprInvoke(string? appId, string uri, string expected)
{
var handler = new InvocationHandler()
{
DaprEndpoint = "https://some.host:3499",
DefaultAppId = appId,
};

Assert.True(handler.TryRewriteUri(new Uri(uri), out var rewritten));
Assert.Equal(expected, rewritten!.OriginalString);
}

[Fact]
public async Task SendAsync_InvalidUri_ThrowsException()
public async Task SendAsync_InvalidNotSetUri_ThrowsException()
{
var handler = new InvocationHandler();
var ex = await Assert.ThrowsAsync<ArgumentException>(async () =>
{
await CallSendAsync(handler, new HttpRequestMessage(){ }); // No URI set
await CallSendAsync(handler, new HttpRequestMessage() { }); // No URI set
});

Assert.Contains("The request URI '' is not a valid Dapr service invocation destination.", ex.Message);
Expand Down Expand Up @@ -132,6 +165,31 @@ public async Task SendAsync_RewritesUri()
Assert.False(request.Headers.TryGetValues("dapr-api-token", out _));
}

[Fact]
public async Task SendAsync_RewritesUri_AndAppId()
{
var uri = "http://bank/accounts/17?";

var capture = new CaptureHandler();
var handler = new InvocationHandler()
{
InnerHandler = capture,

DaprEndpoint = "https://localhost:5000",
DaprApiToken = null,
DefaultAppId = "Bank"
};

var request = new HttpRequestMessage(HttpMethod.Post, uri);
var response = await CallSendAsync(handler, request);

Assert.Equal("https://localhost:5000/v1.0/invoke/Bank/method/accounts/17?", capture.RequestUri?.OriginalString);
Assert.Null(capture.DaprApiToken);

Assert.Equal(uri, request.RequestUri?.OriginalString);
Assert.False(request.Headers.TryGetValues("dapr-api-token", out _));
}

[Fact]
public async Task SendAsync_RewritesUri_AndAddsApiToken()
{
Expand Down Expand Up @@ -164,7 +222,7 @@ private async Task<HttpResponseMessage> CallSendAsync(InvocationHandler handler,

try
{
return await (Task<HttpResponseMessage>)method!.Invoke(handler, new object[]{ message, cancellationToken, })!;
return await (Task<HttpResponseMessage>)method!.Invoke(handler, new object[] { message, cancellationToken, })!;
}
catch (TargetInvocationException tie) // reflection always adds an extra layer of exceptions.
{
Expand Down