Skip to content

Commit

Permalink
Configuration Schema generator (#1383)
Browse files Browse the repository at this point in the history
Adds a tool that automatically generates ConfigurationSchema.json files for components.

To use the tool, a component adds an assembly attribute. For example:

```C#
[assembly: ConfigurationSchema("Aspire:Azure:Storage:Blobs", typeof(AzureStorageBlobsSettings))]
[assembly: ConfigurationSchema("Aspire:Azure:Storage:Blobs:ClientOptions", typeof(BlobClientOptions), exclusionPaths: ["Default"])]

[assembly: LoggingCategories("Azure", "Azure.Core", "Azure.Identity")]
```

### ConfigurationSchemaAttribute

* The first parameter is the config section path where the type is loaded from.
* The second parameter is the Type that is bound at that path.
* ExclusionPaths - (optional) The config sections to exclude from the ConfigurationSchema. This is useful if there are properties you don't want to publicize in the config schema.

### LoggingCategoriesAttribute
* The list of log categories produced by the component. These categories will show up under the `Logging` section in appsettings.json

This tool works after compilation by scanning the assembly for `ConfigurationSchema` and `LoggingCategories` attributes, and uses Roslyn APIs to inspect all properties of the types. It reuses all the parsing logic from https://github.com/dotnet/runtime/tree/main/src/libraries/Microsoft.Extensions.Configuration.Binder/gen, and using the underlying model objects, generates a JSON schema using System.Text.Json.Nodes APIs.

I've copied the necessary code from dotnet/runtime into the `RuntimeSource` folder for now. This code doesn't need to be reviewed since it is a straight copy from dotnet/runtime. After this PR goes through, we will set up an automatic "sync" action that will update this code anytime changes in the dotnet/runtime code is updated.

Fix #1146
  • Loading branch information
eerhardt authored Dec 15, 2023
1 parent f93cc16 commit 4794d39
Show file tree
Hide file tree
Showing 56 changed files with 4,683 additions and 62 deletions.
9 changes: 9 additions & 0 deletions Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.MySqlConnector.Tests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestProject.IntegrationServiceA", "tests\testproject\TestProject.IntegrationServiceA\TestProject.IntegrationServiceA.csproj", "{DCF2D47A-921A-4900-B5B2-CF97B3531CE8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2136E31D-2CBB-41BB-8618-716FF8E46E9E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationSchemaGenerator", "src\Tools\ConfigurationSchemaGenerator\ConfigurationSchemaGenerator.csproj", "{39FA2A64-012F-4EB9-A14F-E8AC54C975F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.MongoDB.Driver", "src\Components\Aspire.MongoDB.Driver\Aspire.MongoDB.Driver.csproj", "{20A5A907-A135-4735-B4BF-E13514F360E3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.MongoDB.Driver.Tests", "tests\Aspire.MongoDB.Driver.Tests\Aspire.MongoDB.Driver.Tests.csproj", "{E592E447-BA3C-44FA-86C1-EBEDC864A644}"
Expand Down Expand Up @@ -447,6 +451,10 @@ Global
{6472D59F-7C04-43DE-AD33-9F20BE3804BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6472D59F-7C04-43DE-AD33-9F20BE3804BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6472D59F-7C04-43DE-AD33-9F20BE3804BF}.Release|Any CPU.Build.0 = Release|Any CPU
{39FA2A64-012F-4EB9-A14F-E8AC54C975F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39FA2A64-012F-4EB9-A14F-E8AC54C975F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39FA2A64-012F-4EB9-A14F-E8AC54C975F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39FA2A64-012F-4EB9-A14F-E8AC54C975F6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -524,6 +532,7 @@ Global
{20A5A907-A135-4735-B4BF-E13514F360E3} = {27381127-6C45-4B4C-8F18-41FF48DFE4B2}
{E592E447-BA3C-44FA-86C1-EBEDC864A644} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{DCF2D47A-921A-4900-B5B2-CF97B3531CE8} = {975F6F41-B455-451D-A312-098DE4A167B6}
{39FA2A64-012F-4EB9-A14F-E8AC54C975F6} = {2136E31D-2CBB-41BB-8618-716FF8E46E9E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6DCEDFEC-988E-4CB3-B45B-191EB5086E0C}
Expand Down
3 changes: 3 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="$(MicrosoftExtensionsDiagnosticsHealthChecksEntityFrameworkCorePackageVersion)" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="$(MicrosoftExtensionsDiagnosticsHealthChecksPackageVersion)" />
<PackageVersion Include="Microsoft.Extensions.Features" Version="$(MicrosoftExtensionsFeaturesPackageVersion)" />
<!-- Roslyn dependencies -->
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" />
<!-- AspNetCore.HealthChecks dependencies (3rd party packages) -->
<PackageVersion Include="AspNetCore.HealthChecks.Azure.Data.Tables" Version="8.0.0" />
<PackageVersion Include="AspNetCore.HealthChecks.Azure.KeyVault.Secrets" Version="8.0.0" />
Expand Down Expand Up @@ -82,6 +84,7 @@
<PackageVersion Include="StackExchange.Redis" Version="2.7.4" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Yarp.ReverseProxy" Version="2.1.0" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.23407.1" />
<!-- Open Telemetry -->
<PackageVersion Include="Npgsql.OpenTelemetry" Version="8.0.0" />
<PackageVersion Include="OpenTelemetry.Exporter.InMemory" Version="1.7.0-alpha.1" />
Expand Down
1 change: 1 addition & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
</packageSource>
<packageSource key="dotnet-libraries">
<package pattern="Microsoft.DeveloperControlPlane*" />
<package pattern="System.CommandLine" />
</packageSource>
<packageSource key="dotnet-eng">
<package pattern="*" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<ItemGroup>
<Compile Include="..\Common\AzureComponent.cs" Link="AzureComponent.cs" />
<Compile Include="..\Common\ConfigurationSchemaAttributes.cs" Link="ConfigurationSchemaAttributes.cs" />
<Compile Include="..\Common\HealthChecksExtensions.cs" Link="HealthChecksExtensions.cs" />
</ItemGroup>

Expand Down
11 changes: 11 additions & 0 deletions src/Components/Aspire.Azure.Storage.Blobs/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Azure.Storage.Blobs;
using Aspire;
using Azure.Storage.Blobs;

[assembly: ConfigurationSchema("Aspire:Azure:Storage:Blobs", typeof(AzureStorageBlobsSettings))]
[assembly: ConfigurationSchema("Aspire:Azure:Storage:Blobs:ClientOptions", typeof(BlobClientOptions), exclusionPaths: ["Default"])]

[assembly: LoggingCategories("Azure", "Azure.Core", "Azure.Identity")]
137 changes: 109 additions & 28 deletions src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,75 +27,156 @@
"Blobs": {
"type": "object",
"properties": {
"ServiceUri": {
"type": "string",
"format": "uri",
"description": "Gets or sets the 'Uri' referencing the Blob service. This is likely to be similar to \"https://{account_name}.blob.core.windows.net\""
},
"HealthChecks": {
"type": "boolean",
"description": "Gets or sets a boolean value that indicates whether the Blob Storage health check is enabled or not.",
"default": true
},
"Tracing": {
"type": "boolean",
"description": "Gets or sets a boolean value that indicates whether the OpenTelemetry tracing is enabled or not.",
"default": false
},
"ClientOptions": {
"type": "object",
"description": "Provides the client configuration options for connecting to Azure Blob Storage.",
"properties": {
"Diagnostics": {
"type": "object",
"properties": {
"ApplicationId": {
"type": "string",
"description": "Gets or sets the value sent as the first part of \u0022User-Agent\u0022 headers for all requests issues by this client. Defaults to P:Azure.Core.DiagnosticsOptions.DefaultApplicationId."
},
"DefaultApplicationId": {
"type": "string",
"description": "Gets or sets the default application id. Default application id would be set on all instances."
},
"IsDistributedTracingEnabled": {
"type": "boolean",
"description": "Gets or sets value indicating whether distributed tracing activities ( T:System.Diagnostics.Activity ) are going to be created for the clients methods calls and HTTP calls."
},
"IsLoggingContentEnabled": {
"type": "boolean",
"description": "Gets or sets value indicating if request or response content should be logged."
},
"IsLoggingEnabled": {
"type": "boolean",
"description": "Get or sets value indicating whether HTTP pipeline logging is enabled."
},
"IsTelemetryEnabled": {
"type": "boolean",
"description": "Gets or sets value indicating whether the \u0022User-Agent\u0022 header containing P:Azure.Core.DiagnosticsOptions.ApplicationId , client library package name and version, P:System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription and P:System.Runtime.InteropServices.RuntimeInformation.OSDescription should be sent.\n The default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0."
},
"LoggedContentSizeLimit": {
"type": "integer",
"description": "Gets or sets value indicating maximum size of content to log in bytes. Defaults to 4096."
}
},
"description": "Gets the client diagnostic options."
},
"EnableTenantDiscovery": {
"type": "boolean",
"description": "Enables tenant discovery through the authorization challenge when the client is configured to use a TokenCredential. When enabled, the client will attempt an initial un-authorized request to prompt a challenge in order to discover the correct tenant for the resource."
"description": "Enables tenant discovery through the authorization challenge when the client is configured to use a TokenCredential.\n When enabled, the client will attempt an initial un-authorized request to prompt a challenge in order to discover the correct tenant for the resource."
},
"EncryptionScope": {
"type": "string",
"description": "Gets the EncryptionScope to be used when making requests."
"description": "Gets the P:Azure.Storage.Blobs.BlobClientOptions.EncryptionScope to be used when making requests."
},
"GeoRedundantSecondaryUri": {
"type": "string",
"format": "uri",
"description": "Gets or sets the secondary storage Uri that can be read from for the storage account if the account is enabled for RA-GRS."
"description": "Gets or sets the secondary storage T:System.Uri that can be read from for the storage account if the\n account is enabled for RA-GRS.\n \n If this property is set, the secondary Uri will be used for GET or HEAD requests during retries.\n If the status of the response from the secondary Uri is a 404, then subsequent retries for\n the request will not use the secondary Uri again, as this indicates that the resource\n may not have propagated there yet. Otherwise, subsequent retries will alternate back and forth\n between primary and secondary Uri."
},
"Retry": {
"type": "object",
"description": "The set of options that can be specified to influence how retry attempts are made, and a failure is eligible to be retried",
"properties": {
"Delay": {
"type": "string",
"format": "duration",
"description": "The delay between retry attempts for a fixed approach or the delay on which to base calculations for a backoff-based approach. If the service provides a Retry-After response header, the next retry will be delayed by the duration specified by the header value."
"description": "The delay between retry attempts for a fixed approach or the delay\n on which to base calculations for a backoff-based approach.\n If the service provides a Retry-After response header, the next retry will be delayed by the duration specified by the header value."
},
"MaxDelay": {
"type": "string",
"format": "duration",
"description": "The maximum permissible delay between retry attempts when the service does not provide a Retry-After response header. If the service provides a Retry-After response header, the next retry will be delayed by the duration specified by the header value."
"description": "The maximum permissible delay between retry attempts when the service does not provide a Retry-After response header.\n If the service provides a Retry-After response header, the next retry will be delayed by the duration specified by the header value."
},
"MaxRetries": {
"type": "integer",
"description": "The maximum number of retry attempts before giving up."
},
"Mode": {
"enum": [ "Fixed", "Exponential" ],
"enum": [
"Fixed",
"Exponential"
],
"description": "The approach to use for calculating retry delays."
},
"NetworkTimeout": {
"type": "string",
"format": "duration",
"description": "The timeout applied to an individual network operations."
}
}
},
"description": "Gets the client retry options."
},
"TransferValidation": {
"type": "object",
"properties": {
"Download": {
"type": "object",
"properties": {
"AutoValidateChecksum": {
"type": "boolean",
"description": "Defaults to true. False can only be specified on specific operations and not at the client level.\n Indicates whether the SDK should validate the content\n body against the content hash before returning contents to the caller.\n If set to false, caller is responsible for extracting the hash out\n of the T:Azure.Response\u00601 and validating the hash themselves."
},
"ChecksumAlgorithm": {
"enum": [
"Auto",
"None",
"MD5",
"StorageCrc64"
],
"description": "Checksum algorithm to use."
}
},
"description": "Options on download."
},
"Upload": {
"type": "object",
"properties": {
"ChecksumAlgorithm": {
"enum": [
"Auto",
"None",
"MD5",
"StorageCrc64"
],
"description": "Checksum algorithm to use."
}
},
"description": "Options on upload."
}
},
"description": "Configures whether to send or receive checksum headers for blob uploads and downloads. Downloads\n can optionally validate that the content matches the checksum."
},
"TrimBlobNameSlashes": {
"type": "boolean",
"description": "Whether to trim leading and trailing slashes on a blob name when using GetBlobClient(String) and similar methods.",
"default": true
"description": "Whether to trim leading and trailing slashes on a blob name when using M:Azure.Storage.Blobs.BlobContainerClient.GetBlobClient(System.String) and similar methods.\n Defaults to true for backwards compatibility."
}
}
},
"description": "Provides the client configuration options for connecting to Azure Blob\n Storage."
},
"ConnectionString": {
"type": "string",
"description": "Gets or sets the connection string used to connect to the blob service."
},
"HealthChecks": {
"type": "boolean",
"description": "Gets or sets a boolean value that indicates whether the Blob Storage health check is enabled or not.",
"default": true
},
"ServiceUri": {
"type": "string",
"format": "uri",
"description": "A T:System.Uri referencing the blob service.\n This is likely to be similar to \u0022https://{account_name}.blob.core.windows.net\u0022."
},
"Tracing": {
"type": "boolean",
"description": "Gets or sets a boolean value that indicates whether the OpenTelemetry tracing is enabled or not.",
"default": true
}
}
},
"description": "Provides the client configuration settings for connecting to Azure Blob Storage."
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<Compile Include="..\Common\HealthChecksExtensions.cs" Link="HealthChecksExtensions.cs" />
<Compile Include="..\Common\ConfigurationSchemaAttributes.cs" Link="ConfigurationSchemaAttributes.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
15 changes: 15 additions & 0 deletions src/Components/Aspire.MySqlConnector/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.MySqlConnector;
using Aspire;

[assembly: ConfigurationSchema("Aspire:MySqlConnector", typeof(MySqlConnectorSettings))]

[assembly: LoggingCategories(
"MySqlConnector",
"MySqlConnector.ConnectionPool",
"MySqlConnector.MySqlBulkCopy",
"MySqlConnector.MySqlCommand",
"MySqlConnector.MySqlConnection",
"MySqlConnector.MySqlDataSource")]
Loading

0 comments on commit 4794d39

Please sign in to comment.