Add nullable to DataProtection (#22591)

* Add nullable to DataProtection

Contributes to https://github.com/dotnet/aspnetcore/issues/5680
This commit is contained in:
Pranav K 2020-06-13 20:39:41 -07:00 committed by GitHub
parent 9b63151b14
commit f04992fab5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 57 additions and 45 deletions

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.DataProtection.Abstractions.netstandard2.0.cs" />

View File

@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.DataProtection
// because we don't want the code provider.CreateProtector() [parameterless] to inadvertently compile.
// The actual signature for this method forces at least one purpose to be provided at the call site.
IDataProtector protector = provider.CreateProtector(purpose);
IDataProtector? protector = provider.CreateProtector(purpose);
if (subPurposes != null && subPurposes.Length > 0)
{
protector = protector?.CreateProtector((IEnumerable<string>)subPurposes);
@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.DataProtection
// We have our own implementation of GetRequiredService<T> since we don't want to
// take a dependency on DependencyInjection.Interfaces.
IDataProtectionProvider provider = (IDataProtectionProvider)services.GetService(typeof(IDataProtectionProvider));
var provider = (IDataProtectionProvider?)services.GetService(typeof(IDataProtectionProvider));
if (provider == null)
{
throw new InvalidOperationException(Resources.FormatDataProtectionExtensions_NoService(typeof(IDataProtectionProvider).FullName));

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.DataProtection
{
internal static class Error
{
public static CryptographicException CryptCommon_GenericError(Exception inner = null)
public static CryptographicException CryptCommon_GenericError(Exception? inner = null)
{
return new CryptographicException(Resources.CryptCommon_GenericError, inner);
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>ASP.NET Core data protection abstractions.
@ -9,6 +9,7 @@ Microsoft.AspNetCore.DataProtection.IDataProtector</Description>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;dataprotection</PackageTags>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.Cryptography.Internal.netstandard2.0.cs" />

View File

@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Cryptography
{
// This isn't a typical Debug.Assert; the check is always performed, even in retail builds.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Assert(bool condition, string message)
public static void Assert([DoesNotReturnIf(false)] bool condition, string message)
{
if (!condition)
{

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Infrastructure for ASP.NET Core cryptographic packages. Applications and libraries should not reference this package directly.</Description>
@ -8,6 +8,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;dataprotection</PackageTags>
<Nullable>annotations</Nullable>
</PropertyGroup>
</Project>

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.Cryptography.KeyDerivation.netstandard2.0.cs" />

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>ASP.NET Core utilities for key derivation.</Description>
@ -7,6 +7,8 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;dataprotection</PackageTags>
<Nullable>enable</Nullable>
<Nullable Condition="'$(TargetFramework)' == 'netstandard2.0'">annotations</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.DataProtection.netstandard2.0.cs" />

View File

@ -9,6 +9,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;dataprotection</PackageTags>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
@ -16,11 +16,11 @@ namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
/// <summary>
/// The friendly name of the <see cref="DataProtectionKey"/>.
/// </summary>
public string FriendlyName { get; set; }
public string? FriendlyName { get; set; }
/// <summary>
/// The XML representation of the <see cref="DataProtectionKey"/>.
/// </summary>
public string Xml { get; set; }
public string? Xml { get; set; }
}
}

View File

@ -40,13 +40,25 @@ namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
/// <inheritdoc />
public virtual IReadOnlyCollection<XElement> GetAllElements()
{
using (var scope = _services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<TContext>();
// forces complete enumeration
return GetAllElementsCore().ToList().AsReadOnly();
// Put logger in a local such that `this` isn't captured.
var logger = _logger;
return context.DataProtectionKeys.AsNoTracking().Select(key => TryParseKeyXml(key.Xml, logger)).ToList().AsReadOnly();
IEnumerable<XElement> GetAllElementsCore()
{
using (var scope = _services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<TContext>();
foreach (var key in context.DataProtectionKeys.AsNoTracking())
{
_logger.ReadingXmlFromKey(key.FriendlyName!, key.Xml);
if (!string.IsNullOrEmpty(key.Xml))
{
yield return XElement.Parse(key.Xml);
}
}
}
}
}
@ -67,18 +79,5 @@ namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
context.SaveChanges();
}
}
private static XElement TryParseKeyXml(string xml, ILogger logger)
{
try
{
return XElement.Parse(xml);
}
catch (Exception e)
{
logger?.LogExceptionWhileParsingKeyXml(xml, e);
return null;
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@ -7,23 +7,23 @@ namespace Microsoft.Extensions.Logging
{
internal static class LoggingExtensions
{
private static readonly Action<ILogger, string, Exception> _anExceptionOccurredWhileParsingKeyXml;
private static readonly Action<ILogger, string, string, Exception> _savingKeyToDbContext;
private static readonly Action<ILogger, string?, string?, Exception?> _readingXmlFromKey;
private static readonly Action<ILogger, string, string, Exception?> _savingKeyToDbContext;
static LoggingExtensions()
{
_anExceptionOccurredWhileParsingKeyXml = LoggerMessage.Define<string>(
eventId: new EventId(1, "ExceptionOccurredWhileParsingKeyXml"),
logLevel: LogLevel.Warning,
formatString: "An exception occurred while parsing the key xml '{Xml}'.");
_readingXmlFromKey = LoggerMessage.Define<string?, string?>(
eventId: new EventId(1, "ReadKeyFromElement"),
logLevel: LogLevel.Debug,
formatString: "Reading data with key '{FriendlyName}', value '{Value}'.");
_savingKeyToDbContext = LoggerMessage.Define<string, string>(
eventId: new EventId(2, "SavingKeyToDbContext"),
logLevel: LogLevel.Debug,
formatString: "Saving key '{FriendlyName}' to '{DbContext}'.");
}
public static void LogExceptionWhileParsingKeyXml(this ILogger logger, string keyXml, Exception exception)
=> _anExceptionOccurredWhileParsingKeyXml(logger, keyXml, exception);
public static void ReadingXmlFromKey(this ILogger logger, string? friendlyName, string? keyXml)
=> _readingXmlFromKey(logger, friendlyName, keyXml, null);
public static void LogSavingKeyToDbContext(this ILogger logger, string friendlyName, string contextName)
=> _savingKeyToDbContext(logger, friendlyName, contextName, null);

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Support for storing keys using Entity Framework Core.</Description>
@ -7,6 +7,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;dataprotection;entityframeworkcore</PackageTags>
<IsPackable>true</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.DataProtection.Extensions.netstandard2.0.cs" />

View File

@ -151,9 +151,9 @@ namespace Microsoft.AspNetCore.DataProtection
}
internal static IDataProtectionProvider CreateProvider(
DirectoryInfo keyDirectory,
DirectoryInfo? keyDirectory,
Action<IDataProtectionBuilder> setupAction,
X509Certificate2 certificate)
X509Certificate2? certificate)
{
// build the service collection
var serviceCollection = new ServiceCollection();

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Additional APIs for ASP.NET Core data protection.</Description>
@ -7,6 +7,7 @@
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;dataprotection</PackageTags>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.DataProtection
private const string MyPurposeString = "Microsoft.AspNetCore.DataProtection.TimeLimitedDataProtector.v1";
private readonly IDataProtector _innerProtector;
private IDataProtector _innerProtectorWithTimeLimitedPurpose; // created on-demand
private IDataProtector? _innerProtectorWithTimeLimitedPurpose; // created on-demand
public TimeLimitedDataProtector(IDataProtector innerProtector)
{

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Support for storing data protection keys in Redis.</Description>
@ -7,6 +7,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;dataprotection;redis</PackageTags>
<IsPackable>true</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
#if NETCOREAPP
using System.Buffers;