Skip to content

Commit 3f80927

Browse files
committed
Simplify validation and make it possible to opt-out from it
1 parent 058a17b commit 3f80927

File tree

7 files changed

+76
-16
lines changed

7 files changed

+76
-16
lines changed

src/Tests/ApprovalFiles/APIApprovals.Approve.approved.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,11 @@ namespace NServiceBus
100100
}
101101
public abstract class TopicTopology
102102
{
103-
protected TopicTopology(NServiceBus.Transport.AzureServiceBus.TopologyOptions options) { }
103+
protected TopicTopology(NServiceBus.Transport.AzureServiceBus.TopologyOptions options, Microsoft.Extensions.Options.IValidateOptions<NServiceBus.Transport.AzureServiceBus.TopologyOptions> optionsValidator) { }
104104
[System.Obsolete("Use `MigrationTopology.IsHierarchy` instead. The member currently throws a NotImp" +
105105
"lementedException. Will be removed in version 6.0.0.", true)]
106106
public bool IsHierarchy { get; }
107+
public Microsoft.Extensions.Options.IValidateOptions<NServiceBus.Transport.AzureServiceBus.TopologyOptions> OptionsValidator { get; set; }
107108
[System.Obsolete("Use `MigrationTopology.TopicToPublishTo` instead. The member currently throws a N" +
108109
"otImplementedException. Will be removed in version 6.0.0.", true)]
109110
public string TopicToPublishTo { get; }
@@ -255,6 +256,11 @@ namespace NServiceBus.Transport.AzureServiceBus
255256
[System.Text.Json.Serialization.JsonInclude]
256257
public System.Collections.Generic.Dictionary<string, System.Collections.Generic.HashSet<string>> SubscribedEventToTopicsMap { get; init; }
257258
}
259+
public sealed class TopologyOptionsDisableValidationValidator : Microsoft.Extensions.Options.IValidateOptions<NServiceBus.Transport.AzureServiceBus.TopologyOptions>
260+
{
261+
public TopologyOptionsDisableValidationValidator() { }
262+
public Microsoft.Extensions.Options.ValidateOptionsResult Validate(string name, NServiceBus.Transport.AzureServiceBus.TopologyOptions options) { }
263+
}
258264
[System.Text.Json.Serialization.JsonSerializable(typeof(NServiceBus.Transport.AzureServiceBus.MigrationTopologyOptions))]
259265
[System.Text.Json.Serialization.JsonSerializable(typeof(NServiceBus.Transport.AzureServiceBus.TopologyOptions))]
260266
[System.Text.Json.Serialization.JsonSourceGenerationOptions(WriteIndented=true)]

src/Tests/EventRouting/MigrationTopologyTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,22 @@ public void Should_self_validate_consistency()
5757
Approver.Verify(validationException.Message);
5858
}
5959

60+
// With the generic host validation can already be done at startup and this allows disabling further validation
61+
// for advanced scenarios to save startup time.
62+
[Test]
63+
public void Should_allow_disabling_validation()
64+
{
65+
var topologyOptions = new MigrationTopologyOptions
66+
{
67+
TopicToPublishTo = new string('a', 261), TopicToSubscribeOn = new string('a', 261)
68+
};
69+
70+
var topology = TopicTopology.FromOptions(topologyOptions);
71+
topology.OptionsValidator = new TopologyOptionsDisableValidationValidator();
72+
73+
Assert.DoesNotThrow(() => topology.Validate());
74+
}
75+
6076
class MyEvent;
6177
class MyEventMappedTwice;
6278
}

src/Tests/EventRouting/TopicPerEventTopologyTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,21 @@ public void Should_self_validate()
4242
Approver.Verify(validationException.Message);
4343
}
4444

45+
// With the generic host validation can already be done at startup and this allows disabling further validation
46+
// for advanced scenarios to save startup time.
47+
[Test]
48+
public void Should_allow_disabling_validation()
49+
{
50+
var topologyOptions = new TopologyOptions
51+
{
52+
PublishedEventToTopicsMap = { { typeof(MyEvent).FullName, new string('c', 261) } }
53+
};
54+
55+
var topology = TopicTopology.FromOptions(topologyOptions);
56+
topology.OptionsValidator = new TopologyOptionsDisableValidationValidator();
57+
58+
Assert.DoesNotThrow(() => topology.Validate());
59+
}
60+
4561
class MyEvent;
4662
}

