Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable nullable reference types #590

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
<Project>

<PropertyGroup>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
</PropertyGroup>
<PropertyGroup>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
</PropertyGroup>

</Project>
<PropertyGroup>
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Nullable" Version="1.3.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Required" Version="1.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion examples/ConfigStoreDemo/Pages/About.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Examples.Conf
{
public class AboutModel : PageModel
{
public string Message { get; set; }
public string? Message { get; set; }

public void OnGet()
{
Expand Down
2 changes: 1 addition & 1 deletion examples/ConfigStoreDemo/Pages/Contact.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Examples.Conf
{
public class ContactModel : PageModel
{
public string Message { get; set; }
public string? Message { get; set; }

public void OnGet()
{
Expand Down
2 changes: 1 addition & 1 deletion examples/ConfigStoreDemo/Pages/Error.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Examples.Conf
{
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public string? RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

Expand Down
8 changes: 7 additions & 1 deletion examples/ConfigStoreDemo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ public static IWebHost BuildWebHost(string[] args)
var settings = config.AddJsonFile("appsettings.json").Build();
config.AddAzureAppConfiguration(options =>
{
options.Connect(settings["connection_string"])
var connectionString = settings["connection_string"];
if (string.IsNullOrEmpty(connectionString))
{
throw new InvalidOperationException("Connection string not found");
}

options.Connect(connectionString)
.ConfigureRefresh(refresh =>
{
refresh.Register("Settings:BackgroundColor")
Expand Down
8 changes: 4 additions & 4 deletions examples/ConfigStoreDemo/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Examples.Conf
{
public class Settings
{
public string AppName { get; set; }
public string? AppName { get; set; }
public double Version { get; set; }
public long RefreshRate { get; set; }
public long FontSize { get; set; }
public string Language { get; set; }
public string Messages { get; set; }
public string BackgroundColor { get; set; }
public string? Language { get; set; }
public string? Messages { get; set; }
public string? BackgroundColor { get; set; }
}
}
4 changes: 2 additions & 2 deletions examples/ConsoleAppWithFailOver/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Examples.Cons
{
class Program
{
static IConfiguration Configuration { get; set; }
static IConfiguration? Configuration { get; set; }

static void Main(string[] args)
{
Expand All @@ -31,7 +31,7 @@ private static void Configure()
IConfiguration configuration = builder.Build();

IConfigurationSection endpointsSection = configuration.GetSection("AppConfig:Endpoints");
IEnumerable<Uri> endpoints = endpointsSection.GetChildren().Select(endpoint => new Uri(endpoint.Value));
IEnumerable<Uri> endpoints = endpointsSection.GetChildren().Select(endpoint => new Uri(endpoint.Value!));

if (endpoints == null || !endpoints.Any())
{
Expand Down
18 changes: 10 additions & 8 deletions examples/ConsoleApplication/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Examples.Cons
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

class Program
{
static IConfiguration Configuration { get; set; }
static IConfigurationRefresher _refresher;
static IConfiguration? Configuration { get; set; }
static IConfigurationRefresher? _refresher;

static void Main(string[] args)
{
Expand All @@ -28,6 +29,7 @@ static void Main(string[] args)
cts.Cancel();
}

[MemberNotNull(nameof(Configuration))]
private static void Configure()
{
var builder = new ConfigurationBuilder();
Expand All @@ -38,18 +40,18 @@ private static void Configure()

IConfiguration configuration = builder.Build();

if (string.IsNullOrEmpty(configuration["connection_string"]))
var connectionString = configuration["connection_string"];
if (string.IsNullOrEmpty(connectionString))
{
Console.WriteLine("Connection string not found.");
Console.WriteLine("Please set the 'connection_string' environment variable to a valid Azure App Configuration connection string and re-run this example.");
return;
throw new InvalidOperationException("Connection string not found");
}

// Augment the configuration builder with Azure App Configuration
// Pull the connection string from an environment variable
builder.AddAzureAppConfiguration(options =>
{
options.Connect(configuration["connection_string"])
options.Connect(connectionString)
.Select("AppName")
.Select("Settings:BackgroundColor")
.ConfigureClientOptions(clientOptions => clientOptions.Retry.MaxRetries = 5)
Expand All @@ -75,9 +77,9 @@ private static async Task Run(CancellationToken token)
while (!token.IsCancellationRequested)
{
// Trigger an async refresh for registered configuration settings without wait
_ = _refresher.TryRefreshAsync();
_ = _refresher!.TryRefreshAsync();

sb.AppendLine($"{Configuration["AppName"]} has been configured to run in {Configuration["Language"]}");
sb.AppendLine($"{Configuration!["AppName"]} has been configured to run in {Configuration["Language"]}");
sb.AppendLine();

sb.AppendLine(string.Equals(Configuration["Language"], "spanish", StringComparison.OrdinalIgnoreCase) ? "Buenos Dias." : "Good morning");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static IApplicationBuilder UseAzureAppConfiguration(this IApplicationBuil
throw new ArgumentNullException(nameof(builder));
}

IConfigurationRefresherProvider refresherProvider = (IConfigurationRefresherProvider)builder.ApplicationServices.GetService(typeof(IConfigurationRefresherProvider));
IConfigurationRefresherProvider? refresherProvider = (IConfigurationRefresherProvider?)builder.ApplicationServices.GetService(typeof(IConfigurationRefresherProvider));

// Verify if AddAzureAppConfiguration was done before calling UseAzureAppConfiguration.
// We use the IConfigurationRefresherProvider to make sure if the required services were added.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static class AzureAppConfigurationRefreshExtensions
public static IFunctionsWorkerApplicationBuilder UseAzureAppConfiguration(this IFunctionsWorkerApplicationBuilder builder)
{
IServiceProvider serviceProvider = builder.Services.BuildServiceProvider();
IConfigurationRefresherProvider refresherProvider = serviceProvider.GetService<IConfigurationRefresherProvider>();
IConfigurationRefresherProvider? refresherProvider = serviceProvider.GetService<IConfigurationRefresherProvider>();

// Verify if AddAzureAppConfiguration was done before calling UseAzureAppConfiguration.
// We use the IConfigurationRefresherProvider to make sure if the required services were added.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Azure.Security.KeyVault.Secrets;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;

namespace Microsoft.Extensions.Configuration.AzureAppConfiguration
Expand All @@ -14,10 +15,10 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration
/// </summary>
public class AzureAppConfigurationKeyVaultOptions
{
internal TokenCredential Credential;
internal TokenCredential? Credential;
internal SecretClientOptions ClientOptions = new SecretClientOptions();
internal List<SecretClient> SecretClients = new List<SecretClient>();
internal Func<Uri, ValueTask<string>> SecretResolver;
internal Func<Uri, ValueTask<string>>? SecretResolver;
internal Dictionary<string, TimeSpan> SecretRefreshIntervals = new Dictionary<string, TimeSpan>();
internal TimeSpan? DefaultSecretRefreshInterval = null;
internal bool IsKeyVaultRefreshConfigured = false;
Expand All @@ -26,6 +27,7 @@ public class AzureAppConfigurationKeyVaultOptions
/// Sets the credentials used to authenticate to key vaults that have no registered <see cref="SecretClient"/>.
/// </summary>
/// <param name="credential">Default token credentials.</param>
[MemberNotNull(nameof(Credential))]
public AzureAppConfigurationKeyVaultOptions SetCredential(TokenCredential credential)
{
Credential = credential;
Expand Down Expand Up @@ -57,6 +59,7 @@ public AzureAppConfigurationKeyVaultOptions Register(SecretClient secretClient)
/// Sets the callback used to resolve key vault references that have no registered <see cref="SecretClient"/>.
/// </summary>
/// <param name="secretResolver">A callback that maps the <see cref="Uri"/> of the key vault secret to its value.</param>
[MemberNotNull(nameof(SecretResolver))]
public AzureAppConfigurationKeyVaultOptions SetSecretResolver(Func<Uri, ValueTask<string>> secretResolver)
{
if (secretResolver == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,19 @@ public class AzureAppConfigurationOptions
/// <summary>
/// The list of connection strings used to connect to an Azure App Configuration store and its replicas.
/// </summary>
internal IEnumerable<string> ConnectionStrings { get; private set; }
internal IEnumerable<string>? ConnectionStrings { get; private set; }

/// <summary>
/// The list of endpoints of an Azure App Configuration store.
/// If this property is set, the <see cref="Credential"/> property also needs to be set.
/// </summary>
internal IEnumerable<Uri> Endpoints { get; private set; }
internal IEnumerable<Uri>? Endpoints { get; private set; }

/// <summary>
/// The credential used to connect to the Azure App Configuration.
/// If this property is set, the <see cref="Endpoints"/> property also needs to be set.
/// </summary>
internal TokenCredential Credential { get; private set; }
internal TokenCredential? Credential { get; private set; }

/// <summary>
/// A collection of <see cref="KeyValueSelector"/>.
Expand All @@ -77,7 +77,7 @@ public class AzureAppConfigurationOptions
internal IEnumerable<IKeyValueAdapter> Adapters
{
get => _adapters;
set => _adapters = value?.ToList();
set => _adapters = value.ToList();
}

/// <summary>
Expand All @@ -94,7 +94,7 @@ internal IEnumerable<IKeyValueAdapter> Adapters
/// An optional configuration client manager that can be used to provide clients to communicate with Azure App Configuration.
/// </summary>
/// <remarks>This property is used only for unit testing.</remarks>
internal IConfigurationClientManager ClientManager { get; set; }
internal IConfigurationClientManager? ClientManager { get; set; }

/// <summary>
/// An optional timespan value to set the minimum backoff duration to a value other than the default.
Expand Down Expand Up @@ -158,7 +158,7 @@ public AzureAppConfigurationOptions()
/// The label filter to apply when querying Azure App Configuration for key-values. By default the null label will be used. Built-in label filter options: <see cref="LabelFilter"/>
/// The characters asterisk (*) and comma (,) are not supported. Backslash (\) character is reserved and must be escaped using another backslash (\).
/// </param>
public AzureAppConfigurationOptions Select(string keyFilter, string labelFilter = LabelFilter.Null)
public AzureAppConfigurationOptions Select(string keyFilter, string? labelFilter = LabelFilter.Null)
{
if (string.IsNullOrEmpty(keyFilter))
{
Expand All @@ -177,10 +177,10 @@ public AzureAppConfigurationOptions Select(string keyFilter, string labelFilter
}

_kvSelectors.AppendUnique(new KeyValueSelector
{
KeyFilter = keyFilter,
LabelFilter = labelFilter
});
(
keyFilter: keyFilter,
labelFilter: labelFilter!
));
return this;
}

Expand All @@ -196,10 +196,7 @@ public AzureAppConfigurationOptions SelectSnapshot(string name)
throw new ArgumentNullException(nameof(name));
}

_kvSelectors.AppendUnique(new KeyValueSelector
{
SnapshotName = name
});
_kvSelectors.AppendUnique(new KeyValueSelector(snapshotName: name));

return this;
}
Expand All @@ -210,7 +207,7 @@ public AzureAppConfigurationOptions SelectSnapshot(string name)
/// All loaded feature flags will be automatically registered for refresh on an individual flag level.
/// </summary>
/// <param name="configure">A callback used to configure feature flag options.</param>
public AzureAppConfigurationOptions UseFeatureFlags(Action<FeatureFlagOptions> configure = null)
public AzureAppConfigurationOptions UseFeatureFlags(Action<FeatureFlagOptions>? configure = null)
{
FeatureFlagOptions options = new FeatureFlagOptions();
configure?.Invoke(options);
Expand All @@ -230,23 +227,23 @@ public AzureAppConfigurationOptions UseFeatureFlags(Action<FeatureFlagOptions> c
{
// Select clause is not present
options.FeatureFlagSelectors.Add(new KeyValueSelector
{
KeyFilter = FeatureManagementConstants.FeatureFlagMarker + "*",
LabelFilter = options.Label == null ? LabelFilter.Null : options.Label
});
(
keyFilter: FeatureManagementConstants.FeatureFlagMarker + "*",
labelFilter: options.Label == null ? LabelFilter.Null : options.Label
));
}

foreach (var featureFlagSelector in options.FeatureFlagSelectors)
{
var featureFlagFilter = featureFlagSelector.KeyFilter;
var labelFilter = featureFlagSelector.LabelFilter;

Select(featureFlagFilter, labelFilter);
Select(featureFlagFilter!, labelFilter!);

_multiKeyWatchers.AppendUnique(new KeyValueWatcher
{
Key = featureFlagFilter,
Label = labelFilter,
Key = featureFlagFilter!,
Label = labelFilter!,
Comment on lines +241 to +246
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here there's no check that featureFlagSelector.KeyFilter and featureFlagSelector.LabelFilter are not null. They might be since featureFlagSelector could be initialized with SnapshotName

// If UseFeatureFlags is called multiple times for the same key and label filters, last cache expiration time wins
CacheExpirationInterval = options.CacheExpirationInterval
});
Expand Down
Loading