Skip to content

Commit 65c92e4

Browse files
committed
Fix EnableEntitySupport overwriting
1 parent f4c3a44 commit 65c92e4

File tree

4 files changed

+95
-66
lines changed

4 files changed

+95
-66
lines changed

src/Client/Core/DependencyInjection/DefaultDurableTaskClientBuilder.cs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,20 @@ namespace Microsoft.DurableTask.Client;
99
/// <summary>
1010
/// Default builder for <see cref="IDurableTaskClientBuilder" />.
1111
/// </summary>
12-
public class DefaultDurableTaskClientBuilder : IDurableTaskClientBuilder
12+
/// <remarks>
13+
/// Initializes a new instance of the <see cref="DefaultDurableTaskClientBuilder"/> class.
14+
/// </remarks>
15+
/// <param name="name">The name of the builder.</param>
16+
/// <param name="services">The service collection.</param>
17+
public class DefaultDurableTaskClientBuilder(string? name, IServiceCollection services) : IDurableTaskClientBuilder
1318
{
1419
Type? buildTarget;
1520

16-
/// <summary>
17-
/// Initializes a new instance of the <see cref="DefaultDurableTaskClientBuilder"/> class.
18-
/// </summary>
19-
/// <param name="name">The name of the builder.</param>
20-
/// <param name="services">The service collection.</param>
21-
public DefaultDurableTaskClientBuilder(string? name, IServiceCollection services)
22-
{
23-
this.Name = name ?? Options.DefaultName;
24-
this.Services = services;
25-
}
26-
2721
/// <inheritdoc/>
28-
public string Name { get; }
22+
public string Name { get; } = name ?? Options.DefaultName;
2923

3024
/// <inheritdoc/>
31-
public IServiceCollection Services { get; }
25+
public IServiceCollection Services { get; } = services;
3226

3327
/// <inheritdoc/>
3428
public Type? BuildTarget

src/Client/Core/DurableTaskClientOptions.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace Microsoft.DurableTask.Client;
1111
public class DurableTaskClientOptions
1212
{
1313
DataConverter dataConverter = JsonDataConverter.Default;
14+
bool enableEntitySupport;
1415

1516
/// <summary>
1617
/// Gets or sets the data converter. Default value is <see cref="JsonDataConverter.Default" />.
@@ -50,7 +51,15 @@ public DataConverter DataConverter
5051
/// Gets or sets a value indicating whether this client should support entities. If true, all instance ids starting with '@' are reserved for entities,
5152
/// and validation checks are performed where appropriate.
5253
/// </summary>
53-
public bool EnableEntitySupport { get; set; }
54+
public bool EnableEntitySupport
55+
{
56+
get => this.enableEntitySupport;
57+
set
58+
{
59+
this.enableEntitySupport = value;
60+
this.EntitySupportExplicitlySet = true;
61+
}
62+
}
5463

5564
/// <summary>
5665
/// Gets a value indicating whether <see cref="DataConverter" /> was explicitly set or not.
@@ -63,6 +72,11 @@ public DataConverter DataConverter
6372
/// </remarks>
6473
internal bool DataConverterExplicitlySet { get; private set; }
6574

75+
/// <summary>
76+
/// Gets a value indicating whether <see cref="EnableEntitySupport" /> was explicitly set or not.
77+
/// </summary>
78+
internal bool EntitySupportExplicitlySet { get; private set; }
79+
6680
/// <summary>
6781
/// Applies these option values to another.
6882
/// </summary>
@@ -72,8 +86,15 @@ internal void ApplyTo(DurableTaskClientOptions other)
7286
if (other is not null)
7387
{
7488
// Make sure to keep this up to date as values are added.
75-
other.DataConverter = this.DataConverter;
76-
other.EnableEntitySupport = this.EnableEntitySupport;
89+
if (!other.DataConverterExplicitlySet)
90+
{
91+
other.DataConverter = this.DataConverter;
92+
}
93+
94+
if (!other.EntitySupportExplicitlySet)
95+
{
96+
other.EnableEntitySupport = this.EnableEntitySupport;
97+
}
7798
}
7899
}
79100
}

