From 55e168fac3661c49cd5189dcf365e51c18f0a3be Mon Sep 17 00:00:00 2001 From: Edwin van Wijk Date: Thu, 24 Sep 2020 19:36:47 +0200 Subject: [PATCH] Add ability to specify default DaprClient options to AddDapr (#394) * Add fix for issue 390 * Move JsonSerializer defaults to DaprClientBuilder ctor * Update samples to reflect changes * Update unit-tests to reflect latest changes * Remove obsolete using statements * Change internal fields to internal properties * Change internal fields to internal properties --- samples/AspNetCore/ControllerSample/Readme.md | 14 ++++-- .../AspNetCore/ControllerSample/Startup.cs | 8 +--- samples/AspNetCore/RoutingSample/Readme.md | 10 +++- .../DaprMvcBuilderExtensions.cs | 7 ++- src/Dapr.Client/DaprClientBuilder.cs | 25 +++++++--- src/Dapr.Client/DaprClientGrpc.cs | 6 +++ .../DaprClientBuilderTest.cs | 27 +++++++++++ .../DaprMvcBuilderExtensionsTest.cs | 48 +++++++++++++++++++ 8 files changed, 124 insertions(+), 21 deletions(-) create mode 100644 test/Dapr.AspNetCore.Test/DaprClientBuilderTest.cs create mode 100644 test/Dapr.AspNetCore.Test/DaprMvcBuilderExtensionsTest.cs diff --git a/samples/AspNetCore/ControllerSample/Readme.md b/samples/AspNetCore/ControllerSample/Readme.md index a137073c..9004a01c 100644 --- a/samples/AspNetCore/ControllerSample/Readme.md +++ b/samples/AspNetCore/ControllerSample/Readme.md @@ -1,6 +1,6 @@ # ASP.NET Core Controller Sample -This sample shows using Dapr with ASP.NET Core routing. This application is a simple and not-so-secure banking application. The application uses the Dapr state-store for its data storage. +This sample shows using Dapr with ASP.NET Core controllers. This application is a simple and not-so-secure banking application. The application uses the Dapr state-store for its data storage. It exposes the following endpoints over HTTP: - GET `/{account}`: Get the balance for the account specified by `id` @@ -13,7 +13,7 @@ The application also registers for pub/sub with the `deposit` and `withdraw` top To run the sample locally run this comment in this directory: ```sh - dapr run --app-id routing --app-port 5000 dotnet run + dapr run --app-id controller --app-port 5000 dotnet run ``` The application will listen on port 5000 for HTTP. @@ -136,13 +136,19 @@ On Windows: ```C# public void ConfigureServices(IServiceCollection services) { - services.AddControllers().AddDapr(); + services.AddControllers().AddDapr(builder => + builder.UseJsonSerializationOptions( + new JsonSerializerOptions() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true, + })); ... } ``` - `AddDapr()` registers the Dapr integration with controllers. This also registers the `StateClient` service with the dependency injection container. This service can be used to interact with the Dapr state-store. + `AddDapr()` registers the Dapr integration with controllers. This also registers the `DaprClient` service with the dependency injection container (using the sepcified `DaprClientBuilder` for settings options). This service can be used to interact with the dapr runtime (e.g. invoke services, publish messages, interact with a state-store, ...). --- diff --git a/samples/AspNetCore/ControllerSample/Startup.cs b/samples/AspNetCore/ControllerSample/Startup.cs index e1aa46c9..877ecb80 100644 --- a/samples/AspNetCore/ControllerSample/Startup.cs +++ b/samples/AspNetCore/ControllerSample/Startup.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------ +// ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // ------------------------------------------------------------ @@ -38,12 +38,6 @@ namespace ControllerSample public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddDapr(); - - services.AddSingleton(new JsonSerializerOptions() - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - PropertyNameCaseInsensitive = true, - }); } /// diff --git a/samples/AspNetCore/RoutingSample/Readme.md b/samples/AspNetCore/RoutingSample/Readme.md index 003ca130..dd9209bb 100644 --- a/samples/AspNetCore/RoutingSample/Readme.md +++ b/samples/AspNetCore/RoutingSample/Readme.md @@ -134,13 +134,19 @@ On Windows: ```C# public void ConfigureServices(IServiceCollection services) { - services.AddDaprClient(); + services.AddDaprClient(builder => + builder.UseJsonSerializationOptions( + new JsonSerializerOptions() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true, + })); ... } ``` - `AddDaprClient()` registers the `StateClient` service with the dependency injection container. This service can be used to interact with the Dapr state-store. + `AddDaprClient()` registers the `DaprClient` service with the dependency injection container (using the sepcified `DaprClientBuilder` for settings options). This service can be used to interact with the dapr runtime (e.g. invoke services, publish messages, interact with a state-store, ...). --- diff --git a/src/Dapr.AspNetCore/DaprMvcBuilderExtensions.cs b/src/Dapr.AspNetCore/DaprMvcBuilderExtensions.cs index 24257612..30d2f5ad 100644 --- a/src/Dapr.AspNetCore/DaprMvcBuilderExtensions.cs +++ b/src/Dapr.AspNetCore/DaprMvcBuilderExtensions.cs @@ -6,8 +6,10 @@ namespace Microsoft.Extensions.DependencyInjection { using System; + using System.Text.Json; using Dapr; using Dapr.AspNetCore; + using Dapr.Client; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; @@ -20,8 +22,9 @@ namespace Microsoft.Extensions.DependencyInjection /// Adds Dapr integration for MVC to the provided . /// /// The . + /// The (optional) to use for configuring the DaprClient. /// The builder. - public static IMvcBuilder AddDapr(this IMvcBuilder builder) + public static IMvcBuilder AddDapr(this IMvcBuilder builder, Action configureClient = null) { if (builder is null) { @@ -35,7 +38,7 @@ namespace Microsoft.Extensions.DependencyInjection return builder; } - builder.Services.AddDaprClient(); + builder.Services.AddDaprClient(configureClient); builder.Services.AddSingleton(); builder.Services.AddSingleton(); diff --git a/src/Dapr.Client/DaprClientBuilder.cs b/src/Dapr.Client/DaprClientBuilder.cs index ba25a037..48703fae 100644 --- a/src/Dapr.Client/DaprClientBuilder.cs +++ b/src/Dapr.Client/DaprClientBuilder.cs @@ -14,10 +14,19 @@ namespace Dapr.Client /// public sealed class DaprClientBuilder { - const string defaultDaprGrpcPort = "50001"; - string daprEndpoint; - JsonSerializerOptions jsonSerializerOptions; - GrpcChannelOptions gRPCChannelOptions; + private const string defaultDaprGrpcPort = "50001"; + private string daprEndpoint; + private JsonSerializerOptions jsonSerializerOptions; + private GrpcChannelOptions gRPCChannelOptions; + + // property exposed for testing purposes + internal string DaprEndpoint => this.daprEndpoint; + + // property exposed for testing purposes + internal JsonSerializerOptions JsonSerializerOptions => this.jsonSerializerOptions; + + // property exposed for testing purposes + internal GrpcChannelOptions GRPCChannelOptions => this.gRPCChannelOptions; /// @@ -26,13 +35,17 @@ namespace Dapr.Client public DaprClientBuilder() { var daprGrpcPort = Environment.GetEnvironmentVariable("DAPR_GRPC_PORT") ?? defaultDaprGrpcPort; - this.daprEndpoint = $"http://127.0.0.1:{daprGrpcPort}"; + this.daprEndpoint = $"http://127.0.0.1:{daprGrpcPort}"; + this.jsonSerializerOptions = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }; } /// /// Overrides the default endpoint used by IDaprClient for conencting to Dapr runtime. /// - /// Endpoint to use for making calls to Dapr runtime. + /// Endpoint to use for making calls to Dapr runtime. /// Default endpoint used is http://127.0.0.1:DAPR_GRPC_PORT. /// DaprClientBuilder instance. public DaprClientBuilder UseEndpoint(string daprEndpoint) diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index 523fcfac..5a6aca83 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -26,6 +26,12 @@ namespace Dapr.Client private readonly Autogenerated.Dapr.DaprClient client; private readonly JsonSerializerOptions jsonSerializerOptions; + // property exposed for testing purposes + internal Autogenerated.Dapr.DaprClient Client => client; + + // property exposed for testing purposes + internal JsonSerializerOptions JsonSerializerOptions => jsonSerializerOptions; + /// /// Initializes a new instance of the class. /// diff --git a/test/Dapr.AspNetCore.Test/DaprClientBuilderTest.cs b/test/Dapr.AspNetCore.Test/DaprClientBuilderTest.cs new file mode 100644 index 00000000..db6eb90b --- /dev/null +++ b/test/Dapr.AspNetCore.Test/DaprClientBuilderTest.cs @@ -0,0 +1,27 @@ +using System.Text.Json; +using Dapr.Client; +using Xunit; + +namespace Dapr.AspNetCore.Test +{ + public class DaprClientBuilderTest + { + [Fact] + public void DaprClientBuilder_UsesPropertyNameCaseHandlingInsensitiveByDefault() + { + DaprClientBuilder builder = new DaprClientBuilder(); + Assert.True(builder.JsonSerializerOptions.PropertyNameCaseInsensitive); + } + + [Fact] + public void DaprClientBuilder_UsesPropertyNameCaseHandlingAsSpecified() + { + DaprClientBuilder builder = new DaprClientBuilder(); + builder.UseJsonSerializationOptions(new JsonSerializerOptions + { + PropertyNameCaseInsensitive = false + }); + Assert.False(builder.JsonSerializerOptions.PropertyNameCaseInsensitive); + } + } +} diff --git a/test/Dapr.AspNetCore.Test/DaprMvcBuilderExtensionsTest.cs b/test/Dapr.AspNetCore.Test/DaprMvcBuilderExtensionsTest.cs new file mode 100644 index 00000000..790584f5 --- /dev/null +++ b/test/Dapr.AspNetCore.Test/DaprMvcBuilderExtensionsTest.cs @@ -0,0 +1,48 @@ +using System; +using System.Text.Json; +using Dapr.Client; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Dapr.AspNetCore.Test +{ + public class DaprMvcBuilderExtensionsTest + { + [Fact] + public void AddDapr_UsesSpecifiedDaprClientBuilderConfig() + { + var services = new ServiceCollection(); + + var clientBuilder = new Action( + builder => builder.UseJsonSerializationOptions( + new JsonSerializerOptions() + { + PropertyNameCaseInsensitive = false + } + ) + ); + + services.AddControllers().AddDapr(clientBuilder); + + var serviceProvider = services.BuildServiceProvider(); + + DaprClientGrpc daprClient = serviceProvider.GetService() as DaprClientGrpc; + + Assert.False(daprClient.JsonSerializerOptions.PropertyNameCaseInsensitive); + } + + [Fact] + public void AddDapr_UsesDefaultDaprClientBuilderConfig() + { + var services = new ServiceCollection(); + + services.AddControllers().AddDapr(); + + var serviceProvider = services.BuildServiceProvider(); + + DaprClientGrpc daprClient = serviceProvider.GetService() as DaprClientGrpc; + + Assert.True(daprClient.JsonSerializerOptions.PropertyNameCaseInsensitive); + } + } +}