From c245e04273be293ab561d2fd3591615814550396 Mon Sep 17 00:00:00 2001 From: ZLoo Date: Sun, 16 Mar 2025 12:18:45 +0300 Subject: [PATCH 1/8] share if null or empty --- ...ire.Hosting.Azure.CognitiveServices.csproj | 1 + .../AzureOpenAIDeployment.cs | 15 ++----- .../Aspire.Hosting.Azure.CosmosDB.csproj | 1 + .../AzureCosmosDBContainerResource.cs | 24 +++++----- .../AzureCosmosDBDatabaseResource.cs | 16 +++---- .../Aspire.Hosting.Azure.EventHubs.csproj | 1 + .../AzureEventHubConsumerGroupResource.cs | 16 +++---- .../AzureEventHubResource.cs | 16 +++---- .../Aspire.Hosting.Azure.PostgreSQL.csproj | 1 + ...ePostgresFlexibleServerDatabaseResource.cs | 10 +---- .../Aspire.Hosting.Azure.ServiceBus.csproj | 1 + .../AzureServiceBusQueueResource.cs | 12 +---- .../AzureServiceBusRule.cs | 12 +---- .../AzureServiceBusSubscriptionResource.cs | 12 +---- .../AzureServiceBusTopicResource.cs | 12 +---- .../Aspire.Hosting.Azure.Sql.csproj | 1 + .../AzureSqlDatabaseResource.cs | 10 +---- .../GarnetBuilderExtensions.cs | 2 +- .../Aspire.Hosting.Milvus.csproj | 2 + .../MilvusDatabaseResource.cs | 10 +---- .../Aspire.Hosting.MongoDB.csproj | 1 + .../MongoDBDatabaseResource.cs | 11 +---- .../Aspire.Hosting.MySql.csproj | 1 + .../MySqlDatabaseResource.cs | 11 +---- .../Aspire.Hosting.Oracle.csproj | 1 + .../OracleDatabaseResource.cs | 11 +---- .../Aspire.Hosting.PostgreSQL.csproj | 1 + .../PostgresDatabaseResource.cs | 11 +---- .../Aspire.Hosting.Python.csproj | 1 + .../PythonAppResourceBuilderExtensions.cs | 19 +------- .../RedisBuilderExtensions.cs | 2 +- src/Aspire.Hosting.Redis/RedisResource.cs | 2 + .../Aspire.Hosting.SqlServer.csproj | 1 + .../SqlServerDatabaseResource.cs | 10 +---- .../Aspire.Hosting.Testing.csproj | 1 + .../DistributedApplicationFactory.cs | 20 +-------- .../DistributedApplicationTestingBuilder.cs | 21 +-------- src/Aspire.Hosting.Valkey/ValkeyResource.cs | 2 + .../ApplicationModel/ExecutableResource.cs | 13 +----- src/Aspire.Hosting/Aspire.Hosting.csproj | 1 + .../Aspire.OpenAI/Aspire.OpenAI.csproj | 1 + .../AspireOpenAIClientBuilder.cs | 10 +---- .../Common/ArgumentExceptionExtensions.cs | 45 +++++++++++++++++++ 43 files changed, 129 insertions(+), 243 deletions(-) create mode 100644 src/Components/Common/ArgumentExceptionExtensions.cs diff --git a/src/Aspire.Hosting.Azure.CognitiveServices/Aspire.Hosting.Azure.CognitiveServices.csproj b/src/Aspire.Hosting.Azure.CognitiveServices/Aspire.Hosting.Azure.CognitiveServices.csproj index 29f2a4f1c83..2988e306b47 100644 --- a/src/Aspire.Hosting.Azure.CognitiveServices/Aspire.Hosting.Azure.CognitiveServices.csproj +++ b/src/Aspire.Hosting.Azure.CognitiveServices/Aspire.Hosting.Azure.CognitiveServices.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIDeployment.cs b/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIDeployment.cs index c203383bdb0..6a16e71fe3a 100644 --- a/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIDeployment.cs +++ b/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIDeployment.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - namespace Aspire.Hosting.ApplicationModel; /// @@ -25,17 +22,17 @@ public class AzureOpenAIDeployment(string name, string modelName, string modelVe /// /// Gets the name of the deployment. /// - public string Name { get; private set; } = ThrowIfNullOrEmpty(name); + public string Name { get; private set; } = name.ThrowIfNullOrEmpty(); /// /// Gets the name of the model. /// - public string ModelName { get; private set; } = ThrowIfNullOrEmpty(modelName); + public string ModelName { get; private set; } = modelName.ThrowIfNullOrEmpty(); /// /// Gets the version of the model. /// - public string ModelVersion { get; private set; } = ThrowIfNullOrEmpty(modelVersion); + public string ModelVersion { get; private set; } = modelVersion.ThrowIfNullOrEmpty(); /// /// Gets the name of the SKU. @@ -52,10 +49,4 @@ public class AzureOpenAIDeployment(string name, string modelName, string modelVe /// The default value is . /// public int SkuCapacity { get; set; } = skuCapacity ?? DefaultSkuCapacity; - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.CosmosDB/Aspire.Hosting.Azure.CosmosDB.csproj b/src/Aspire.Hosting.Azure.CosmosDB/Aspire.Hosting.Azure.CosmosDB.csproj index 1b6139decb8..f9ebbb902a7 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/Aspire.Hosting.Azure.CosmosDB.csproj +++ b/src/Aspire.Hosting.Azure.CosmosDB/Aspire.Hosting.Azure.CosmosDB.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs index 249acf47aff..b3720a95133 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using Aspire.Hosting.ApplicationModel; namespace Aspire.Hosting.Azure; @@ -17,15 +15,27 @@ namespace Aspire.Hosting.Azure; public class AzureCosmosDBContainerResource(string name, string containerName, string partitionKeyPath, AzureCosmosDBDatabaseResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { + private string _containerName = containerName.ThrowIfNullOrEmpty(); + /// /// Gets or sets the container name. /// - public string ContainerName { get; set; } = ThrowIfNullOrEmpty(containerName); + public string ContainerName + { + get => _containerName; + set => _containerName = value.ThrowIfNullOrEmpty(nameof(containerName)); + } + + private string _partitionKeyPath = partitionKeyPath.ThrowIfNullOrEmpty(); /// /// Gets or sets the partition key path. /// - public string PartitionKeyPath { get; set; } = ThrowIfNullOrEmpty(partitionKeyPath); + public string PartitionKeyPath + { + get => _partitionKeyPath; + set => _partitionKeyPath = value.ThrowIfNullOrEmpty(nameof(partitionKeyPath)); + } /// /// Gets the parent Azure Cosmos DB database resource. @@ -40,10 +50,4 @@ public class AzureCosmosDBContainerResource(string name, string containerName, s // ensure Azure Functions projects can WithReference a CosmosDB database container void IResourceWithAzureFunctionsConfig.ApplyAzureFunctionsConfiguration(IDictionary target, string connectionName) => ((IResourceWithAzureFunctionsConfig)Parent).ApplyAzureFunctionsConfiguration(target, connectionName); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs index 432c143d814..68840adbc26 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using Aspire.Hosting.ApplicationModel; namespace Aspire.Hosting.Azure; @@ -17,10 +15,16 @@ namespace Aspire.Hosting.Azure; public class AzureCosmosDBDatabaseResource(string name, string databaseName, AzureCosmosDBResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { + private string _databaseName = databaseName.ThrowIfNullOrEmpty(); + /// /// Gets or sets the database name. /// - public string DatabaseName { get; set; } = ThrowIfNullOrEmpty(databaseName); + public string DatabaseName + { + get => _databaseName; + set => _databaseName = value.ThrowIfNullOrEmpty(nameof(databaseName)); + } /// /// The containers for this database. @@ -40,10 +44,4 @@ public class AzureCosmosDBDatabaseResource(string name, string databaseName, Azu // ensure Azure Functions projects can WithReference a CosmosDB database void IResourceWithAzureFunctionsConfig.ApplyAzureFunctionsConfiguration(IDictionary target, string connectionName) => ((IResourceWithAzureFunctionsConfig)Parent).ApplyAzureFunctionsConfiguration(target, connectionName); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.EventHubs.csproj b/src/Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.EventHubs.csproj index ca40ec7effc..e66e5162ecc 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.EventHubs.csproj +++ b/src/Aspire.Hosting.Azure.EventHubs/Aspire.Hosting.Azure.EventHubs.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubConsumerGroupResource.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubConsumerGroupResource.cs index a61cef7f1f7..cb15dee23d5 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubConsumerGroupResource.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubConsumerGroupResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Text.Json; using Aspire.Hosting.ApplicationModel; using Azure.Provisioning; @@ -19,10 +17,16 @@ namespace Aspire.Hosting.Azure; public class AzureEventHubConsumerGroupResource(string name, string consumerGroupName, AzureEventHubResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { + private string _consumerGroupName = consumerGroupName.ThrowIfNullOrEmpty(); + /// /// The event hub consumer group name. /// - public string ConsumerGroupName { get; set; } = ThrowIfNullOrEmpty(consumerGroupName); + public string ConsumerGroupName + { + get => _consumerGroupName; + set => _consumerGroupName = value.ThrowIfNullOrEmpty(nameof(consumerGroupName)); + } /// /// Gets the parent Azure Event Hub resource. @@ -60,10 +64,4 @@ internal void WriteJsonObjectProperties(Utf8JsonWriter writer) { writer.WriteString(nameof(Name), ConsumerGroupName); } - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs index 82e3baa673b..c6362bc44f3 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Text.Json; using Aspire.Hosting.ApplicationModel; using Azure.Provisioning; @@ -19,10 +17,16 @@ namespace Aspire.Hosting.Azure; public class AzureEventHubResource(string name, string hubName, AzureEventHubsResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { + private string _hubName = hubName.ThrowIfNullOrEmpty(); + /// /// The event hub name. /// - public string HubName { get; set; } = ThrowIfNullOrEmpty(hubName); + public string HubName + { + get => _hubName; + set => _hubName = value.ThrowIfNullOrEmpty(nameof(hubName)); + } /// /// Number of partitions created for the Event Hub, allowed values are from @@ -109,10 +113,4 @@ internal void WriteJsonObjectProperties(Utf8JsonWriter writer) writer.WriteEndArray(); } #pragma warning restore CA1507 // Use nameof to express symbol names - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.PostgreSQL/Aspire.Hosting.Azure.PostgreSQL.csproj b/src/Aspire.Hosting.Azure.PostgreSQL/Aspire.Hosting.Azure.PostgreSQL.csproj index 4bdcc5541ed..2e6e9e2e8e9 100644 --- a/src/Aspire.Hosting.Azure.PostgreSQL/Aspire.Hosting.Azure.PostgreSQL.csproj +++ b/src/Aspire.Hosting.Azure.PostgreSQL/Aspire.Hosting.Azure.PostgreSQL.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresFlexibleServerDatabaseResource.cs b/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresFlexibleServerDatabaseResource.cs index e7f82496a4a..282f7abd16e 100644 --- a/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresFlexibleServerDatabaseResource.cs +++ b/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresFlexibleServerDatabaseResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using Aspire.Hosting.ApplicationModel; namespace Aspire.Hosting.Azure; @@ -29,7 +27,7 @@ public class AzurePostgresFlexibleServerDatabaseResource(string name, string dat /// /// Gets the database name. /// - public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); + public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); /// /// Gets the inner PostgresDatabaseResource resource. @@ -41,12 +39,6 @@ public class AzurePostgresFlexibleServerDatabaseResource(string name, string dat /// public override ResourceAnnotationCollection Annotations => InnerResource?.Annotations ?? base.Annotations; - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } - internal void SetInnerResource(PostgresDatabaseResource innerResource) { // Copy the annotations to the inner resource before making it the inner resource diff --git a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj index 69df052cad5..a304e785dba 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj +++ b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusQueueResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusQueueResource.cs index ecdbe80b960..9ef809545a0 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusQueueResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusQueueResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Text.Json; using System.Xml; using Aspire.Hosting.ApplicationModel; @@ -20,7 +18,7 @@ namespace Aspire.Hosting.Azure; public class AzureServiceBusQueueResource(string name, string queueName, AzureServiceBusResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _queueName = ThrowIfNullOrEmpty(queueName); + private string _queueName = queueName.ThrowIfNullOrEmpty(); /// /// The queue name. @@ -28,7 +26,7 @@ public class AzureServiceBusQueueResource(string name, string queueName, AzureSe public string QueueName { get => _queueName; - set => _queueName = ThrowIfNullOrEmpty(value, nameof(queueName)); + set => _queueName = value.ThrowIfNullOrEmpty(nameof(queueName)); } /// @@ -198,10 +196,4 @@ internal void WriteJsonObjectProperties(Utf8JsonWriter writer) } writer.WriteEndObject(); } - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusRule.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusRule.cs index 362cd821317..fb32268bbb3 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusRule.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusRule.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Provisioning; @@ -17,7 +15,7 @@ namespace Aspire.Hosting.Azure; /// public class AzureServiceBusRule(string name) { - private string _name = ThrowIfNullOrEmpty(name); + private string _name = name.ThrowIfNullOrEmpty(); /// /// The rule name. @@ -25,7 +23,7 @@ public class AzureServiceBusRule(string name) public string Name { get => _name; - set => _name = ThrowIfNullOrEmpty(value, nameof(name)); + set => _name = value.ThrowIfNullOrEmpty(nameof(name)); } /// @@ -181,10 +179,4 @@ internal void WriteJsonObjectProperties(Utf8JsonWriter writer) writer.WriteEndObject(); // Properties } - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusSubscriptionResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusSubscriptionResource.cs index c3c1303f00e..ed3e35107f9 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusSubscriptionResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusSubscriptionResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Text.Json; using System.Xml; using Aspire.Hosting.ApplicationModel; @@ -20,7 +18,7 @@ namespace Aspire.Hosting.Azure; public class AzureServiceBusSubscriptionResource(string name, string subscriptionName, AzureServiceBusTopicResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _subscriptionName = ThrowIfNullOrEmpty(subscriptionName); + private string _subscriptionName = subscriptionName.ThrowIfNullOrEmpty(); /// /// The subscription name. @@ -28,7 +26,7 @@ public class AzureServiceBusSubscriptionResource(string name, string subscriptio public string SubscriptionName { get => _subscriptionName; - set => _subscriptionName = ThrowIfNullOrEmpty(value, nameof(subscriptionName)); + set => _subscriptionName = value.ThrowIfNullOrEmpty(nameof(subscriptionName)); } /// @@ -183,10 +181,4 @@ internal void WriteJsonObjectProperties(Utf8JsonWriter writer) writer.WriteEndObject(); } - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusTopicResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusTopicResource.cs index 2e268d0a87c..6ef616ffa29 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusTopicResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusTopicResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Text.Json; using System.Xml; using Aspire.Hosting.ApplicationModel; @@ -20,7 +18,7 @@ namespace Aspire.Hosting.Azure; public class AzureServiceBusTopicResource(string name, string topicName, AzureServiceBusResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _topicName = ThrowIfNullOrEmpty(topicName); + private string _topicName = topicName.ThrowIfNullOrEmpty(); /// /// The topic name. @@ -28,7 +26,7 @@ public class AzureServiceBusTopicResource(string name, string topicName, AzureSe public string TopicName { get => _topicName; - set => _topicName = ThrowIfNullOrEmpty(value, nameof(topicName)); + set => _topicName = value.ThrowIfNullOrEmpty(nameof(topicName)); } /// @@ -126,10 +124,4 @@ internal void WriteJsonObjectProperties(Utf8JsonWriter writer) writer.WriteEndObject(); } - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.Sql/Aspire.Hosting.Azure.Sql.csproj b/src/Aspire.Hosting.Azure.Sql/Aspire.Hosting.Azure.Sql.csproj index 7dfc5b09eb3..bc8f870d77e 100644 --- a/src/Aspire.Hosting.Azure.Sql/Aspire.Hosting.Azure.Sql.csproj +++ b/src/Aspire.Hosting.Azure.Sql/Aspire.Hosting.Azure.Sql.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Aspire.Hosting.Azure.Sql/AzureSqlDatabaseResource.cs b/src/Aspire.Hosting.Azure.Sql/AzureSqlDatabaseResource.cs index 858738eb5d8..2e0af9463e5 100644 --- a/src/Aspire.Hosting.Azure.Sql/AzureSqlDatabaseResource.cs +++ b/src/Aspire.Hosting.Azure.Sql/AzureSqlDatabaseResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using Aspire.Hosting.ApplicationModel; namespace Aspire.Hosting.Azure; @@ -30,7 +28,7 @@ public class AzureSqlDatabaseResource(string name, string databaseName, AzureSql /// /// Gets the database name. /// - public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); + public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); /// /// Gets the inner SqlServerDatabaseResource resource. @@ -42,12 +40,6 @@ public class AzureSqlDatabaseResource(string name, string databaseName, AzureSql /// public override ResourceAnnotationCollection Annotations => InnerResource?.Annotations ?? base.Annotations; - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } - internal void SetInnerResource(SqlServerDatabaseResource innerResource) { // Copy the annotations to the inner resource before making it the inner resource diff --git a/src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs b/src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs index 17ae0fe0a6b..1c4851f70b5 100644 --- a/src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs +++ b/src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs @@ -54,7 +54,7 @@ public static class GarnetBuilderExtensions public static IResourceBuilder AddGarnet(this IDistributedApplicationBuilder builder, [ResourceName] string name, int? port) { - return builder.AddGarnet(name, port, password: null); + return AddGarnet(builder, name, port, password: null); } /// diff --git a/src/Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.csproj b/src/Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.csproj index 5c7f70f8828..f14fbb1d233 100644 --- a/src/Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.csproj +++ b/src/Aspire.Hosting.Milvus/Aspire.Hosting.Milvus.csproj @@ -11,6 +11,8 @@ + + diff --git a/src/Aspire.Hosting.Milvus/MilvusDatabaseResource.cs b/src/Aspire.Hosting.Milvus/MilvusDatabaseResource.cs index 69adf9f4743..9a3c4329d7d 100644 --- a/src/Aspire.Hosting.Milvus/MilvusDatabaseResource.cs +++ b/src/Aspire.Hosting.Milvus/MilvusDatabaseResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using Aspire.Hosting.Milvus; namespace Aspire.Hosting.ApplicationModel; @@ -29,11 +27,5 @@ public class MilvusDatabaseResource(string name, string databaseName, MilvusServ /// /// Gets the database name. /// - public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } + public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); } diff --git a/src/Aspire.Hosting.MongoDB/Aspire.Hosting.MongoDB.csproj b/src/Aspire.Hosting.MongoDB/Aspire.Hosting.MongoDB.csproj index 93fc96cb9b8..a3ad1df04b6 100644 --- a/src/Aspire.Hosting.MongoDB/Aspire.Hosting.MongoDB.csproj +++ b/src/Aspire.Hosting.MongoDB/Aspire.Hosting.MongoDB.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Aspire.Hosting.MongoDB/MongoDBDatabaseResource.cs b/src/Aspire.Hosting.MongoDB/MongoDBDatabaseResource.cs index 2c66493fc82..f9610b2be0c 100644 --- a/src/Aspire.Hosting.MongoDB/MongoDBDatabaseResource.cs +++ b/src/Aspire.Hosting.MongoDB/MongoDBDatabaseResource.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - namespace Aspire.Hosting.ApplicationModel; /// @@ -28,11 +25,5 @@ public class MongoDBDatabaseResource(string name, string databaseName, MongoDBSe /// /// Gets the database name. /// - public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } + public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); } diff --git a/src/Aspire.Hosting.MySql/Aspire.Hosting.MySql.csproj b/src/Aspire.Hosting.MySql/Aspire.Hosting.MySql.csproj index 4070ac50ab7..cd7b795497d 100644 --- a/src/Aspire.Hosting.MySql/Aspire.Hosting.MySql.csproj +++ b/src/Aspire.Hosting.MySql/Aspire.Hosting.MySql.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Aspire.Hosting.MySql/MySqlDatabaseResource.cs b/src/Aspire.Hosting.MySql/MySqlDatabaseResource.cs index 6acef5cb340..92cc0f19600 100644 --- a/src/Aspire.Hosting.MySql/MySqlDatabaseResource.cs +++ b/src/Aspire.Hosting.MySql/MySqlDatabaseResource.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - namespace Aspire.Hosting.ApplicationModel; /// @@ -29,11 +26,5 @@ public class MySqlDatabaseResource(string name, string databaseName, MySqlServer /// /// Gets the database name. /// - public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } + public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); } diff --git a/src/Aspire.Hosting.Oracle/Aspire.Hosting.Oracle.csproj b/src/Aspire.Hosting.Oracle/Aspire.Hosting.Oracle.csproj index 75c7631f739..d7d4ffe9fac 100644 --- a/src/Aspire.Hosting.Oracle/Aspire.Hosting.Oracle.csproj +++ b/src/Aspire.Hosting.Oracle/Aspire.Hosting.Oracle.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs b/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs index 872443a66eb..a304ac62b3b 100644 --- a/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs +++ b/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - namespace Aspire.Hosting.ApplicationModel; /// @@ -29,11 +26,5 @@ public class OracleDatabaseResource(string name, string databaseName, OracleData /// /// Gets the database name. /// - public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } + public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); } diff --git a/src/Aspire.Hosting.PostgreSQL/Aspire.Hosting.PostgreSQL.csproj b/src/Aspire.Hosting.PostgreSQL/Aspire.Hosting.PostgreSQL.csproj index fdc2dd9df05..6b107b79249 100644 --- a/src/Aspire.Hosting.PostgreSQL/Aspire.Hosting.PostgreSQL.csproj +++ b/src/Aspire.Hosting.PostgreSQL/Aspire.Hosting.PostgreSQL.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs b/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs index d06c6a24924..a0485cddba9 100644 --- a/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs +++ b/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - namespace Aspire.Hosting.ApplicationModel; /// @@ -29,11 +26,5 @@ public class PostgresDatabaseResource(string name, string databaseName, Postgres /// /// Gets the database name. /// - public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } + public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); } diff --git a/src/Aspire.Hosting.Python/Aspire.Hosting.Python.csproj b/src/Aspire.Hosting.Python/Aspire.Hosting.Python.csproj index 367683a5155..1606889137a 100644 --- a/src/Aspire.Hosting.Python/Aspire.Hosting.Python.csproj +++ b/src/Aspire.Hosting.Python/Aspire.Hosting.Python.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs b/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs index d93f5912606..28574255b1e 100644 --- a/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs @@ -111,7 +111,7 @@ public static IResourceBuilder AddPythonApp( ArgumentException.ThrowIfNullOrEmpty(appDirectory); ArgumentException.ThrowIfNullOrEmpty(scriptPath); ArgumentException.ThrowIfNullOrEmpty(virtualEnvironmentPath); - ThrowIfNullOrContainsIsNullOrEmpty(scriptArgs); + scriptArgs.ThrowIfNullOrContainsIsNullOrEmpty(); appDirectory = PathNormalizer.NormalizePathForCurrentPlatform(Path.Combine(builder.AppHostDirectory, appDirectory)); var virtualEnvironment = new VirtualEnvironment(Path.IsPathRooted(virtualEnvironmentPath) @@ -173,21 +173,4 @@ private static void AddOpenTelemetryArguments(CommandLineArgsCallbackContext con context.Args.Add("--metrics_exporter"); context.Args.Add("otlp"); } - - private static void ThrowIfNullOrContainsIsNullOrEmpty(string[] scriptArgs) - { - ArgumentNullException.ThrowIfNull(scriptArgs); - foreach (var scriptArg in scriptArgs) - { - if (string.IsNullOrEmpty(scriptArg)) - { - var values = string.Join(", ", scriptArgs); - if (scriptArg is null) - { - throw new ArgumentNullException(nameof(scriptArgs), $"Array params contains null item: [{values}]"); - } - throw new ArgumentException($"Array params contains empty item: [{values}]", nameof(scriptArgs)); - } - } - } } diff --git a/src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs b/src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs index 35b3a167956..f2f4d87302e 100644 --- a/src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs +++ b/src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs @@ -39,7 +39,7 @@ public static class RedisBuilderExtensions /// public static IResourceBuilder AddRedis(this IDistributedApplicationBuilder builder, [ResourceName] string name, int? port) { - return builder.AddRedis(name, port, null); + return AddRedis(builder, name, port, null); } /// diff --git a/src/Aspire.Hosting.Redis/RedisResource.cs b/src/Aspire.Hosting.Redis/RedisResource.cs index fc9ea4b2843..169d8ec8c83 100644 --- a/src/Aspire.Hosting.Redis/RedisResource.cs +++ b/src/Aspire.Hosting.Redis/RedisResource.cs @@ -16,6 +16,8 @@ public class RedisResource(string name) : ContainerResource(name), IResourceWith /// A parameter that contains the Redis server password. public RedisResource(string name, ParameterResource password) : this(name) { + ArgumentNullException.ThrowIfNull(password); + PasswordParameter = password; } diff --git a/src/Aspire.Hosting.SqlServer/Aspire.Hosting.SqlServer.csproj b/src/Aspire.Hosting.SqlServer/Aspire.Hosting.SqlServer.csproj index f488e5e241b..873a9f5e947 100644 --- a/src/Aspire.Hosting.SqlServer/Aspire.Hosting.SqlServer.csproj +++ b/src/Aspire.Hosting.SqlServer/Aspire.Hosting.SqlServer.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs b/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs index e87343e2627..929273670c2 100644 --- a/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs +++ b/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using Microsoft.Data.SqlClient; namespace Aspire.Hosting.ApplicationModel; @@ -40,11 +38,5 @@ public ReferenceExpression ConnectionStringExpression /// /// Gets the database name. /// - public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } + public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); } diff --git a/src/Aspire.Hosting.Testing/Aspire.Hosting.Testing.csproj b/src/Aspire.Hosting.Testing/Aspire.Hosting.Testing.csproj index 8a9ce7eb030..c2c9ef339c0 100644 --- a/src/Aspire.Hosting.Testing/Aspire.Hosting.Testing.csproj +++ b/src/Aspire.Hosting.Testing/Aspire.Hosting.Testing.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs b/src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs index 1d9b3bdd36c..5a3048af99b 100644 --- a/src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs +++ b/src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs @@ -21,7 +21,7 @@ namespace Aspire.Hosting.Testing; public class DistributedApplicationFactory(Type entryPoint, string[] args) : IDisposable, IAsyncDisposable { private readonly Type _entryPoint = entryPoint ?? throw new ArgumentNullException(nameof(entryPoint)); - private readonly string[] _args = ThrowIfNullOrContainsIsNullOrEmpty(args); + private readonly string[] _args = args.ThrowIfNullOrContainsIsNullOrEmpty(); private readonly TaskCompletionSource _startedTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly TaskCompletionSource _exitTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly TaskCompletionSource _builderTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); @@ -149,24 +149,6 @@ protected virtual void OnBuilt(DistributedApplication application) { } - private static string[] ThrowIfNullOrContainsIsNullOrEmpty(string[] args) - { - ArgumentNullException.ThrowIfNull(args); - foreach (var arg in args) - { - if (string.IsNullOrEmpty(arg)) - { - var values = string.Join(", ", args); - if (arg is null) - { - throw new ArgumentNullException(nameof(args), $"Array params contains null item: [{values}]"); - } - throw new ArgumentException($"Array params contains empty item: [{values}]", nameof(args)); - } - } - return args; - } - private void OnBuiltCore(DistributedApplication application) { _shutdownTimeout = application.Services.GetService>()?.Value.ShutdownTimeout ?? _shutdownTimeout; diff --git a/src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs b/src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs index da73accdc96..0fa19d0448d 100644 --- a/src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs +++ b/src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs @@ -102,7 +102,7 @@ public static Task CreateAsync CreateAsync(Type entryPoint, string[] args, Action configureBuilder, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(entryPoint); - ThrowIfNullOrContainsIsNullOrEmpty(args); + args.ThrowIfNullOrContainsIsNullOrEmpty(); ArgumentNullException.ThrowIfNull(configureBuilder, nameof(configureBuilder)); var factory = new SuspendingDistributedApplicationFactory(entryPoint, args, configureBuilder); @@ -129,29 +129,12 @@ public static IDistributedApplicationTestingBuilder Create(params string[] args) /// public static IDistributedApplicationTestingBuilder Create(string[] args, Action configureBuilder) { - ThrowIfNullOrContainsIsNullOrEmpty(args); + args.ThrowIfNullOrContainsIsNullOrEmpty(); ArgumentNullException.ThrowIfNull(configureBuilder); return new TestingBuilder(args, configureBuilder); } - private static void ThrowIfNullOrContainsIsNullOrEmpty(string[] args) - { - ArgumentNullException.ThrowIfNull(args); - foreach (var arg in args) - { - if (string.IsNullOrEmpty(arg)) - { - var values = string.Join(", ", args); - if (arg is null) - { - throw new ArgumentNullException(nameof(args), $"Array params contains null item: [{values}]"); - } - throw new ArgumentException($"Array params contains empty item: [{values}]", nameof(args)); - } - } - } - private sealed class SuspendingDistributedApplicationFactory(Type entryPoint, string[] args, Action configureBuilder) : DistributedApplicationFactory(entryPoint, args) { diff --git a/src/Aspire.Hosting.Valkey/ValkeyResource.cs b/src/Aspire.Hosting.Valkey/ValkeyResource.cs index 15b64e5c396..85a268d3a1e 100644 --- a/src/Aspire.Hosting.Valkey/ValkeyResource.cs +++ b/src/Aspire.Hosting.Valkey/ValkeyResource.cs @@ -20,6 +20,8 @@ public class ValkeyResource(string name) : ContainerResource(name), IResourceWit /// A parameter that contains the Valkey server password. public ValkeyResource(string name, ParameterResource password) : this(name) { + ArgumentNullException.ThrowIfNull(password); + PasswordParameter = password; } diff --git a/src/Aspire.Hosting/ApplicationModel/ExecutableResource.cs b/src/Aspire.Hosting/ApplicationModel/ExecutableResource.cs index 5a3a7297553..55cd1b86ab8 100644 --- a/src/Aspire.Hosting/ApplicationModel/ExecutableResource.cs +++ b/src/Aspire.Hosting/ApplicationModel/ExecutableResource.cs @@ -1,9 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - namespace Aspire.Hosting.ApplicationModel; /// @@ -18,16 +15,10 @@ public class ExecutableResource(string name, string command, string workingDirec /// /// Gets the command associated with this executable resource. /// - public string Command { get; } = ThrowIfNullOrEmpty(command); + public string Command { get; } = command.ThrowIfNullOrEmpty(); /// /// Gets the working directory for the executable resource. /// - public string WorkingDirectory { get; } = ThrowIfNullOrEmpty(workingDirectory); - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } + public string WorkingDirectory { get; } = workingDirectory.ThrowIfNullOrEmpty(); } diff --git a/src/Aspire.Hosting/Aspire.Hosting.csproj b/src/Aspire.Hosting/Aspire.Hosting.csproj index 5f95a62ccbd..a19c769e194 100644 --- a/src/Aspire.Hosting/Aspire.Hosting.csproj +++ b/src/Aspire.Hosting/Aspire.Hosting.csproj @@ -38,6 +38,7 @@ + diff --git a/src/Components/Aspire.OpenAI/Aspire.OpenAI.csproj b/src/Components/Aspire.OpenAI/Aspire.OpenAI.csproj index c7ce004d418..d43f0978b89 100644 --- a/src/Components/Aspire.OpenAI/Aspire.OpenAI.csproj +++ b/src/Components/Aspire.OpenAI/Aspire.OpenAI.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Components/Aspire.OpenAI/AspireOpenAIClientBuilder.cs b/src/Components/Aspire.OpenAI/AspireOpenAIClientBuilder.cs index 440adf96ff0..38e901cd979 100644 --- a/src/Components/Aspire.OpenAI/AspireOpenAIClientBuilder.cs +++ b/src/Components/Aspire.OpenAI/AspireOpenAIClientBuilder.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Data.Common; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using OpenAI; @@ -31,7 +29,7 @@ public class AspireOpenAIClientBuilder(IHostApplicationBuilder hostBuilder, stri /// /// Gets the name used to retrieve the connection string from the ConnectionStrings configuration section. /// - public string ConnectionName { get; } = ThrowIfNullOrEmpty(connectionName); + public string ConnectionName { get; } = connectionName.ThrowIfNullOrEmpty(); /// /// Gets the service key used to register the service, if any. @@ -87,10 +85,4 @@ internal string GetRequiredDeploymentName() private static string? ConnectionStringValue(DbConnectionStringBuilder connectionString, string key) => connectionString.TryGetValue(key, out var value) ? value as string : null; - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Components/Common/ArgumentExceptionExtensions.cs b/src/Components/Common/ArgumentExceptionExtensions.cs new file mode 100644 index 00000000000..ade5bf85d5c --- /dev/null +++ b/src/Components/Common/ArgumentExceptionExtensions.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace Aspire; + +internal static class ArgumentExceptionExtensions +{ + /// + /// Adds a check Throw ArgumentException if argument is null or empty. + /// And return argument + /// + /// + /// + /// argument not null + public static string ThrowIfNullOrEmpty( + [NotNull] this string? argument, + [CallerArgumentExpression(nameof(argument))] string? paramName = null) + { + ArgumentException.ThrowIfNullOrEmpty(argument, paramName); + return argument; + } + + public static string[] ThrowIfNullOrContainsIsNullOrEmpty( + [NotNull] this string[] args, + [CallerArgumentExpression(nameof(args))] string? paramName = null) + { + ArgumentNullException.ThrowIfNull(args, paramName); + foreach (var arg in args) + { + if (string.IsNullOrEmpty(arg)) + { + var values = string.Join(", ", args); + if (arg is null) + { + throw new ArgumentNullException(paramName, $"Array params contains null item: [{values}]"); + } + throw new ArgumentException($"Array params contains empty item: [{values}]", paramName); + } + } + return args; + } +} From b6a7c8ff32dd0b6cfff0593ac68281c1d6c14bf2 Mon Sep 17 00:00:00 2001 From: ZLoo Date: Tue, 18 Mar 2025 19:38:39 +0300 Subject: [PATCH 2/8] fix mt by feedback(static method, add tests) --- .../AzureOpenAIDeployment.cs | 8 ++- .../AzureCosmosDBContainerResource.cs | 9 +-- .../AzureCosmosDBDatabaseResource.cs | 5 +- .../AzureEventHubConsumerGroupResource.cs | 5 +- .../AzureEventHubResource.cs | 5 +- ...ePostgresFlexibleServerDatabaseResource.cs | 3 +- .../AzureServiceBusQueueResource.cs | 5 +- .../AzureServiceBusRule.cs | 5 +- .../AzureServiceBusSubscriptionResource.cs | 5 +- .../AzureServiceBusTopicResource.cs | 5 +- .../AzureSqlDatabaseResource.cs | 3 +- .../MilvusDatabaseResource.cs | 3 +- .../MongoDBDatabaseResource.cs | 4 +- .../MySqlDatabaseResource.cs | 4 +- .../OracleDatabaseResource.cs | 4 +- .../PostgresDatabaseResource.cs | 4 +- .../PythonAppResourceBuilderExtensions.cs | 3 +- .../SqlServerDatabaseResource.cs | 3 +- .../DistributedApplicationFactory.cs | 3 +- .../DistributedApplicationTestingBuilder.cs | 5 +- .../ApplicationModel/ExecutableResource.cs | 6 +- .../AspireOpenAIClientBuilder.cs | 3 +- .../Common/ArgumentExceptionExtensions.cs | 4 +- .../GarnetPublicApiTests.cs | 38 ++++++++--- .../RedisPublicApiTests.cs | 68 +++++++++++++++---- 25 files changed, 147 insertions(+), 63 deletions(-) diff --git a/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIDeployment.cs b/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIDeployment.cs index 6a16e71fe3a..ec177c41f2a 100644 --- a/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIDeployment.cs +++ b/src/Aspire.Hosting.Azure.CognitiveServices/AzureOpenAIDeployment.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using static Aspire.ArgumentExceptionExtensions; + namespace Aspire.Hosting.ApplicationModel; /// @@ -22,17 +24,17 @@ public class AzureOpenAIDeployment(string name, string modelName, string modelVe /// /// Gets the name of the deployment. /// - public string Name { get; private set; } = name.ThrowIfNullOrEmpty(); + public string Name { get; private set; } = ThrowIfNullOrEmpty(name); /// /// Gets the name of the model. /// - public string ModelName { get; private set; } = modelName.ThrowIfNullOrEmpty(); + public string ModelName { get; private set; } = ThrowIfNullOrEmpty(modelName); /// /// Gets the version of the model. /// - public string ModelVersion { get; private set; } = modelVersion.ThrowIfNullOrEmpty(); + public string ModelVersion { get; private set; } = ThrowIfNullOrEmpty(modelVersion); /// /// Gets the name of the SKU. diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs index b3720a95133..050ff05d488 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.ApplicationModel; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -15,7 +16,7 @@ namespace Aspire.Hosting.Azure; public class AzureCosmosDBContainerResource(string name, string containerName, string partitionKeyPath, AzureCosmosDBDatabaseResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _containerName = containerName.ThrowIfNullOrEmpty(); + private string _containerName = ThrowIfNullOrEmpty(containerName); /// /// Gets or sets the container name. @@ -23,10 +24,10 @@ public class AzureCosmosDBContainerResource(string name, string containerName, s public string ContainerName { get => _containerName; - set => _containerName = value.ThrowIfNullOrEmpty(nameof(containerName)); + set => _containerName = ThrowIfNullOrEmpty(value, nameof(containerName)); } - private string _partitionKeyPath = partitionKeyPath.ThrowIfNullOrEmpty(); + private string _partitionKeyPath = ThrowIfNullOrEmpty(partitionKeyPath); /// /// Gets or sets the partition key path. @@ -34,7 +35,7 @@ public string ContainerName public string PartitionKeyPath { get => _partitionKeyPath; - set => _partitionKeyPath = value.ThrowIfNullOrEmpty(nameof(partitionKeyPath)); + set => _partitionKeyPath = ThrowIfNullOrEmpty(value, nameof(partitionKeyPath)); } /// diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs index 68840adbc26..9809f6e7fe5 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.ApplicationModel; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -15,7 +16,7 @@ namespace Aspire.Hosting.Azure; public class AzureCosmosDBDatabaseResource(string name, string databaseName, AzureCosmosDBResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _databaseName = databaseName.ThrowIfNullOrEmpty(); + private string _databaseName = ThrowIfNullOrEmpty(databaseName); /// /// Gets or sets the database name. @@ -23,7 +24,7 @@ public class AzureCosmosDBDatabaseResource(string name, string databaseName, Azu public string DatabaseName { get => _databaseName; - set => _databaseName = value.ThrowIfNullOrEmpty(nameof(databaseName)); + set => _databaseName = ThrowIfNullOrEmpty(value, nameof(databaseName)); } /// diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubConsumerGroupResource.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubConsumerGroupResource.cs index cb15dee23d5..2c0db7f957b 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubConsumerGroupResource.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubConsumerGroupResource.cs @@ -4,6 +4,7 @@ using System.Text.Json; using Aspire.Hosting.ApplicationModel; using Azure.Provisioning; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -17,7 +18,7 @@ namespace Aspire.Hosting.Azure; public class AzureEventHubConsumerGroupResource(string name, string consumerGroupName, AzureEventHubResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _consumerGroupName = consumerGroupName.ThrowIfNullOrEmpty(); + private string _consumerGroupName = ThrowIfNullOrEmpty(consumerGroupName); /// /// The event hub consumer group name. @@ -25,7 +26,7 @@ public class AzureEventHubConsumerGroupResource(string name, string consumerGrou public string ConsumerGroupName { get => _consumerGroupName; - set => _consumerGroupName = value.ThrowIfNullOrEmpty(nameof(consumerGroupName)); + set => _consumerGroupName = ThrowIfNullOrEmpty(value, nameof(consumerGroupName)); } /// diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs index c6362bc44f3..49bc80b13fa 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubResource.cs @@ -4,6 +4,7 @@ using System.Text.Json; using Aspire.Hosting.ApplicationModel; using Azure.Provisioning; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -17,7 +18,7 @@ namespace Aspire.Hosting.Azure; public class AzureEventHubResource(string name, string hubName, AzureEventHubsResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _hubName = hubName.ThrowIfNullOrEmpty(); + private string _hubName = ThrowIfNullOrEmpty(hubName); /// /// The event hub name. @@ -25,7 +26,7 @@ public class AzureEventHubResource(string name, string hubName, AzureEventHubsRe public string HubName { get => _hubName; - set => _hubName = value.ThrowIfNullOrEmpty(nameof(hubName)); + set => _hubName = ThrowIfNullOrEmpty(value, nameof(hubName)); } /// diff --git a/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresFlexibleServerDatabaseResource.cs b/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresFlexibleServerDatabaseResource.cs index 282f7abd16e..b63dd6c31fe 100644 --- a/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresFlexibleServerDatabaseResource.cs +++ b/src/Aspire.Hosting.Azure.PostgreSQL/AzurePostgresFlexibleServerDatabaseResource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.ApplicationModel; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -27,7 +28,7 @@ public class AzurePostgresFlexibleServerDatabaseResource(string name, string dat /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); + public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); /// /// Gets the inner PostgresDatabaseResource resource. diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusQueueResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusQueueResource.cs index 9ef809545a0..8b07987a4a7 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusQueueResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusQueueResource.cs @@ -5,6 +5,7 @@ using System.Xml; using Aspire.Hosting.ApplicationModel; using Azure.Provisioning; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -18,7 +19,7 @@ namespace Aspire.Hosting.Azure; public class AzureServiceBusQueueResource(string name, string queueName, AzureServiceBusResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _queueName = queueName.ThrowIfNullOrEmpty(); + private string _queueName = ThrowIfNullOrEmpty(queueName); /// /// The queue name. @@ -26,7 +27,7 @@ public class AzureServiceBusQueueResource(string name, string queueName, AzureSe public string QueueName { get => _queueName; - set => _queueName = value.ThrowIfNullOrEmpty(nameof(queueName)); + set => _queueName = ThrowIfNullOrEmpty(value, nameof(queueName)); } /// diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusRule.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusRule.cs index fb32268bbb3..1e623b34d13 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusRule.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusRule.cs @@ -3,6 +3,7 @@ using System.Text.Json; using Azure.Provisioning; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -15,7 +16,7 @@ namespace Aspire.Hosting.Azure; /// public class AzureServiceBusRule(string name) { - private string _name = name.ThrowIfNullOrEmpty(); + private string _name = ThrowIfNullOrEmpty(name); /// /// The rule name. @@ -23,7 +24,7 @@ public class AzureServiceBusRule(string name) public string Name { get => _name; - set => _name = value.ThrowIfNullOrEmpty(nameof(name)); + set => _name = ThrowIfNullOrEmpty(value, nameof(name)); } /// diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusSubscriptionResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusSubscriptionResource.cs index ed3e35107f9..daf73841387 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusSubscriptionResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusSubscriptionResource.cs @@ -5,6 +5,7 @@ using System.Xml; using Aspire.Hosting.ApplicationModel; using Azure.Provisioning; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -18,7 +19,7 @@ namespace Aspire.Hosting.Azure; public class AzureServiceBusSubscriptionResource(string name, string subscriptionName, AzureServiceBusTopicResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _subscriptionName = subscriptionName.ThrowIfNullOrEmpty(); + private string _subscriptionName = ThrowIfNullOrEmpty(subscriptionName); /// /// The subscription name. @@ -26,7 +27,7 @@ public class AzureServiceBusSubscriptionResource(string name, string subscriptio public string SubscriptionName { get => _subscriptionName; - set => _subscriptionName = value.ThrowIfNullOrEmpty(nameof(subscriptionName)); + set => _subscriptionName = ThrowIfNullOrEmpty(value, nameof(subscriptionName)); } /// diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusTopicResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusTopicResource.cs index 6ef616ffa29..e1d44fcd787 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusTopicResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusTopicResource.cs @@ -5,6 +5,7 @@ using System.Xml; using Aspire.Hosting.ApplicationModel; using Azure.Provisioning; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -18,7 +19,7 @@ namespace Aspire.Hosting.Azure; public class AzureServiceBusTopicResource(string name, string topicName, AzureServiceBusResource parent) : Resource(name), IResourceWithParent, IResourceWithConnectionString, IResourceWithAzureFunctionsConfig { - private string _topicName = topicName.ThrowIfNullOrEmpty(); + private string _topicName = ThrowIfNullOrEmpty(topicName); /// /// The topic name. @@ -26,7 +27,7 @@ public class AzureServiceBusTopicResource(string name, string topicName, AzureSe public string TopicName { get => _topicName; - set => _topicName = value.ThrowIfNullOrEmpty(nameof(topicName)); + set => _topicName = ThrowIfNullOrEmpty(value, nameof(topicName)); } /// diff --git a/src/Aspire.Hosting.Azure.Sql/AzureSqlDatabaseResource.cs b/src/Aspire.Hosting.Azure.Sql/AzureSqlDatabaseResource.cs index 2e0af9463e5..7f145cf4dfc 100644 --- a/src/Aspire.Hosting.Azure.Sql/AzureSqlDatabaseResource.cs +++ b/src/Aspire.Hosting.Azure.Sql/AzureSqlDatabaseResource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.ApplicationModel; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Azure; @@ -28,7 +29,7 @@ public class AzureSqlDatabaseResource(string name, string databaseName, AzureSql /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); + public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); /// /// Gets the inner SqlServerDatabaseResource resource. diff --git a/src/Aspire.Hosting.Milvus/MilvusDatabaseResource.cs b/src/Aspire.Hosting.Milvus/MilvusDatabaseResource.cs index 9a3c4329d7d..85ec2c48bc2 100644 --- a/src/Aspire.Hosting.Milvus/MilvusDatabaseResource.cs +++ b/src/Aspire.Hosting.Milvus/MilvusDatabaseResource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.Milvus; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.ApplicationModel; @@ -27,5 +28,5 @@ public class MilvusDatabaseResource(string name, string databaseName, MilvusServ /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); + public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); } diff --git a/src/Aspire.Hosting.MongoDB/MongoDBDatabaseResource.cs b/src/Aspire.Hosting.MongoDB/MongoDBDatabaseResource.cs index f9610b2be0c..7824434664b 100644 --- a/src/Aspire.Hosting.MongoDB/MongoDBDatabaseResource.cs +++ b/src/Aspire.Hosting.MongoDB/MongoDBDatabaseResource.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using static Aspire.ArgumentExceptionExtensions; + namespace Aspire.Hosting.ApplicationModel; /// @@ -25,5 +27,5 @@ public class MongoDBDatabaseResource(string name, string databaseName, MongoDBSe /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); + public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); } diff --git a/src/Aspire.Hosting.MySql/MySqlDatabaseResource.cs b/src/Aspire.Hosting.MySql/MySqlDatabaseResource.cs index 92cc0f19600..6ff68308ddf 100644 --- a/src/Aspire.Hosting.MySql/MySqlDatabaseResource.cs +++ b/src/Aspire.Hosting.MySql/MySqlDatabaseResource.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using static Aspire.ArgumentExceptionExtensions; + namespace Aspire.Hosting.ApplicationModel; /// @@ -26,5 +28,5 @@ public class MySqlDatabaseResource(string name, string databaseName, MySqlServer /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); + public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); } diff --git a/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs b/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs index a304ac62b3b..03703b44213 100644 --- a/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs +++ b/src/Aspire.Hosting.Oracle/OracleDatabaseResource.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using static Aspire.ArgumentExceptionExtensions; + namespace Aspire.Hosting.ApplicationModel; /// @@ -26,5 +28,5 @@ public class OracleDatabaseResource(string name, string databaseName, OracleData /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); + public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); } diff --git a/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs b/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs index a0485cddba9..77d40fbc365 100644 --- a/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs +++ b/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using static Aspire.ArgumentExceptionExtensions; + namespace Aspire.Hosting.ApplicationModel; /// @@ -26,5 +28,5 @@ public class PostgresDatabaseResource(string name, string databaseName, Postgres /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); + public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); } diff --git a/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs b/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs index 28574255b1e..a0f9a37b962 100644 --- a/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs @@ -4,6 +4,7 @@ using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Python; using Aspire.Hosting.Utils; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting; @@ -111,7 +112,7 @@ public static IResourceBuilder AddPythonApp( ArgumentException.ThrowIfNullOrEmpty(appDirectory); ArgumentException.ThrowIfNullOrEmpty(scriptPath); ArgumentException.ThrowIfNullOrEmpty(virtualEnvironmentPath); - scriptArgs.ThrowIfNullOrContainsIsNullOrEmpty(); + ThrowIfNullOrContainsIsNullOrEmpty(scriptArgs); appDirectory = PathNormalizer.NormalizePathForCurrentPlatform(Path.Combine(builder.AppHostDirectory, appDirectory)); var virtualEnvironment = new VirtualEnvironment(Path.IsPathRooted(virtualEnvironmentPath) diff --git a/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs b/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs index 929273670c2..799746a83a0 100644 --- a/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs +++ b/src/Aspire.Hosting.SqlServer/SqlServerDatabaseResource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Data.SqlClient; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.ApplicationModel; @@ -38,5 +39,5 @@ public ReferenceExpression ConnectionStringExpression /// /// Gets the database name. /// - public string DatabaseName { get; } = databaseName.ThrowIfNullOrEmpty(); + public string DatabaseName { get; } = ThrowIfNullOrEmpty(databaseName); } diff --git a/src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs b/src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs index 5a3048af99b..5b3a6c5f791 100644 --- a/src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs +++ b/src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Testing; @@ -21,7 +22,7 @@ namespace Aspire.Hosting.Testing; public class DistributedApplicationFactory(Type entryPoint, string[] args) : IDisposable, IAsyncDisposable { private readonly Type _entryPoint = entryPoint ?? throw new ArgumentNullException(nameof(entryPoint)); - private readonly string[] _args = args.ThrowIfNullOrContainsIsNullOrEmpty(); + private readonly string[] _args = ThrowIfNullOrContainsIsNullOrEmpty(args); private readonly TaskCompletionSource _startedTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly TaskCompletionSource _exitTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly TaskCompletionSource _builderTcs = new(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs b/src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs index 0fa19d0448d..e2d7a395c6b 100644 --- a/src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs +++ b/src/Aspire.Hosting.Testing/DistributedApplicationTestingBuilder.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.Testing; @@ -102,7 +103,7 @@ public static Task CreateAsync CreateAsync(Type entryPoint, string[] args, Action configureBuilder, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(entryPoint); - args.ThrowIfNullOrContainsIsNullOrEmpty(); + ThrowIfNullOrContainsIsNullOrEmpty(args); ArgumentNullException.ThrowIfNull(configureBuilder, nameof(configureBuilder)); var factory = new SuspendingDistributedApplicationFactory(entryPoint, args, configureBuilder); @@ -129,7 +130,7 @@ public static IDistributedApplicationTestingBuilder Create(params string[] args) /// public static IDistributedApplicationTestingBuilder Create(string[] args, Action configureBuilder) { - args.ThrowIfNullOrContainsIsNullOrEmpty(); + ThrowIfNullOrContainsIsNullOrEmpty(args); ArgumentNullException.ThrowIfNull(configureBuilder); return new TestingBuilder(args, configureBuilder); diff --git a/src/Aspire.Hosting/ApplicationModel/ExecutableResource.cs b/src/Aspire.Hosting/ApplicationModel/ExecutableResource.cs index 55cd1b86ab8..27efd877a73 100644 --- a/src/Aspire.Hosting/ApplicationModel/ExecutableResource.cs +++ b/src/Aspire.Hosting/ApplicationModel/ExecutableResource.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using static Aspire.ArgumentExceptionExtensions; + namespace Aspire.Hosting.ApplicationModel; /// @@ -15,10 +17,10 @@ public class ExecutableResource(string name, string command, string workingDirec /// /// Gets the command associated with this executable resource. /// - public string Command { get; } = command.ThrowIfNullOrEmpty(); + public string Command { get; } = ThrowIfNullOrEmpty(command); /// /// Gets the working directory for the executable resource. /// - public string WorkingDirectory { get; } = workingDirectory.ThrowIfNullOrEmpty(); + public string WorkingDirectory { get; } = ThrowIfNullOrEmpty(workingDirectory); } diff --git a/src/Components/Aspire.OpenAI/AspireOpenAIClientBuilder.cs b/src/Components/Aspire.OpenAI/AspireOpenAIClientBuilder.cs index 38e901cd979..6e4ec3ce61f 100644 --- a/src/Components/Aspire.OpenAI/AspireOpenAIClientBuilder.cs +++ b/src/Components/Aspire.OpenAI/AspireOpenAIClientBuilder.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using OpenAI; +using static Aspire.ArgumentExceptionExtensions; namespace Aspire.OpenAI; @@ -29,7 +30,7 @@ public class AspireOpenAIClientBuilder(IHostApplicationBuilder hostBuilder, stri /// /// Gets the name used to retrieve the connection string from the ConnectionStrings configuration section. /// - public string ConnectionName { get; } = connectionName.ThrowIfNullOrEmpty(); + public string ConnectionName { get; } = ThrowIfNullOrEmpty(connectionName); /// /// Gets the service key used to register the service, if any. diff --git a/src/Components/Common/ArgumentExceptionExtensions.cs b/src/Components/Common/ArgumentExceptionExtensions.cs index ade5bf85d5c..16463748426 100644 --- a/src/Components/Common/ArgumentExceptionExtensions.cs +++ b/src/Components/Common/ArgumentExceptionExtensions.cs @@ -16,7 +16,7 @@ internal static class ArgumentExceptionExtensions /// /// argument not null public static string ThrowIfNullOrEmpty( - [NotNull] this string? argument, + [NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) { ArgumentException.ThrowIfNullOrEmpty(argument, paramName); @@ -24,7 +24,7 @@ public static string ThrowIfNullOrEmpty( } public static string[] ThrowIfNullOrContainsIsNullOrEmpty( - [NotNull] this string[] args, + [NotNull] string[] args, [CallerArgumentExpression(nameof(args))] string? paramName = null) { ArgumentNullException.ThrowIfNull(args, paramName); diff --git a/tests/Aspire.Hosting.Garnet.Tests/GarnetPublicApiTests.cs b/tests/Aspire.Hosting.Garnet.Tests/GarnetPublicApiTests.cs index 160671a44df..b9264d96b64 100644 --- a/tests/Aspire.Hosting.Garnet.Tests/GarnetPublicApiTests.cs +++ b/tests/Aspire.Hosting.Garnet.Tests/GarnetPublicApiTests.cs @@ -9,27 +9,45 @@ namespace Aspire.Hosting.Garnet.Tests; public class GarnetPublicApiTests { - [Fact] - public void AddGarnetShouldThrowWhenBuilderIsNull() + [Theory] + [InlineData(0)] + [InlineData(1)] + public void AddGarnetShouldThrowWhenBuilderIsNull(int overrideIndex) { IDistributedApplicationBuilder builder = null!; const string name = "garnet"; + int? port = null; + IResourceBuilder? password = null; - var action = () => builder.AddGarnet(name); + Action action = overrideIndex switch + { + 0 => () => builder.AddGarnet(name, port), + 1 => () => builder.AddGarnet(name, port, password), + _ => throw new InvalidOperationException() + }; var exception = Assert.Throws(action); Assert.Equal(nameof(builder), exception.ParamName); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void AddGarnetShouldThrowWhenNameIsNullOrEmpty(bool isNull) + [InlineData(0, false)] + [InlineData(0, true)] + [InlineData(1, false)] + [InlineData(1, true)] + public void AddGarnetShouldThrowWhenNameIsNullOrEmpty(int overrideIndex, bool isNull) { - var builder = TestDistributedApplicationBuilder.Create(); + using var builder = TestDistributedApplicationBuilder.Create(); var name = isNull ? null! : string.Empty; + int? port = null; + IResourceBuilder? password = null; - var action = () => builder.AddGarnet(name); + Action action = overrideIndex switch + { + 0 => () => builder.AddGarnet(name, port), + 1 => () => builder.AddGarnet(name, port, password), + _ => throw new InvalidOperationException() + }; var exception = isNull ? Assert.Throws(action) @@ -65,8 +83,8 @@ public void WithDataBindMountShouldThrowWhenBuilderIsNull() [InlineData(false)] public void WithDataBindMountShouldThrowWhenSourceIsNullOrEmpty(bool isNull) { - var builder = TestDistributedApplicationBuilder.Create() - .AddGarnet("garnet"); + using var testBuilder = TestDistributedApplicationBuilder.Create(); + var builder = testBuilder.AddGarnet("garnet"); var source = isNull ? null! : string.Empty; var action = () => builder.WithDataBindMount(source); diff --git a/tests/Aspire.Hosting.Redis.Tests/RedisPublicApiTests.cs b/tests/Aspire.Hosting.Redis.Tests/RedisPublicApiTests.cs index 4241bf31001..5e4f9183850 100644 --- a/tests/Aspire.Hosting.Redis.Tests/RedisPublicApiTests.cs +++ b/tests/Aspire.Hosting.Redis.Tests/RedisPublicApiTests.cs @@ -9,27 +9,45 @@ namespace Aspire.Hosting.Redis.Tests; public class RedisPublicApiTests { - [Fact] - public void AddRedisShouldThrowWhenBuilderIsNull() + [Theory] + [InlineData(0)] + [InlineData(1)] + public void AddRedisShouldThrowWhenBuilderIsNull(int overrideIndex) { IDistributedApplicationBuilder builder = null!; const string name = "Redis"; + int? port = null; + IResourceBuilder? password = null; - var action = () => builder.AddRedis(name); + Action action = overrideIndex switch + { + 0 => () => builder.AddRedis(name, port), + 1 => () => builder.AddRedis(name, port, password), + _ => throw new InvalidOperationException() + }; var exception = Assert.Throws(action); Assert.Equal(nameof(builder), exception.ParamName); } [Theory] - [InlineData(true)] - [InlineData(false)] - public void AddRedisShouldThrowWhenNameIsNullOrEmpty(bool isNull) + [InlineData(0, false)] + [InlineData(0, true)] + [InlineData(1, false)] + [InlineData(1, true)] + public void AddRedisShouldThrowWhenNameIsNullOrEmpty(int overrideIndex, bool isNull) { - var builder = TestDistributedApplicationBuilder.Create(); + using var builder = TestDistributedApplicationBuilder.Create(); var name = isNull ? null! : string.Empty; + int? port = null; + IResourceBuilder? password = null; - var action = () => builder.AddRedis(name); + Action action = overrideIndex switch + { + 0 => () => builder.AddRedis(name, port), + 1 => () => builder.AddRedis(name, port, password), + _ => throw new InvalidOperationException() + }; var exception = isNull ? Assert.Throws(action) @@ -111,7 +129,7 @@ public void WithDataBindMountShouldThrowWhenBuilderIsNull() [InlineData(false)] public void WithDataBindMountShouldThrowWhenNameIsNullOrEmpty(bool isNull) { - var builder = TestDistributedApplicationBuilder.Create(); + using var builder = TestDistributedApplicationBuilder.Create(); var redis = builder.AddRedis("Redis"); var source = isNull ? null! : string.Empty; @@ -162,7 +180,7 @@ public void RedisInsightWithDataBindMountShouldThrowWhenBuilderIsNull() [InlineData(false)] public void RedisInsightWithDataBindMountShouldThrowWhenNameIsNullOrEmpty(bool isNull) { - var builder = TestDistributedApplicationBuilder.Create(); + using var builder = TestDistributedApplicationBuilder.Create(); IResourceBuilder? redisInsightBuilder = null; var redis = builder.AddRedis("Redis").WithRedisInsight(resource => { redisInsightBuilder = resource; }); var source = isNull ? null! : string.Empty; @@ -206,14 +224,34 @@ public void CtorRedisInsightResourceShouldThrowWhenNameIsNullOrEmpty(bool isNull Assert.Equal(nameof(name), exception.ParamName); } + [Fact] + public void CtorRedisResourceShouldThrowWhenPasswordIsNull() + { + const string name = "redis"; + ParameterResource password = null!; + + var action = () => new RedisResource(name, password); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(password), exception.ParamName); + } + [Theory] - [InlineData(true)] - [InlineData(false)] - public void CtorRedisResourceShouldThrowWhenNameIsNullOrEmpty(bool isNull) + [InlineData(0, false)] + [InlineData(0, true)] + [InlineData(1, false)] + [InlineData(1, true)] + public void CtorRedisResourceShouldThrowWhenNameIsNullOrEmpty(int overrideIndex, bool isNull) { var name = isNull ? null! : string.Empty; - - var action = () => new RedisResource(name); + var password = new ParameterResource("password", (_) => "password"); + + Action action = overrideIndex switch + { + 0 => () => new RedisResource(name), + 1 => () => new RedisResource(name, password), + _ => throw new InvalidOperationException() + }; var exception = isNull ? Assert.Throws(action) From 58ef279679d10c112187476eab57721ff54658a3 Mon Sep 17 00:00:00 2001 From: ZLoo Date: Wed, 19 Mar 2025 10:00:44 +0300 Subject: [PATCH 3/8] remove not use using --- src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs b/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs index 87182a599b7..7d6443057f7 100644 --- a/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs +++ b/src/Aspire.Hosting.PostgreSQL/PostgresDatabaseResource.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Data.Common; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using static Aspire.ArgumentExceptionExtensions; namespace Aspire.Hosting.ApplicationModel; From 12df020890b8f0c62812664ca391dbb2b661a5ee Mon Sep 17 00:00:00 2001 From: ZLoo Date: Fri, 21 Mar 2025 20:18:05 +0300 Subject: [PATCH 4/8] fix mr conflict --- .../AzureCosmosDBContainerResource.cs | 6 ------ .../AzureCosmosDBDatabaseResource.cs | 6 ------ 2 files changed, 12 deletions(-) diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs index 623a22cea13..fbd70958312 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBContainerResource.cs @@ -65,10 +65,4 @@ void IResourceWithAzureFunctionsConfig.ApplyAzureFunctionsConfiguration(IDiction target[$"Aspire__Microsoft__Azure__Cosmos__{connectionName}__ContainerName"] = ContainerName; } } - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs index 840fd9c921d..538efb145f8 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBDatabaseResource.cs @@ -59,10 +59,4 @@ void IResourceWithAzureFunctionsConfig.ApplyAzureFunctionsConfiguration(IDiction target[$"Aspire__Microsoft__Azure__Cosmos__{connectionName}__DatabaseName"] = DatabaseName; } } - - private static string ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) - { - ArgumentException.ThrowIfNullOrEmpty(argument, paramName); - return argument; - } } From 6e4fc836850d7adfbfb241aa653f28c5b3447eaa Mon Sep 17 00:00:00 2001 From: ZLoo Date: Sat, 26 Apr 2025 13:34:15 +0300 Subject: [PATCH 5/8] fix failed test --- tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs b/tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs index 409e2f49349..e10d5bc8713 100644 --- a/tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs +++ b/tests/Aspire.Hosting.Tests/ExecutableResourceTests.cs @@ -96,10 +96,7 @@ public void ExecutableResourceNullWorkingDirectory() [Fact] public void ExecutableResourceEmptyWorkingDirectory() - { - var er = new ExecutableResource("name", command: "cmd", workingDirectory: ""); - Assert.Empty(er.WorkingDirectory); - } + => Assert.Throws("workingDirectory", () => new ExecutableResource("name", command: "cmd", workingDirectory: "")); private sealed class TestResource(string name, string connectionString) : Resource(name), IResourceWithConnectionString { From 148c580eb6f42d882d44e12c21d37d6d319dec43 Mon Sep 17 00:00:00 2001 From: ZLoo Date: Sat, 26 Apr 2025 14:04:22 +0300 Subject: [PATCH 6/8] remove "Do not call ConfigureAwait(false) in test method" Causes an error in parallel launch --- tests/Aspire.Components.Common.Tests/ConformanceTests.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/Aspire.Components.Common.Tests/ConformanceTests.cs b/tests/Aspire.Components.Common.Tests/ConformanceTests.cs index c6f3523a1d9..9ac1001e6f3 100644 --- a/tests/Aspire.Components.Common.Tests/ConformanceTests.cs +++ b/tests/Aspire.Components.Common.Tests/ConformanceTests.cs @@ -317,13 +317,11 @@ public async Task HealthCheckReportsExpectedStatus(string? key) // DisableRetries so the test doesn't take so long retrying when the server isn't available. using IHost host = CreateHostWithComponent(configureComponent: DisableRetries, key: key); - HealthCheckService healthCheckService = host.Services.GetRequiredService(); + var healthCheckService = host.Services.GetRequiredService(); -#pragma warning disable xUnit1030 // Do not call ConfigureAwait(false) in test method - HealthReport healthReport = await healthCheckService.CheckHealthAsync().ConfigureAwait(false); -#pragma warning restore xUnit1030 // Do not call ConfigureAwait(false) in test method + HealthReport healthReport = await healthCheckService.CheckHealthAsync(); - HealthStatus expected = CanConnectToServer ? HealthStatus.Healthy : HealthStatus.Unhealthy; + var expected = CanConnectToServer ? HealthStatus.Healthy : HealthStatus.Unhealthy; Assert.Equal(expected, healthReport.Status); Assert.NotEmpty(healthReport.Entries); From 3ca50cc16ebfc12dff07396bd250d473a8a9f7bc Mon Sep 17 00:00:00 2001 From: ZLoo Date: Tue, 29 Apr 2025 13:06:40 +0300 Subject: [PATCH 7/8] add XunitCultureAttribute --- .../ProjectResourceTests.cs | 3 + .../UseCultureAttribute.cs | 84 +++++++++++++++++++ .../UseDefaultXunitCultureAttribute.cs | 24 ++++++ 3 files changed, 111 insertions(+) create mode 100644 tests/Aspire.TestUtilities/UseCultureAttribute.cs create mode 100644 tests/Aspire.TestUtilities/UseDefaultXunitCultureAttribute.cs diff --git a/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs b/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs index bdba1bf321f..5486e81dc71 100644 --- a/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs +++ b/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs @@ -6,6 +6,7 @@ using Aspire.Hosting.Tests.Helpers; using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; +using Aspire.TestUtilities; using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -266,6 +267,7 @@ public void WithLaunchProfile_ApplicationUrlTrailingSemiColon_Ignore() } [Fact] + [UseDefaultXunitCulture] public void AddProjectFailsIfFileDoesNotExist() { var appBuilder = CreateBuilder(); @@ -275,6 +277,7 @@ public void AddProjectFailsIfFileDoesNotExist() } [Fact] + [UseDefaultXunitCulture] public void SpecificLaunchProfileFailsIfProfileDoesNotExist() { var appBuilder = CreateBuilder(); diff --git a/tests/Aspire.TestUtilities/UseCultureAttribute.cs b/tests/Aspire.TestUtilities/UseCultureAttribute.cs new file mode 100644 index 00000000000..405b891702d --- /dev/null +++ b/tests/Aspire.TestUtilities/UseCultureAttribute.cs @@ -0,0 +1,84 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using System.Reflection; + +namespace Aspire.TestUtilities; + +/// +/// Apply this attribute to your test method to replace the +/// with another culture. +/// +/// +/// Replaces the culture of the current thread with . +/// +/// The name of the culture to set for both . +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +public abstract class UseCultureAttribute(string culture, string uiCulture) : BeforeAfterTestAttribute +{ + private CultureInfo _originalCulture = Thread.CurrentThread.CurrentCulture; + private CultureInfo _originalUICulture = Thread.CurrentThread.CurrentUICulture; + + private readonly Lazy _culture = new(() => new(culture, useUserOverride: false)); + + /// + /// Gets the culture. + /// + public CultureInfo Culture => _culture.Value; + + private readonly Lazy _uiCulture = new(() => new(uiCulture, useUserOverride: false)); + + /// + /// Gets the UI culture. + /// + public CultureInfo UICulture => _uiCulture.Value; + + /// + /// Replaces the culture and UI culture of the current thread with . + /// + /// The name of the culture to set for both and . + public UseCultureAttribute(string culture) + : this(culture, culture) + { + } + + /// + /// Stores the current + /// + /// and replaces them with the new cultures defined in the constructor. + /// + /// The method under test + public override void Before(MethodInfo methodUnderTest, IXunitTest test) + { + _originalCulture = Thread.CurrentThread.CurrentCulture; + _originalUICulture = Thread.CurrentThread.CurrentUICulture; + + CultureInfo.DefaultThreadCurrentCulture = Culture; + CultureInfo.DefaultThreadCurrentUICulture = UICulture; + + Thread.CurrentThread.CurrentCulture = Culture; + Thread.CurrentThread.CurrentUICulture = UICulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + + base.Before(methodUnderTest, test); + } + + /// + /// Restores the original and + /// to + /// + /// The method under test + public override void After(MethodInfo methodUnderTest, IXunitTest test) + { + Thread.CurrentThread.CurrentCulture = _originalCulture; + Thread.CurrentThread.CurrentUICulture = _originalUICulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + + base.After(methodUnderTest, test); + } +} diff --git a/tests/Aspire.TestUtilities/UseDefaultXunitCultureAttribute.cs b/tests/Aspire.TestUtilities/UseDefaultXunitCultureAttribute.cs new file mode 100644 index 00000000000..ef0d2d3c7da --- /dev/null +++ b/tests/Aspire.TestUtilities/UseDefaultXunitCultureAttribute.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; + +namespace Aspire.TestUtilities; + +/// +/// Apply this attribute to your test method to replace the +/// with another culture. +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +public sealed class UseDefaultXunitCultureAttribute : UseCultureAttribute +{ + public const string DefaultXunitCultureAttribute = "en-US"; + + /// + /// Replaces the culture of the current thread with the . + /// + public UseDefaultXunitCultureAttribute() + : base(DefaultXunitCultureAttribute, DefaultXunitCultureAttribute) + { + } +} From 339042becc08ac11e4208edc0a6645b07e342caf Mon Sep 17 00:00:00 2001 From: ZLoo Date: Tue, 29 Apr 2025 21:21:59 +0300 Subject: [PATCH 8/8] Revert "add XunitCultureAttribute" This reverts commit 3ca50cc16ebfc12dff07396bd250d473a8a9f7bc. --- .../ProjectResourceTests.cs | 3 - .../UseCultureAttribute.cs | 84 ------------------- .../UseDefaultXunitCultureAttribute.cs | 24 ------ 3 files changed, 111 deletions(-) delete mode 100644 tests/Aspire.TestUtilities/UseCultureAttribute.cs delete mode 100644 tests/Aspire.TestUtilities/UseDefaultXunitCultureAttribute.cs diff --git a/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs b/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs index 5486e81dc71..bdba1bf321f 100644 --- a/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs +++ b/tests/Aspire.Hosting.Tests/ProjectResourceTests.cs @@ -6,7 +6,6 @@ using Aspire.Hosting.Tests.Helpers; using Aspire.Hosting.Tests.Utils; using Aspire.Hosting.Utils; -using Aspire.TestUtilities; using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -267,7 +266,6 @@ public void WithLaunchProfile_ApplicationUrlTrailingSemiColon_Ignore() } [Fact] - [UseDefaultXunitCulture] public void AddProjectFailsIfFileDoesNotExist() { var appBuilder = CreateBuilder(); @@ -277,7 +275,6 @@ public void AddProjectFailsIfFileDoesNotExist() } [Fact] - [UseDefaultXunitCulture] public void SpecificLaunchProfileFailsIfProfileDoesNotExist() { var appBuilder = CreateBuilder(); diff --git a/tests/Aspire.TestUtilities/UseCultureAttribute.cs b/tests/Aspire.TestUtilities/UseCultureAttribute.cs deleted file mode 100644 index 405b891702d..00000000000 --- a/tests/Aspire.TestUtilities/UseCultureAttribute.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Globalization; -using System.Reflection; - -namespace Aspire.TestUtilities; - -/// -/// Apply this attribute to your test method to replace the -/// with another culture. -/// -/// -/// Replaces the culture of the current thread with . -/// -/// The name of the culture to set for both . -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] -public abstract class UseCultureAttribute(string culture, string uiCulture) : BeforeAfterTestAttribute -{ - private CultureInfo _originalCulture = Thread.CurrentThread.CurrentCulture; - private CultureInfo _originalUICulture = Thread.CurrentThread.CurrentUICulture; - - private readonly Lazy _culture = new(() => new(culture, useUserOverride: false)); - - /// - /// Gets the culture. - /// - public CultureInfo Culture => _culture.Value; - - private readonly Lazy _uiCulture = new(() => new(uiCulture, useUserOverride: false)); - - /// - /// Gets the UI culture. - /// - public CultureInfo UICulture => _uiCulture.Value; - - /// - /// Replaces the culture and UI culture of the current thread with . - /// - /// The name of the culture to set for both and . - public UseCultureAttribute(string culture) - : this(culture, culture) - { - } - - /// - /// Stores the current - /// - /// and replaces them with the new cultures defined in the constructor. - /// - /// The method under test - public override void Before(MethodInfo methodUnderTest, IXunitTest test) - { - _originalCulture = Thread.CurrentThread.CurrentCulture; - _originalUICulture = Thread.CurrentThread.CurrentUICulture; - - CultureInfo.DefaultThreadCurrentCulture = Culture; - CultureInfo.DefaultThreadCurrentUICulture = UICulture; - - Thread.CurrentThread.CurrentCulture = Culture; - Thread.CurrentThread.CurrentUICulture = UICulture; - - CultureInfo.CurrentCulture.ClearCachedData(); - CultureInfo.CurrentUICulture.ClearCachedData(); - - base.Before(methodUnderTest, test); - } - - /// - /// Restores the original and - /// to - /// - /// The method under test - public override void After(MethodInfo methodUnderTest, IXunitTest test) - { - Thread.CurrentThread.CurrentCulture = _originalCulture; - Thread.CurrentThread.CurrentUICulture = _originalUICulture; - - CultureInfo.CurrentCulture.ClearCachedData(); - CultureInfo.CurrentUICulture.ClearCachedData(); - - base.After(methodUnderTest, test); - } -} diff --git a/tests/Aspire.TestUtilities/UseDefaultXunitCultureAttribute.cs b/tests/Aspire.TestUtilities/UseDefaultXunitCultureAttribute.cs deleted file mode 100644 index ef0d2d3c7da..00000000000 --- a/tests/Aspire.TestUtilities/UseDefaultXunitCultureAttribute.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Globalization; - -namespace Aspire.TestUtilities; - -/// -/// Apply this attribute to your test method to replace the -/// with another culture. -/// -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] -public sealed class UseDefaultXunitCultureAttribute : UseCultureAttribute -{ - public const string DefaultXunitCultureAttribute = "en-US"; - - /// - /// Replaces the culture of the current thread with the . - /// - public UseDefaultXunitCultureAttribute() - : base(DefaultXunitCultureAttribute, DefaultXunitCultureAttribute) - { - } -}