src/Client/OrchestrationServiceClientShim/DependencyInjection/DurableTaskClientBuilderExtensions.cs

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using DurableTask.Core.Entities;
66
using Microsoft.DurableTask.Client.OrchestrationServiceClientShim;
77
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.DependencyInjection.Extensions;
89
using Microsoft.Extensions.Options;
910

1011
namespace Microsoft.DurableTask.Client;
@@ -56,55 +57,74 @@ public static IDurableTaskClientBuilder UseOrchestrationService(
5657
{
5758
Check.NotNull(builder);
5859
Check.NotNull(configure);
59-
builder.Services.Configure(builder.Name, configure);
60-
builder.Services.AddOptions<ShimDurableTaskClientOptions>(builder.Name)
61-
.PostConfigure<IServiceProvider>((opt, sp) =>
62-
{
63-
ConfigureClient(sp, opt);
64-
ConfigureEntities(builder.Name, sp, opt);
65-
})
66-
.Validate(x => x.Client is not null, "ShimDurableTaskClientOptions.Client must not be null.")
67-
.Validate(
68-
x => !x.EnableEntitySupport || x.Entities.Queries is not null,
69-
"ShimDurableTaskClientOptions.Entities.Queries must not be null when entity support is enabled.");
70-
60+
builder.Services.AddOptions<ShimDurableTaskClientOptions>(builder.Name).Configure(configure);
61+
builder.Services.TryAddSingleton<IPostConfigureOptions<ShimDurableTaskClientOptions>, OptionsConfigure>();
62+
builder.Services.TryAddSingleton<IValidateOptions<ShimDurableTaskClientOptions>, OptionsValidator>();
7163
return builder.UseBuildTarget<ShimDurableTaskClient, ShimDurableTaskClientOptions>();
7264
}
7365

74-
static void ConfigureClient(IServiceProvider services, ShimDurableTaskClientOptions options)
66+
static IEntityOrchestrationService? GetEntityService(
67+
IServiceProvider services, ShimDurableTaskClientOptions options)
7568
{
76-
if (options.Client is not null)
77-
{
78-
return;
79-
}
80-
81-
// Try to resolve client from service container.
82-
options.Client = services.GetService<IOrchestrationServiceClient>()
83-
?? services.GetService<IOrchestrationService>() as IOrchestrationServiceClient;
69+
return options.Client as IEntityOrchestrationService
70+
?? services.GetService<IEntityOrchestrationService>()
71+
?? services.GetService<IOrchestrationServiceClient>() as IEntityOrchestrationService
72+
?? services.GetService<IOrchestrationService>() as IEntityOrchestrationService;
8473
}
8574

86-
static void ConfigureEntities(string name, IServiceProvider services, ShimDurableTaskClientOptions options)
75+
class OptionsConfigure(IServiceProvider services) : IPostConfigureOptions<ShimDurableTaskClientOptions>
8776
{
88-
if (options.Entities.Queries is null)
77+
public void PostConfigure(string name, ShimDurableTaskClientOptions options)
8978
{
90-
options.Entities.Queries = services.GetService<EntityBackendQueries>()
91-
?? GetEntityService(services, options)?.EntityBackendQueries;
79+
ConfigureClient(services, options);
80+
ConfigureEntities(name, services, options); // Must be called after ConfigureClient.
9281
}
9382

94-
if (options.Entities.MaxSignalDelayTime is null)
83+
static void ConfigureClient(IServiceProvider services, ShimDurableTaskClientOptions options)
9584
{
96-
EntityBackendProperties? properties = services.GetService<IOptionsMonitor<EntityBackendProperties>>()?.Get(name)
97-
?? GetEntityService(services, options)?.EntityBackendProperties;
98-
options.Entities.MaxSignalDelayTime = properties?.MaximumSignalDelayTime;
85+
if (options.Client is not null)
86+
{
87+
return;
88+
}
89+
90+
// Try to resolve client from service container.
91+
options.Client = services.GetService<IOrchestrationServiceClient>()
92+
?? services.GetService<IOrchestrationService>() as IOrchestrationServiceClient;
93+
}
94+
95+
static void ConfigureEntities(string name, IServiceProvider services, ShimDurableTaskClientOptions options)
96+
{
97+
if (options.Entities.Queries is null)
98+
{
99+
options.Entities.Queries = services.GetService<EntityBackendQueries>()
100+
?? GetEntityService(services, options)?.EntityBackendQueries;
101+
}
102+
103+
if (options.Entities.MaxSignalDelayTime is null)
104+
{
105+
EntityBackendProperties? properties = services.GetService<IOptionsMonitor<EntityBackendProperties>>()?.Get(name)
106+
?? GetEntityService(services, options)?.EntityBackendProperties;
107+
options.Entities.MaxSignalDelayTime = properties?.MaximumSignalDelayTime;
108+
}
99109
}
100110
}
101111

102-
static IEntityOrchestrationService? GetEntityService(
103-
IServiceProvider services, ShimDurableTaskClientOptions options)
112+
class OptionsValidator : IValidateOptions<ShimDurableTaskClientOptions>
104113
{
105-
return services.GetService<IEntityOrchestrationService>()
106-
?? services.GetService<IOrchestrationService>() as IEntityOrchestrationService
107-
?? services.GetService<IOrchestrationServiceClient>() as IEntityOrchestrationService
108-
?? options.Client as IEntityOrchestrationService;
114+
public ValidateOptionsResult Validate(string name, ShimDurableTaskClientOptions options)
115+
{
116+
if (options.Client is null)
117+
{
118+
return ValidateOptionsResult.Fail("ShimDurableTaskClientOptions.Client must not be null.");
119+
}
120+
121+
if (options.EnableEntitySupport && options.Entities.Queries is null)
122+
{
123+
return ValidateOptionsResult.Fail(
124+
"ShimDurableTaskClientOptions.Entities.Queries must not be null when entity support is enabled.");
125+
}
126+
127+
return ValidateOptionsResult.Success;
128+
}
109129
}
110130
}