src/Transport/EventRouting/MigrationTopology.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
namespace NServiceBus.Transport.AzureServiceBus;
22

33
using System;
4+
using Microsoft.Extensions.Options;
45

56
/// <summary>
67
/// Topology that allows mixing of single-topic and topic-per-event approaches in order to allow gradual migration to the topic-per-event topology.
78
/// </summary>
89
public sealed class MigrationTopology : TopicTopology
910
{
10-
internal MigrationTopology(MigrationTopologyOptions options) : base(options) => Options = options;
11+
internal MigrationTopology(MigrationTopologyOptions options) : base(options,
12+
new OptionsValidatorDecorator(new MigrationTopologyOptionsValidator())) =>
13+
Options = options;
1114

1215
/// <summary>
1316
/// Gets the topic name of the topic where all single-topic events are published to.
@@ -182,4 +185,13 @@ protected override string GetPublishDestinationCore(string eventTypeFullName)
182185
}
183186

184187
internal override SubscriptionManager CreateSubscriptionManager(SubscriptionManagerCreationOptions creationOptions) => new MigrationTopologySubscriptionManager(creationOptions, Options);
188+
189+
sealed class OptionsValidatorDecorator(IValidateOptions<MigrationTopologyOptions> decorated)
190+
: IValidateOptions<TopologyOptions>
191+
{
192+
public ValidateOptionsResult Validate(string? name, TopologyOptions options) =>
193+
decorated.Validate(name,
194+
options as MigrationTopologyOptions ??
195+
throw new Exception("The options to be validated must be of type MigrationTopologyOptions."));
196+
}
185197
}

src/Transport/EventRouting/TopicPerEventTopology.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace NServiceBus.Transport.AzureServiceBus;
88
/// </summary>
99
public sealed class TopicPerEventTopology : TopicTopology
1010
{
11-
internal TopicPerEventTopology(TopologyOptions options) : base(options)
11+
internal TopicPerEventTopology(TopologyOptions options) : base(options, new TopologyOptionsValidator())
1212
{
1313
}
1414

src/Transport/EventRouting/TopicTopology.cs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ public abstract partial class TopicTopology
1414
/// <summary>
1515
/// Allows creating topology instances based on serializable state
1616
/// </summary>
17-
protected TopicTopology(TopologyOptions options) => Options = options;
17+
protected TopicTopology(TopologyOptions options, IValidateOptions<TopologyOptions> optionsValidator)
18+
{
19+
Options = options;
20+
OptionsValidator = optionsValidator;
21+
}
22+
23+
/// <summary>
24+
/// Gets or sets the options validator used to validate the consistency of the provided options.
25+
/// </summary>
26+
public IValidateOptions<TopologyOptions> OptionsValidator { get; set; }
1827

1928
internal TopologyOptions Options { get; }
2029

@@ -77,18 +86,7 @@ public static MigrationTopology MigrateFromTopicHierarchy(string topicToPublishT
7786
/// </summary>
7887
public void Validate()
7988
{
80-
ValidateOptionsResult validationResult;
81-
82-
if (Options is MigrationTopologyOptions migrationOptions)
83-
{
84-
var migrationOptionsValidator = new MigrationTopologyOptionsValidator();
85-
validationResult = migrationOptionsValidator.Validate(null, migrationOptions);
86-
}
87-
else
88-
{
89-
var validator = new TopologyOptionsValidator();
90-
validationResult = validator.Validate(null, Options);
91-
}
89+
ValidateOptionsResult validationResult = OptionsValidator.Validate(null, Options);
9290

9391
if (validationResult.Succeeded)
9492
{
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace NServiceBus.Transport.AzureServiceBus;
2+
3+
using Microsoft.Extensions.Options;
4+
5+
/// <summary>
6+
/// Does not validate the provided <see cref="TopologyOptions"/>.
7+
/// </summary>
8+
public sealed class TopologyOptionsDisableValidationValidator : IValidateOptions<TopologyOptions>
9+
{
10+
/// <inheritdoc />
11+
public ValidateOptionsResult Validate(string name, TopologyOptions options) => ValidateOptionsResult.Success;
12+
}

0 commit comments

Comments
 (0)