From 37bd4ab30aa9c9d81ce0dd65ffc0d97323692b7e Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 22 Dec 2025 08:49:28 -0700 Subject: [PATCH 1/2] Fix hostname field input blocking in SCMU (#5238) # Fix hostname field input blocking in ServiceControl Management Utility **Fixes #5190** ## Problem The hostname fields in the ServiceControl Management Utility (SCMU) were blocking valid dash (`-`) characters from being typed, while allowing invalid characters like `/[]|`. This was caused by CheckBox controls intercepting keystrokes for nested TextBox controls in the add instance views. Users reported that typing `-` would not work but typing any of `/[]|` does work. The only workaround was to paste the dash character from the clipboard. ## Root Cause The issue occurred because: 1. TextBox controls for hostname input were nested inside CheckBox controls in the XAML layout 2. WPF CheckBox controls intercept certain keystrokes (including dashes) for their nested content 3. This prevented users from typing dashes directly into hostname fields, requiring copy/paste workarounds ## Solution Restructured the UI layout in the add instance views to separate CheckBox and Expander controls using a Grid-based horizontal layout. ### Before: ```xaml ``` ### After: ```xaml ``` Co-authored-by: Christian --- .../UI/InstanceAdd/ServiceControlAddView.xaml | 197 +++++++++++------- 1 file changed, 119 insertions(+), 78 deletions(-) diff --git a/src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddView.xaml b/src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddView.xaml index 950c834121..4b09b4623c 100644 --- a/src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddView.xaml +++ b/src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddView.xaml @@ -78,10 +78,29 @@ Foreground="{StaticResource ErrorBrush}" Text="Must select either an audit or an error instance." /> - - - - + + + + + + + + + + + + @@ -120,7 +139,7 @@ Text="{Binding ErrorPassword}" Visibility="{Binding ErrorPasswordEnabled, Converter={StaticResource boolToVis}}" /> - @@ -237,93 +256,114 @@ SelectedValue="{Binding ErrorEnableFullTextSearchOnBodies}" /> - - + + - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - + + + - - - + + - - - + - - - - - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - + - - - - + - - - + + + + From fd7d52e3cef2fd630d1c7ae886306432de94ccf6 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 23 Dec 2025 19:06:50 -0700 Subject: [PATCH 2/2] # Fix hostname validation in SCMU (#5241) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Fix hostname validation in SCMU ## Summary This PR completes the fix for issue #5190 by adding proper hostname validation to ServiceControl.Config. While PR #5238 partially addressed the issue by allowing dashes in hostnames, it didn't implement comprehensive hostname validation, leaving users able to enter invalid hostnames that would cause configuration issues. ## Background **Original Issue**: #5190 reported that ServiceControl.Config was not properly validating hostname fields, allowing users to enter invalid values that would cause runtime failures. **Previous Fix**: PR #5238 addressed part of the problem by allowing dashes in hostnames, but the validation was still incomplete and didn't prevent other invalid hostname formats. **This Fix**: Implements comprehensive RFC-compliant hostname validation using .NET's built-in `Uri.CheckHostName()` method. ## Validation Behavior The new validation accepts: - ✅ Valid DNS hostnames (server01, myhost.domain.com) - ✅ localhost - ✅ Hostnames with dashes (server-01, my-host.domain.com) - *previously fixed by PR #5238* * test case for IPV6 * fixing broken implementation for ips * adding missing test cases * Update src/ServiceControl.Config.Tests/Validation/EditAuditInstanceValidationTests.cs Co-authored-by: Nick Gallegos --- .../AddAuditInstanceValidationTests.cs | 29 +++++++++++++++++ .../AddErrorInstanceValidationTests.cs | 29 +++++++++++++++++ .../AddMonitoringInstanceValidationTests.cs | 28 +++++++++++++++++ .../EditAuditInstanceValidationTests.cs | 31 ++++++++++++++++++- .../EditErrorInstanceValidationTests.cs | 29 +++++++++++++++++ .../EditMonitoringInstanceValidationTests.cs | 29 +++++++++++++++++ .../ServiceControlAddViewModelValidator.cs | 2 ++ .../MonitoringEditViewModelValidator.cs | 4 --- ...rviceControlAuditEditViewModelValidator.cs | 1 + .../ServiceControlEditViewModelValidator.cs | 1 + ...haredMonitoringEditorViewModelValidator.cs | 2 +- .../AddNewAuditInstanceViewModelValidator.cs | 5 +++ .../Validation/Validations.cs | 17 ++++++++++ 13 files changed, 201 insertions(+), 6 deletions(-) diff --git a/src/ServiceControl.Config.Tests/Validation/AddAuditInstanceValidationTests.cs b/src/ServiceControl.Config.Tests/Validation/AddAuditInstanceValidationTests.cs index d76f3400fc..800976d87a 100644 --- a/src/ServiceControl.Config.Tests/Validation/AddAuditInstanceValidationTests.cs +++ b/src/ServiceControl.Config.Tests/Validation/AddAuditInstanceValidationTests.cs @@ -321,6 +321,8 @@ public void Audit_hostname_can_not_be_null_when_adding_audit_instance() [TestCase("192.168.1.1")] [TestCase("256.0.0.0")] + [TestCase("::1")] + [TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")] public void Audit_hostname_can_be_an_ip_address_when_adding_audit_instance(string ipAddress) { var viewModel = new ServiceControlAddViewModel @@ -337,6 +339,33 @@ public void Audit_hostname_can_be_an_ip_address_when_adding_audit_instance(strin Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.AuditHostName)), Is.Empty); } + [TestCase("hostname with spaces")] + [TestCase("bad@hostname")] + [TestCase("bad#hostname")] + [TestCase("badhostname...")] + [TestCase("badhostname[/")] + public void Audit_hostname_cannot_contain_invalid_characters_when_adding_audit_instance(string invalidHostname) + { + var viewModel = new ServiceControlAddViewModel + { + InstallAuditInstance = true, + SubmitAttempted = true, + AuditHostName = invalidHostname + }; + + viewModel.NotifyOfPropertyChange(nameof(viewModel.AuditHostName)); + + var notifyErrorInfo = GetNotifyErrorInfo(viewModel); + var errors = notifyErrorInfo.GetErrors(nameof(viewModel.AuditHostName)); + + Assert.Multiple(() => + { + Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames"); + Assert.That(errors.Cast().Any(error => error.Contains("Hostname is not valid")), Is.True, + "Hostname validation should display the exact error message 'Hostname is not valid'"); + }); + } + #endregion #region Portnumber diff --git a/src/ServiceControl.Config.Tests/Validation/AddErrorInstanceValidationTests.cs b/src/ServiceControl.Config.Tests/Validation/AddErrorInstanceValidationTests.cs index 534ba7f705..12150cab65 100644 --- a/src/ServiceControl.Config.Tests/Validation/AddErrorInstanceValidationTests.cs +++ b/src/ServiceControl.Config.Tests/Validation/AddErrorInstanceValidationTests.cs @@ -320,6 +320,8 @@ public void Error_hostname_can_not_be_null_when_adding_error_instance() [TestCase("192.168.1.1")] [TestCase("256.0.0.0")] + [TestCase("::1")] + [TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")] public void Error_hostname_can_be_an_ip_address_when_adding_error_instance(string ipAddress) { var viewModel = new ServiceControlAddViewModel @@ -336,6 +338,33 @@ public void Error_hostname_can_be_an_ip_address_when_adding_error_instance(strin Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.ErrorHostName)), Is.Empty); } + [TestCase("hostname with spaces")] + [TestCase("bad@hostname")] + [TestCase("bad#hostname")] + [TestCase("badhostname...")] + [TestCase("badhostname[/")] + public void Error_hostname_cannot_contain_invalid_characters_when_adding_error_instance(string invalidHostname) + { + var viewModel = new ServiceControlAddViewModel + { + InstallErrorInstance = true, + SubmitAttempted = true, + ErrorHostName = invalidHostname + }; + + viewModel.NotifyOfPropertyChange(nameof(viewModel.ErrorHostName)); + + var notifyErrorInfo = GetNotifyErrorInfo(viewModel); + var errors = notifyErrorInfo.GetErrors(nameof(viewModel.ErrorHostName)); + + Assert.Multiple(() => + { + Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames"); + Assert.That(errors.Cast().Any(error => error.Contains("Hostname is not valid")), Is.True, + "Hostname validation should display the exact error message 'Hostname is not valid'"); + }); + } + #endregion #region Portnumber diff --git a/src/ServiceControl.Config.Tests/Validation/AddMonitoringInstanceValidationTests.cs b/src/ServiceControl.Config.Tests/Validation/AddMonitoringInstanceValidationTests.cs index 42ccf0e6dd..5a089ddee9 100644 --- a/src/ServiceControl.Config.Tests/Validation/AddMonitoringInstanceValidationTests.cs +++ b/src/ServiceControl.Config.Tests/Validation/AddMonitoringInstanceValidationTests.cs @@ -127,6 +127,8 @@ public void Monitoring_hostname_cannot_be_null_when_adding_monitoring_instance() [TestCase("192.168.1.1")] [TestCase("256.0.0.0")] + [TestCase("::1")] + [TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")] public void Monitoring_hostname_can_be_an_ip_address_when_adding_monitoring_instance(string ipAddress) { var viewModel = new MonitoringAddViewModel @@ -142,6 +144,32 @@ public void Monitoring_hostname_can_be_an_ip_address_when_adding_monitoring_inst Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.HostName)), Is.Empty); } + [TestCase("hostname with spaces")] + [TestCase("bad@hostname")] + [TestCase("bad#hostname")] + [TestCase("badhostname...")] + [TestCase("badhostname[/")] + public void Monitoring_hostname_cannot_contain_invalid_characters_when_adding_monitoring_instance(string invalidHostname) + { + var viewModel = new MonitoringAddViewModel + { + SubmitAttempted = true, + HostName = invalidHostname + }; + + viewModel.NotifyOfPropertyChange(nameof(viewModel.HostName)); + + var notifyErrorInfo = GetNotifyErrorInfo(viewModel); + var errors = notifyErrorInfo.GetErrors(nameof(viewModel.HostName)); + + Assert.Multiple(() => + { + Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames"); + Assert.That(errors.Cast().Any(error => error.Contains("Hostname is not valid")), Is.True, + "Hostname validation should display the exact error message 'Hostname is not valid'"); + }); + } + #endregion #region Portnumber diff --git a/src/ServiceControl.Config.Tests/Validation/EditAuditInstanceValidationTests.cs b/src/ServiceControl.Config.Tests/Validation/EditAuditInstanceValidationTests.cs index 73abc4d6d2..977bc00b9e 100644 --- a/src/ServiceControl.Config.Tests/Validation/EditAuditInstanceValidationTests.cs +++ b/src/ServiceControl.Config.Tests/Validation/EditAuditInstanceValidationTests.cs @@ -1,6 +1,7 @@ namespace ServiceControl.Config.Tests.Validation { using System.ComponentModel; + using System.Linq; using NUnit.Framework; using ServiceControlInstaller.Engine.Instances; using UI.InstanceAdd; @@ -127,7 +128,9 @@ public void Audit_hostname_can_not_be_null_when_editing_audit_instance() [TestCase("192.168.1.1")] [TestCase("256.0.0.0")] - public void Audi_hostname_can_be_an_ip_address_when_editing_an_audit_instance(string ipAddress) + [TestCase("::1")] + [TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")] + public void Audit_hostname_can_be_an_ip_address_when_editing_an_audit_instance(string ipAddress) { var viewModel = new ServiceControlAuditEditViewModel { @@ -142,6 +145,32 @@ public void Audi_hostname_can_be_an_ip_address_when_editing_an_audit_instance(st Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.HostName)), Is.Empty); } + [TestCase("hostname with spaces")] + [TestCase("bad@hostname")] + [TestCase("bad#hostname")] + [TestCase("badhostname...")] + [TestCase("badhostname[/")] + public void Audit_hostname_cannot_contain_invalid_characters_when_editing_audit_instance(string invalidHostname) + { + var viewModel = new ServiceControlAuditEditViewModel + { + SubmitAttempted = true, + HostName = invalidHostname + }; + + viewModel.NotifyOfPropertyChange(nameof(viewModel.HostName)); + + var notifyErrorInfo = GetNotifyErrorInfo(viewModel); + var errors = notifyErrorInfo.GetErrors(nameof(viewModel.HostName)); + + Assert.Multiple(() => + { + Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames"); + Assert.That(errors.Cast().Any(error => error.Contains("Hostname is not valid")), Is.True, + "Hostname validation should display the exact error message 'Hostname is not valid'"); + }); + } + #endregion #region Portnumber diff --git a/src/ServiceControl.Config.Tests/Validation/EditErrorInstanceValidationTests.cs b/src/ServiceControl.Config.Tests/Validation/EditErrorInstanceValidationTests.cs index a1e744191a..230bf2bbad 100644 --- a/src/ServiceControl.Config.Tests/Validation/EditErrorInstanceValidationTests.cs +++ b/src/ServiceControl.Config.Tests/Validation/EditErrorInstanceValidationTests.cs @@ -1,6 +1,7 @@ namespace ServiceControl.Config.Tests.Validation { using System.ComponentModel; + using System.Linq; using NUnit.Framework; using ServiceControlInstaller.Engine.Instances; using UI.InstanceAdd; @@ -120,6 +121,8 @@ public void Error_hostname_can_not_be_null_when_editing_error_instance() [TestCase("192.168.1.1")] [TestCase("256.0.0.0")] + [TestCase("::1")] + [TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")] public void Error_hostname_can_be_an_ip_address_when_editing_an_error_instance(string ipAddress) { var viewModel = new ServiceControlEditViewModel @@ -135,6 +138,32 @@ public void Error_hostname_can_be_an_ip_address_when_editing_an_error_instance(s Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.HostName)), Is.Empty); } + [TestCase("hostname with spaces")] + [TestCase("bad@hostname")] + [TestCase("bad#hostname")] + [TestCase("badhostname...")] + [TestCase("badhostname[/")] + public void Error_hostname_cannot_contain_invalid_characters_when_editing_error_instance(string invalidHostname) + { + var viewModel = new ServiceControlEditViewModel + { + SubmitAttempted = true, + HostName = invalidHostname + }; + + viewModel.NotifyOfPropertyChange(nameof(viewModel.HostName)); + + var notifyErrorInfo = GetNotifyErrorInfo(viewModel); + var errors = notifyErrorInfo.GetErrors(nameof(viewModel.HostName)); + + Assert.Multiple(() => + { + Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames"); + Assert.That(errors.Cast().Any(error => error.Contains("Hostname is not valid")), Is.True, + "Hostname validation should display the exact error message 'Hostname is not valid'"); + }); + } + #endregion #region Portnumber diff --git a/src/ServiceControl.Config.Tests/Validation/EditMonitoringInstanceValidationTests.cs b/src/ServiceControl.Config.Tests/Validation/EditMonitoringInstanceValidationTests.cs index 18815e2ea7..2754b0dd87 100644 --- a/src/ServiceControl.Config.Tests/Validation/EditMonitoringInstanceValidationTests.cs +++ b/src/ServiceControl.Config.Tests/Validation/EditMonitoringInstanceValidationTests.cs @@ -1,6 +1,7 @@ namespace ServiceControl.Config.Tests.Validation { using System.ComponentModel; + using System.Linq; using NUnit.Framework; using UI.InstanceEdit; @@ -42,6 +43,8 @@ public void Monitoring_hostname_cannot_be_null_when_editing_monitoring_instance( [TestCase("192.168.1.1")] [TestCase("256.0.0.0")] + [TestCase("::1")] + [TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")] public void Monitoring_hostname_can_be_an_ip_address_when_editing_a_monitoring_instance(string ipAddress) { var viewModel = new MonitoringEditViewModel @@ -56,6 +59,32 @@ public void Monitoring_hostname_can_be_an_ip_address_when_editing_a_monitoring_i Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.HostName)), Is.Empty); } + + [TestCase("hostname with spaces")] + [TestCase("bad@hostname")] + [TestCase("bad#hostname")] + [TestCase("badhostname...")] + [TestCase("badhostname[/")] + public void Monitoring_hostname_cannot_contain_invalid_characters_when_editing_monitoring_instance(string invalidHostname) + { + var viewModel = new MonitoringEditViewModel + { + SubmitAttempted = true, + HostName = invalidHostname + }; + + viewModel.NotifyOfPropertyChange(nameof(viewModel.HostName)); + + var notifyErrorInfo = GetNotifyErrorInfo(viewModel); + var errors = notifyErrorInfo.GetErrors(nameof(viewModel.HostName)); + + Assert.Multiple(() => + { + Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames"); + Assert.That(errors.Cast().Any(error => error.Contains("Hostname is not valid")), Is.True, + "Hostname validation should display the exact error message 'Hostname is not valid'"); + }); + } #endregion #region Portnumber diff --git a/src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddViewModelValidator.cs b/src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddViewModelValidator.cs index 223d5505dd..7a627d954a 100644 --- a/src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddViewModelValidator.cs +++ b/src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddViewModelValidator.cs @@ -52,6 +52,7 @@ public ServiceControlAddViewModelValidator() RuleFor(viewModel => viewModel.ErrorHostName) .NotEmpty() + .ValidHostname() .When(viewModel => viewModel.InstallErrorInstance); RuleFor(x => x.ErrorPortNumber) @@ -155,6 +156,7 @@ public ServiceControlAddViewModelValidator() RuleFor(viewModel => viewModel.AuditHostName) .NotEmpty() + .ValidHostname() .When(viewModel => viewModel.InstallAuditInstance); RuleFor(x => x.AuditPortNumber) diff --git a/src/ServiceControl.Config/UI/InstanceEdit/MonitoringEditViewModelValidator.cs b/src/ServiceControl.Config/UI/InstanceEdit/MonitoringEditViewModelValidator.cs index d9c762282c..46aad9154d 100644 --- a/src/ServiceControl.Config/UI/InstanceEdit/MonitoringEditViewModelValidator.cs +++ b/src/ServiceControl.Config/UI/InstanceEdit/MonitoringEditViewModelValidator.cs @@ -12,10 +12,6 @@ public MonitoringEditViewModelValidator() .NotEmpty() .When(x => x.SubmitAttempted); - RuleFor(x => x.HostName) - .NotEmpty() - .When(x => x.SubmitAttempted); - RuleFor(x => x.PortNumber) .NotEmpty() .ValidPort() diff --git a/src/ServiceControl.Config/UI/InstanceEdit/ServiceControlAuditEditViewModelValidator.cs b/src/ServiceControl.Config/UI/InstanceEdit/ServiceControlAuditEditViewModelValidator.cs index b4dd2524e0..9741d57238 100644 --- a/src/ServiceControl.Config/UI/InstanceEdit/ServiceControlAuditEditViewModelValidator.cs +++ b/src/ServiceControl.Config/UI/InstanceEdit/ServiceControlAuditEditViewModelValidator.cs @@ -14,6 +14,7 @@ public ServiceControlAuditEditViewModelValidator() RuleFor(x => x.HostName) .NotEmpty() + .ValidHostname() .When(x => x.SubmitAttempted); RuleFor(x => x.PortNumber) diff --git a/src/ServiceControl.Config/UI/InstanceEdit/ServiceControlEditViewModelValidator.cs b/src/ServiceControl.Config/UI/InstanceEdit/ServiceControlEditViewModelValidator.cs index d91d0f78da..0e9f6bfe8f 100644 --- a/src/ServiceControl.Config/UI/InstanceEdit/ServiceControlEditViewModelValidator.cs +++ b/src/ServiceControl.Config/UI/InstanceEdit/ServiceControlEditViewModelValidator.cs @@ -14,6 +14,7 @@ public ServiceControlEditViewModelValidator() RuleFor(x => x.HostName) .NotEmpty() + .ValidHostname() .When(x => x.SubmitAttempted); RuleFor(x => x.PortNumber) diff --git a/src/ServiceControl.Config/UI/SharedInstanceEditor/SharedMonitoringEditorViewModelValidator.cs b/src/ServiceControl.Config/UI/SharedInstanceEditor/SharedMonitoringEditorViewModelValidator.cs index 54d21952ff..d226baa652 100644 --- a/src/ServiceControl.Config/UI/SharedInstanceEditor/SharedMonitoringEditorViewModelValidator.cs +++ b/src/ServiceControl.Config/UI/SharedInstanceEditor/SharedMonitoringEditorViewModelValidator.cs @@ -9,7 +9,7 @@ protected SharedMonitoringEditorViewModelValidator() { RuleFor(x => x.HostName) .NotEmpty() - .When(x => x.SubmitAttempted); + .ValidHostname(); RuleFor(x => x.LogPath) .NotEmpty() diff --git a/src/ServiceControl.Config/UI/Upgrades/AddNewAuditInstanceViewModelValidator.cs b/src/ServiceControl.Config/UI/Upgrades/AddNewAuditInstanceViewModelValidator.cs index cd38ec6059..26b4cdc499 100644 --- a/src/ServiceControl.Config/UI/Upgrades/AddNewAuditInstanceViewModelValidator.cs +++ b/src/ServiceControl.Config/UI/Upgrades/AddNewAuditInstanceViewModelValidator.cs @@ -60,6 +60,11 @@ public AddNewAuditInstanceViewModelValidator() .NotEmpty() .NotEqual(x => x.ServiceControlAudit.AuditQueueName).WithMessage(string.Format(Validation.Validations.MSG_UNIQUEQUEUENAME, "Audit")) .When(x => x.SubmitAttempted && (x.ServiceControlAudit.AuditForwarding?.Value ?? false)); + + RuleFor(x => x.ServiceControlAudit.HostName) + .NotEmpty() + .ValidHostname() + .When(x => x.SubmitAttempted); } } } \ No newline at end of file diff --git a/src/ServiceControl.Config/Validation/Validations.cs b/src/ServiceControl.Config/Validation/Validations.cs index b0562eee77..7fb7ba8373 100644 --- a/src/ServiceControl.Config/Validation/Validations.cs +++ b/src/ServiceControl.Config/Validation/Validations.cs @@ -202,6 +202,21 @@ public static IRuleBuilderOptions MustBeUniqueWindowsServiceName(t }); } + public static IRuleBuilderOptions ValidHostname(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.Must((t, hostname) => + { + if (string.IsNullOrWhiteSpace(hostname)) + { + return false; + } + + var hostNameType = Uri.CheckHostName(hostname); + return hostNameType is UriHostNameType.Dns or UriHostNameType.IPv4 or UriHostNameType.IPv6; + }) + .WithMessage(MSG_INVALID_HOSTNAME); + } + public const string MSG_EMAIL_NOT_VALID = "Not Valid."; public const string MSG_THIS_TRANSPORT_REQUIRES_A_CONNECTION_STRING = "This transport requires a connection string."; @@ -234,6 +249,8 @@ public static IRuleBuilderOptions MustBeUniqueWindowsServiceName(t public const string MSG_ILLEGAL_PATH_CHAR = "Paths cannot contain characters {0}"; + public const string MSG_INVALID_HOSTNAME = "Hostname is not valid."; + static char[] ILLEGAL_PATH_CHARS = { '*',