src/Client/OrchestrationServiceClientShim/ShimDurableEntityClient.cs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,14 @@ namespace Microsoft.DurableTask.Client.OrchestrationServiceClientShim;
1111
/// <summary>
1212
/// A shim client for interacting with entities backend via <see cref="IOrchestrationServiceClient"/>.
1313
/// </summary>
14-
class ShimDurableEntityClient : DurableEntityClient
14+
/// <remarks>
15+
/// Initializes a new instance of the <see cref="ShimDurableEntityClient"/> class.
16+
/// </remarks>
17+
/// <param name="name">The name of this client.</param>
18+
/// <param name="options">The client options..</param>
19+
class ShimDurableEntityClient(string name, ShimDurableTaskClientOptions options) : DurableEntityClient(name)
1520
{
16-
readonly ShimDurableTaskClientOptions options;
17-
18-
/// <summary>
19-
/// Initializes a new instance of the <see cref="ShimDurableEntityClient"/> class.
20-
/// </summary>
21-
/// <param name="name">The name of this client.</param>
22-
/// <param name="options">The client options..</param>
23-
public ShimDurableEntityClient(string name, ShimDurableTaskClientOptions options)
24-
: base(name)
25-
{
26-
this.options = Check.NotNull(options);
27-
}
21+
readonly ShimDurableTaskClientOptions options = Check.NotNull(options);
2822

2923
EntityBackendQueries Queries => this.options.Entities.Queries!;
3024

@@ -128,7 +122,7 @@ AsyncPageable<TMetadata> GetAllEntitiesAsync<TMetadata>(
128122
},
129123
cancellation);
130124

131-
return new Page<TMetadata>(result.Results.Select(select).ToList(), result.ContinuationToken);
125+
return new Page<TMetadata>([.. result.Results.Select(select)], result.ContinuationToken);
132126
});
133127
}
134128

0 commit comments

Comments
 (0)