Make ILoggerFactory an optional service on any DI-injected services

This commit is contained in:
Nate McMaster 2017-06-13 00:00:47 -07:00
parent abf05e2856
commit 5d1a523682
33 changed files with 238 additions and 236 deletions

View File

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\dependencies.props" /> <Import Project="..\..\build\dependencies.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<OutputType>exe</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace AzureBlob namespace AzureBlob
{ {
@ -24,21 +25,19 @@ namespace AzureBlob
container.CreateIfNotExistsAsync().GetAwaiter().GetResult(); container.CreateIfNotExistsAsync().GetAwaiter().GetResult();
// Configure // Configure
using (var services = new ServiceCollection()
.AddLogging(o => o.AddConsole().SetMinimumLevel(LogLevel.Debug))
.AddDataProtection()
.PersistKeysToAzureBlobStorage(container, "keys.xml")
.Services
.BuildServiceProvider())
{
// Run a sample payload
var serviceCollection = new ServiceCollection(); var protector = services.GetDataProtector("sample-purpose");
serviceCollection.AddLogging(); var protectedData = protector.Protect("Hello world!");
serviceCollection.AddDataProtection() Console.WriteLine(protectedData);
.PersistKeysToAzureBlobStorage(container, "keys.xml"); }
var services = serviceCollection.BuildServiceProvider();
var loggerFactory = services.GetService<LoggerFactory>();
loggerFactory.AddConsole();
// Run a sample payload
var protector = services.GetDataProtector("sample-purpose");
var protectedData = protector.Protect("Hello world!");
Console.WriteLine(protectedData);
} }
} }
} }

View File

@ -1,22 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:2041/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"AzureBlob": {
"commandName": "Project"
}
}
}

View File

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\dependencies.props" /> <Import Project="..\..\build\dependencies.props" />
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks> <TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
<OutputType>exe</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -14,25 +14,23 @@ namespace CustomEncryptorSample
public static void Main(string[] args) public static void Main(string[] args)
{ {
var keysFolder = Path.Combine(Directory.GetCurrentDirectory(), "temp-keys"); var keysFolder = Path.Combine(Directory.GetCurrentDirectory(), "temp-keys");
var serviceCollection = new ServiceCollection(); using (var services = new ServiceCollection()
serviceCollection.AddLogging(); .AddLogging(o => o.AddConsole().SetMinimumLevel(LogLevel.Debug))
serviceCollection.AddDataProtection() .AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(keysFolder)) .PersistKeysToFileSystem(new DirectoryInfo(keysFolder))
.UseXmlEncryptor(s => new CustomXmlEncryptor(s)); .UseXmlEncryptor(s => new CustomXmlEncryptor(s))
.Services.BuildServiceProvider())
{
var protector = services.GetDataProtector("SamplePurpose");
var services = serviceCollection.BuildServiceProvider(); // protect the payload
var loggerFactory = services.GetRequiredService<LoggerFactory>(); var protectedPayload = protector.Protect("Hello World!");
loggerFactory.AddConsole(); Console.WriteLine($"Protect returned: {protectedPayload}");
var protector = services.GetDataProtector("SamplePurpose"); // unprotect the payload
var unprotectedPayload = protector.Unprotect(protectedPayload);
// protect the payload Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
var protectedPayload = protector.Protect("Hello World!"); }
Console.WriteLine($"Protect returned: {protectedPayload}");
// unprotect the payload
var unprotectedPayload = protector.Unprotect(protectedPayload);
Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
} }
} }
} }

View File

@ -1,22 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:1398/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"CustomEncryptorSample": {
"commandName": "Project"
}
}
}

View File

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\dependencies.props" /> <Import Project="..\..\build\dependencies.props" />
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks> <TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
<OutputType>exe</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -16,7 +16,8 @@ namespace KeyManagementSample
{ {
var keysFolder = Path.Combine(Directory.GetCurrentDirectory(), "temp-keys"); var keysFolder = Path.Combine(Directory.GetCurrentDirectory(), "temp-keys");
var serviceCollection = new ServiceCollection(); var serviceCollection = new ServiceCollection();
var builder = serviceCollection.AddDataProtection() var builder = serviceCollection
.AddDataProtection()
// point at a specific folder and use DPAPI to encrypt keys // point at a specific folder and use DPAPI to encrypt keys
.PersistKeysToFileSystem(new DirectoryInfo(keysFolder)); .PersistKeysToFileSystem(new DirectoryInfo(keysFolder));
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@ -24,40 +25,41 @@ namespace KeyManagementSample
builder.ProtectKeysWithDpapi(); builder.ProtectKeysWithDpapi();
} }
var services = serviceCollection.BuildServiceProvider(); using (var services = serviceCollection.BuildServiceProvider())
// perform a protect operation to force the system to put at least
// one key in the key ring
services.GetDataProtector("Sample.KeyManager.v1").Protect("payload");
Console.WriteLine("Performed a protect operation.");
// get a reference to the key manager
var keyManager = services.GetService<IKeyManager>();
// list all keys in the key ring
var allKeys = keyManager.GetAllKeys();
Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
foreach (var key in allKeys)
{ {
Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}"); // perform a protect operation to force the system to put at least
} // one key in the key ring
services.GetDataProtector("Sample.KeyManager.v1").Protect("payload");
Console.WriteLine("Performed a protect operation.");
// revoke all keys in the key ring // get a reference to the key manager
keyManager.RevokeAllKeys(DateTimeOffset.Now, reason: "Revocation reason here."); var keyManager = services.GetService<IKeyManager>();
Console.WriteLine("Revoked all existing keys.");
// add a new key to the key ring with immediate activation and a 1-month expiration // list all keys in the key ring
keyManager.CreateNewKey( var allKeys = keyManager.GetAllKeys();
activationDate: DateTimeOffset.Now, Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
expirationDate: DateTimeOffset.Now.AddMonths(1)); foreach (var key in allKeys)
Console.WriteLine("Added a new key."); {
Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}");
}
// list all keys in the key ring // revoke all keys in the key ring
allKeys = keyManager.GetAllKeys(); keyManager.RevokeAllKeys(DateTimeOffset.Now, reason: "Revocation reason here.");
Console.WriteLine($"The key ring contains {allKeys.Count} key(s)."); Console.WriteLine("Revoked all existing keys.");
foreach (var key in allKeys)
{ // add a new key to the key ring with immediate activation and a 1-month expiration
Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}"); keyManager.CreateNewKey(
activationDate: DateTimeOffset.Now,
expirationDate: DateTimeOffset.Now.AddMonths(1));
Console.WriteLine("Added a new key.");
// list all keys in the key ring
allKeys = keyManager.GetAllKeys();
Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
foreach (var key in allKeys)
{
Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}");
}
} }
} }
} }

View File

@ -1,22 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:1396/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"KeyManagementSample": {
"commandName": "Project"
}
}
}

View File

@ -17,19 +17,18 @@ namespace Redis
var redis = ConnectionMultiplexer.Connect("localhost:6379"); var redis = ConnectionMultiplexer.Connect("localhost:6379");
// Configure // Configure
var serviceCollection = new ServiceCollection(); using (var services = new ServiceCollection()
serviceCollection.AddLogging(); .AddLogging(o => o.AddConsole().SetMinimumLevel(LogLevel.Debug))
serviceCollection.AddDataProtection() .AddDataProtection()
.PersistKeysToRedis(redis, "DataProtection-Keys"); .PersistKeysToRedis(redis, "DataProtection-Keys")
.Services
var services = serviceCollection.BuildServiceProvider(); .BuildServiceProvider())
var loggerFactory = services.GetService<LoggerFactory>(); {
loggerFactory.AddConsole(); // Run a sample payload
var protector = services.GetDataProtector("sample-purpose");
// Run a sample payload var protectedData = protector.Protect("Hello world!");
var protector = services.GetDataProtector("sample-purpose"); Console.WriteLine(protectedData);
var protectedData = protector.Protect("Hello world!"); }
Console.WriteLine(protectedData);
} }
} }
} }

View File

@ -1,22 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:2042/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Redis": {
"commandName": "Project"
}
}
}

View File

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\dependencies.props" /> <Import Project="..\..\build\dependencies.props" />
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks> <TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
<OutputType>exe</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Security.Cryptography; using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography; using Microsoft.AspNetCore.Cryptography;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel
{ {
@ -42,7 +43,7 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
void IInternalAlgorithmConfiguration.Validate() void IInternalAlgorithmConfiguration.Validate()
{ {
var factory = new AuthenticatedEncryptorFactory(DataProtectionProviderFactory.GetDefaultLoggerFactory()); var factory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
// Run a sample payload through an encrypt -> decrypt operation to make sure data round-trips properly. // Run a sample payload through an encrypt -> decrypt operation to make sure data round-trips properly.
var encryptor = factory.CreateAuthenticatedEncryptorInstance(Secret.Random(512 / 8), this); var encryptor = factory.CreateAuthenticatedEncryptorInstance(Secret.Random(512 / 8), this);
try try

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Cryptography; using Microsoft.AspNetCore.Cryptography;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel
{ {
@ -88,7 +89,7 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
/// </summary> /// </summary>
void IInternalAlgorithmConfiguration.Validate() void IInternalAlgorithmConfiguration.Validate()
{ {
var factory = new CngCbcAuthenticatedEncryptorFactory(DataProtectionProviderFactory.GetDefaultLoggerFactory()); var factory = new CngCbcAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
// Run a sample payload through an encrypt -> decrypt operation to make sure data round-trips properly. // Run a sample payload through an encrypt -> decrypt operation to make sure data round-trips properly.
using (var encryptor = factory.CreateAuthenticatedEncryptorInstance(Secret.Random(512 / 8), this)) using (var encryptor = factory.CreateAuthenticatedEncryptorInstance(Secret.Random(512 / 8), this))
{ {

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Cryptography; using Microsoft.AspNetCore.Cryptography;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel
{ {
@ -64,7 +65,7 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
/// </summary> /// </summary>
void IInternalAlgorithmConfiguration.Validate() void IInternalAlgorithmConfiguration.Validate()
{ {
var factory = new CngGcmAuthenticatedEncryptorFactory(DataProtectionProviderFactory.GetDefaultLoggerFactory()); var factory = new CngGcmAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
// Run a sample payload through an encrypt -> decrypt operation to make sure data round-trips properly. // Run a sample payload through an encrypt -> decrypt operation to make sure data round-trips properly.
using (var encryptor = factory.CreateAuthenticatedEncryptorInstance(Secret.Random(512 / 8), this)) using (var encryptor = factory.CreateAuthenticatedEncryptorInstance(Secret.Random(512 / 8), this))
{ {

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Security.Cryptography; using System.Security.Cryptography;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel
{ {
@ -66,7 +67,7 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
/// </summary> /// </summary>
void IInternalAlgorithmConfiguration.Validate() void IInternalAlgorithmConfiguration.Validate()
{ {
var factory = new ManagedAuthenticatedEncryptorFactory(DataProtectionProviderFactory.GetDefaultLoggerFactory()); var factory = new ManagedAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
// Run a sample payload through an encrypt -> decrypt operation to make sure data round-trips properly. // Run a sample payload through an encrypt -> decrypt operation to make sure data round-trips properly.
using (var encryptor = factory.CreateAuthenticatedEncryptorInstance(Secret.Random(512 / 8), this)) using (var encryptor = factory.CreateAuthenticatedEncryptorInstance(Secret.Random(512 / 8), this))
{ {

View File

@ -14,6 +14,7 @@ using Microsoft.AspNetCore.DataProtection.XmlEncryption;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Win32; using Microsoft.Win32;
@ -206,7 +207,7 @@ namespace Microsoft.AspNetCore.DataProtection
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services => builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{ {
var loggerFactory = services.GetRequiredService<ILoggerFactory>(); var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
return new ConfigureOptions<KeyManagementOptions>(options => return new ConfigureOptions<KeyManagementOptions>(options =>
{ {
options.XmlRepository = new FileSystemXmlRepository(directory, loggerFactory); options.XmlRepository = new FileSystemXmlRepository(directory, loggerFactory);
@ -236,7 +237,7 @@ namespace Microsoft.AspNetCore.DataProtection
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services => builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{ {
var loggerFactory = services.GetRequiredService<ILoggerFactory>(); var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
return new ConfigureOptions<KeyManagementOptions>(options => return new ConfigureOptions<KeyManagementOptions>(options =>
{ {
options.XmlRepository = new RegistryXmlRepository(registryKey, loggerFactory); options.XmlRepository = new RegistryXmlRepository(registryKey, loggerFactory);
@ -266,7 +267,7 @@ namespace Microsoft.AspNetCore.DataProtection
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services => builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{ {
var loggerFactory = services.GetRequiredService<ILoggerFactory>(); var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
return new ConfigureOptions<KeyManagementOptions>(options => return new ConfigureOptions<KeyManagementOptions>(options =>
{ {
options.XmlEncryptor = new CertificateXmlEncryptor(certificate, loggerFactory); options.XmlEncryptor = new CertificateXmlEncryptor(certificate, loggerFactory);
@ -306,7 +307,7 @@ namespace Microsoft.AspNetCore.DataProtection
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services => builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{ {
var loggerFactory = services.GetRequiredService<ILoggerFactory>(); var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
var certificateResolver = services.GetRequiredService<ICertificateResolver>(); var certificateResolver = services.GetRequiredService<ICertificateResolver>();
return new ConfigureOptions<KeyManagementOptions>(options => return new ConfigureOptions<KeyManagementOptions>(options =>
{ {
@ -357,7 +358,7 @@ namespace Microsoft.AspNetCore.DataProtection
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services => builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{ {
var loggerFactory = services.GetRequiredService<ILoggerFactory>(); var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
return new ConfigureOptions<KeyManagementOptions>(options => return new ConfigureOptions<KeyManagementOptions>(options =>
{ {
CryptoUtil.AssertPlatformIsWindows(); CryptoUtil.AssertPlatformIsWindows();
@ -419,7 +420,7 @@ namespace Microsoft.AspNetCore.DataProtection
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services => builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{ {
var loggerFactory = services.GetRequiredService<ILoggerFactory>(); var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
return new ConfigureOptions<KeyManagementOptions>(options => return new ConfigureOptions<KeyManagementOptions>(options =>
{ {
CryptoUtil.AssertPlatformIsWindows8OrLater(); CryptoUtil.AssertPlatformIsWindows8OrLater();

View File

@ -1,16 +0,0 @@
// 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 Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.DataProtection
{
internal static class DataProtectionProviderFactory
{
public static ILoggerFactory GetDefaultLoggerFactory()
{
return NullLoggerFactory.Instance;
}
}
}

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.DataProtection.XmlEncryption;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
@ -64,8 +65,6 @@ namespace Microsoft.Extensions.DependencyInjection
private static void AddDataProtectionServices(IServiceCollection services) private static void AddDataProtectionServices(IServiceCollection services)
{ {
services.TryAddSingleton<ILoggerFactory>(DataProtectionProviderFactory.GetDefaultLoggerFactory());
if (OSVersionUtil.IsWindows()) if (OSVersionUtil.IsWindows())
{ {
services.TryAddSingleton<RegistryPolicyResolver>(); services.TryAddSingleton<RegistryPolicyResolver>();
@ -88,10 +87,9 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
var dpOptions = s.GetRequiredService<IOptions<DataProtectionOptions>>(); var dpOptions = s.GetRequiredService<IOptions<DataProtectionOptions>>();
var keyRingProvider = s.GetRequiredService<IKeyRingProvider>(); var keyRingProvider = s.GetRequiredService<IKeyRingProvider>();
var loggerFactory = s.GetRequiredService<ILoggerFactory>(); var loggerFactory = s.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
IDataProtectionProvider dataProtectionProvider = null; IDataProtectionProvider dataProtectionProvider = new KeyRingBasedDataProtectionProvider(keyRingProvider, loggerFactory);
dataProtectionProvider = new KeyRingBasedDataProtectionProvider(keyRingProvider, loggerFactory);
// Link the provider to the supplied discriminator // Link the provider to the supplied discriminator
if (!string.IsNullOrEmpty(dpOptions.Value.ApplicationDiscriminator)) if (!string.IsNullOrEmpty(dpOptions.Value.ApplicationDiscriminator))

View File

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationM
using Microsoft.AspNetCore.DataProtection.KeyManagement; using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal; using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.DataProtection namespace Microsoft.AspNetCore.DataProtection
{ {
@ -24,11 +25,23 @@ namespace Microsoft.AspNetCore.DataProtection
private readonly KeyRingBasedDataProtectionProvider _dataProtectionProvider; private readonly KeyRingBasedDataProtectionProvider _dataProtectionProvider;
/// <summary> /// <summary>
/// Creates an ephemeral <see cref="IDataProtectionProvider"/>, optionally providing /// Creates an ephemeral <see cref="IDataProtectionProvider"/>.
/// services (such as logging) for consumption by the provider.
/// </summary> /// </summary>
public EphemeralDataProtectionProvider()
: this (NullLoggerFactory.Instance)
{ }
/// <summary>
/// Creates an ephemeral <see cref="IDataProtectionProvider"/> with logging.
/// </summary>
/// <param name="loggerFactory">The <see cref="ILoggerFactory" />.</param>
public EphemeralDataProtectionProvider(ILoggerFactory loggerFactory) public EphemeralDataProtectionProvider(ILoggerFactory loggerFactory)
{ {
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
IKeyRingProvider keyringProvider; IKeyRingProvider keyringProvider;
if (OSVersionUtil.IsWindows()) if (OSVersionUtil.IsWindows())
{ {

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal; using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.DataProtection.Internal namespace Microsoft.AspNetCore.DataProtection.Internal
{ {
@ -14,6 +15,10 @@ namespace Microsoft.AspNetCore.DataProtection.Internal
private readonly IKeyRingProvider _keyRingProvider; private readonly IKeyRingProvider _keyRingProvider;
private readonly ILogger<DataProtectionStartupFilter> _logger; private readonly ILogger<DataProtectionStartupFilter> _logger;
public DataProtectionStartupFilter(IKeyRingProvider keyRingProvider)
: this(keyRingProvider, NullLoggerFactory.Instance)
{ }
public DataProtectionStartupFilter(IKeyRingProvider keyRingProvider, ILoggerFactory loggerFactory) public DataProtectionStartupFilter(IKeyRingProvider keyRingProvider, ILoggerFactory loggerFactory)
{ {
_keyRingProvider = keyRingProvider; _keyRingProvider = keyRingProvider;

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.DataProtection.KeyManagement; using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.DataProtection.Internal namespace Microsoft.AspNetCore.DataProtection.Internal
@ -15,7 +16,18 @@ namespace Microsoft.AspNetCore.DataProtection.Internal
private readonly RegistryPolicyResolver _registryPolicyResolver; private readonly RegistryPolicyResolver _registryPolicyResolver;
private readonly ILoggerFactory _loggerFactory; private readonly ILoggerFactory _loggerFactory;
public KeyManagementOptionsSetup(ILoggerFactory loggerFactory) : this(loggerFactory, registryPolicyResolver: null) public KeyManagementOptionsSetup()
: this(NullLoggerFactory.Instance, registryPolicyResolver: null)
{
}
public KeyManagementOptionsSetup(ILoggerFactory loggerFactory)
: this(loggerFactory, registryPolicyResolver: null)
{
}
public KeyManagementOptionsSetup(RegistryPolicyResolver registryPolicyResolver)
: this(NullLoggerFactory.Instance, registryPolicyResolver)
{ {
} }

View File

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Cryptography;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal; using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.DataProtection.KeyManagement namespace Microsoft.AspNetCore.DataProtection.KeyManagement
@ -40,6 +41,10 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
/// </remarks> /// </remarks>
private readonly TimeSpan _maxServerToServerClockSkew; private readonly TimeSpan _maxServerToServerClockSkew;
public DefaultKeyResolver(IOptions<KeyManagementOptions> keyManagementOptions)
: this(keyManagementOptions, NullLoggerFactory.Instance)
{ }
public DefaultKeyResolver(IOptions<KeyManagementOptions> keyManagementOptions, ILoggerFactory loggerFactory) public DefaultKeyResolver(IOptions<KeyManagementOptions> keyManagementOptions, ILoggerFactory loggerFactory)
{ {
_keyPropagationWindow = keyManagementOptions.Value.KeyPropagationWindow; _keyPropagationWindow = keyManagementOptions.Value.KeyPropagationWindow;

View File

@ -8,6 +8,7 @@ using System.Threading;
using Microsoft.AspNetCore.Cryptography; using Microsoft.AspNetCore.Cryptography;
using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal; using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.DataProtection.KeyManagement namespace Microsoft.AspNetCore.DataProtection.KeyManagement
@ -16,7 +17,6 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
private CacheableKeyRing _cacheableKeyRing; private CacheableKeyRing _cacheableKeyRing;
private readonly object _cacheableKeyRingLockObj = new object(); private readonly object _cacheableKeyRingLockObj = new object();
private readonly ICacheableKeyRingProvider _cacheableKeyRingProvider;
private readonly IDefaultKeyResolver _defaultKeyResolver; private readonly IDefaultKeyResolver _defaultKeyResolver;
private readonly KeyManagementOptions _keyManagementOptions; private readonly KeyManagementOptions _keyManagementOptions;
private readonly IKeyManager _keyManager; private readonly IKeyManager _keyManager;
@ -25,31 +25,31 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public KeyRingProvider( public KeyRingProvider(
IKeyManager keyManager, IKeyManager keyManager,
IOptions<KeyManagementOptions> keyManagementOptions, IOptions<KeyManagementOptions> keyManagementOptions,
IDefaultKeyResolver defaultKeyResolver, IDefaultKeyResolver defaultKeyResolver)
ILoggerFactory loggerFactory)
: this( : this(
keyManager, keyManager,
keyManagementOptions, keyManagementOptions,
cacheableKeyRingProvider: null, defaultKeyResolver,
defaultKeyResolver: defaultKeyResolver, NullLoggerFactory.Instance)
loggerFactory: loggerFactory)
{ {
} }
public KeyRingProvider( public KeyRingProvider(
IKeyManager keyManager, IKeyManager keyManager,
IOptions<KeyManagementOptions> keyManagementOptions, IOptions<KeyManagementOptions> keyManagementOptions,
ICacheableKeyRingProvider cacheableKeyRingProvider,
IDefaultKeyResolver defaultKeyResolver, IDefaultKeyResolver defaultKeyResolver,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
{ {
_keyManagementOptions = new KeyManagementOptions(keyManagementOptions.Value); // clone so new instance is immutable _keyManagementOptions = new KeyManagementOptions(keyManagementOptions.Value); // clone so new instance is immutable
_keyManager = keyManager; _keyManager = keyManager;
_cacheableKeyRingProvider = cacheableKeyRingProvider ?? this; CacheableKeyRingProvider = this;
_defaultKeyResolver = defaultKeyResolver; _defaultKeyResolver = defaultKeyResolver;
_logger = loggerFactory.CreateLogger<KeyRingProvider>(); _logger = loggerFactory.CreateLogger<KeyRingProvider>();
} }
// for testing
internal ICacheableKeyRingProvider CacheableKeyRingProvider { get; set; }
private CacheableKeyRing CreateCacheableKeyRingCore(DateTimeOffset now, IKey keyJustAdded) private CacheableKeyRing CreateCacheableKeyRingCore(DateTimeOffset now, IKey keyJustAdded)
{ {
// Refresh the list of all keys // Refresh the list of all keys
@ -183,7 +183,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
try try
{ {
newCacheableKeyRing = _cacheableKeyRingProvider.GetCacheableKeyRing(utcNow); newCacheableKeyRing = CacheableKeyRingProvider.GetCacheableKeyRing(utcNow);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -20,6 +20,7 @@ using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal;
using Microsoft.AspNetCore.DataProtection.Repositories; using Microsoft.AspNetCore.DataProtection.Repositories;
using Microsoft.AspNetCore.DataProtection.XmlEncryption; using Microsoft.AspNetCore.DataProtection.XmlEncryption;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Win32; using Microsoft.Win32;
@ -55,6 +56,15 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
private CancellationTokenSource _cacheExpirationTokenSource; private CancellationTokenSource _cacheExpirationTokenSource;
/// <summary>
/// Creates an <see cref="XmlKeyManager"/>.
/// </summary>
/// <param name="keyManagementOptions">The <see cref="IOptions{KeyManagementOptions}"/> instance that provides the configuration.</param>
/// <param name="activator">The <see cref="IActivator"/>.</param>
public XmlKeyManager(IOptions<KeyManagementOptions> keyManagementOptions, IActivator activator)
: this (keyManagementOptions, activator, NullLoggerFactory.Instance)
{ }
/// <summary> /// <summary>
/// Creates an <see cref="XmlKeyManager"/>. /// Creates an <see cref="XmlKeyManager"/>.
/// </summary> /// </summary>
@ -63,7 +73,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param> /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public XmlKeyManager(IOptions<KeyManagementOptions> keyManagementOptions, IActivator activator, ILoggerFactory loggerFactory) public XmlKeyManager(IOptions<KeyManagementOptions> keyManagementOptions, IActivator activator, ILoggerFactory loggerFactory)
{ {
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
_logger = _loggerFactory.CreateLogger<XmlKeyManager>(); _logger = _loggerFactory.CreateLogger<XmlKeyManager>();
KeyRepository = keyManagementOptions.Value.XmlRepository; KeyRepository = keyManagementOptions.Value.XmlRepository;

View File

@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Cryptography;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.DataProtection.Internal; using Microsoft.AspNetCore.DataProtection.Internal;
using Microsoft.AspNetCore.DataProtection.KeyManagement; using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.Logging;
using Microsoft.Win32; using Microsoft.Win32;
namespace Microsoft.AspNetCore.DataProtection namespace Microsoft.AspNetCore.DataProtection
@ -22,20 +21,17 @@ namespace Microsoft.AspNetCore.DataProtection
{ {
private readonly Func<RegistryKey> _getPolicyRegKey; private readonly Func<RegistryKey> _getPolicyRegKey;
private readonly IActivator _activator; private readonly IActivator _activator;
private readonly ILoggerFactory _loggerFactory;
public RegistryPolicyResolver(IActivator activator, ILoggerFactory loggerFactory) public RegistryPolicyResolver(IActivator activator)
{ {
_getPolicyRegKey = () => Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\DotNetPackages\Microsoft.AspNetCore.DataProtection"); _getPolicyRegKey = () => Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\DotNetPackages\Microsoft.AspNetCore.DataProtection");
_activator = activator; _activator = activator;
_loggerFactory = loggerFactory;
} }
internal RegistryPolicyResolver(RegistryKey policyRegKey, IActivator activator, ILoggerFactory loggerFactory) internal RegistryPolicyResolver(RegistryKey policyRegKey, IActivator activator)
{ {
_getPolicyRegKey = () => policyRegKey; _getPolicyRegKey = () => policyRegKey;
_activator = activator; _activator = activator;
_loggerFactory = loggerFactory;
} }
// populates an options object from values stored in the registry // populates an options object from values stored in the registry
@ -95,10 +91,8 @@ namespace Microsoft.AspNetCore.DataProtection
/// <summary> /// <summary>
/// Returns a <see cref="RegistryPolicy"/> from the default registry location. /// Returns a <see cref="RegistryPolicy"/> from the default registry location.
/// </summary> /// </summary>
public static RegistryPolicy ResolveDefaultPolicy(IActivator activator, ILoggerFactory loggerFactory) public static RegistryPolicy ResolveDefaultPolicy(IActivator activator)
{ => new RegistryPolicyResolver(activator).ResolvePolicy();
return new RegistryPolicyResolver(activator, loggerFactory).ResolvePolicy();
}
internal RegistryPolicy ResolvePolicy() internal RegistryPolicy ResolvePolicy()
{ {

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.DataProtection namespace Microsoft.AspNetCore.DataProtection
{ {
@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.DataProtection
private static readonly Regex _versionPattern = new Regex(@",\s?Version=[0-9]+(\.[0-9]+){0,3}", RegexOptions.Compiled, TimeSpan.FromSeconds(2)); private static readonly Regex _versionPattern = new Regex(@",\s?Version=[0-9]+(\.[0-9]+){0,3}", RegexOptions.Compiled, TimeSpan.FromSeconds(2));
public TypeForwardingActivator(IServiceProvider services) public TypeForwardingActivator(IServiceProvider services)
: this(services, DataProtectionProviderFactory.GetDefaultLoggerFactory()) : this(services, NullLoggerFactory.Instance)
{ {
} }

View File

@ -79,11 +79,6 @@
"MemberId": "public .ctor(Microsoft.Win32.RegistryKey registryKey, System.IServiceProvider services)", "MemberId": "public .ctor(Microsoft.Win32.RegistryKey registryKey, System.IServiceProvider services)",
"Kind": "Removal" "Kind": "Removal"
}, },
{
"TypeId": "public sealed class Microsoft.AspNetCore.DataProtection.EphemeralDataProtectionProvider : Microsoft.AspNetCore.DataProtection.IDataProtectionProvider",
"MemberId": "public .ctor()",
"Kind": "Removal"
},
{ {
"TypeId": "public sealed class Microsoft.AspNetCore.DataProtection.EphemeralDataProtectionProvider : Microsoft.AspNetCore.DataProtection.IDataProtectionProvider", "TypeId": "public sealed class Microsoft.AspNetCore.DataProtection.EphemeralDataProtectionProvider : Microsoft.AspNetCore.DataProtection.IDataProtectionProvider",
"MemberId": "public .ctor(System.IServiceProvider services)", "MemberId": "public .ctor(System.IServiceProvider services)",
@ -244,4 +239,4 @@
"MemberId": "Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.IAuthenticatedEncryptor CreateEncryptor()", "MemberId": "Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.IAuthenticatedEncryptor CreateEncryptor()",
"Kind": "Addition" "Kind": "Addition"
} }
] ]

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.DataProtection
public void DifferentProvider_SamePurpose_DoesNotRoundTripData() public void DifferentProvider_SamePurpose_DoesNotRoundTripData()
{ {
// Arrange // Arrange
var dataProtector1 = new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("purpose"); var dataProtector1 = new EphemeralDataProtectionProvider().CreateProtector("purpose");
var dataProtector2 = new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("purpose"); var dataProtector2 = new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("purpose");
byte[] bytes = Encoding.UTF8.GetBytes("Hello there!"); byte[] bytes = Encoding.UTF8.GetBytes("Hello there!");

View File

@ -89,8 +89,7 @@ namespace Microsoft.AspNetCore.DataProtection.Internal
var policyResolver = new RegistryPolicyResolver( var policyResolver = new RegistryPolicyResolver(
registryKey, registryKey,
activator: SimpleActivator.DefaultWithoutServices, activator: SimpleActivator.DefaultWithoutServices);
loggerFactory: NullLoggerFactory.Instance);
var setup = new KeyManagementOptionsSetup(NullLoggerFactory.Instance, policyResolver); var setup = new KeyManagementOptionsSetup(NullLoggerFactory.Instance, policyResolver);

View File

@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
ShouldGenerateNewKey = false ShouldGenerateNewKey = false
}) })
}); });
// Act // Act
var cacheableKeyRing = keyRingProvider.GetCacheableKeyRing(now); var cacheableKeyRing = keyRingProvider.GetCacheableKeyRing(now);
@ -597,9 +597,11 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
return new KeyRingProvider( return new KeyRingProvider(
keyManager: null, keyManager: null,
keyManagementOptions: Options.Create(options), keyManagementOptions: Options.Create(options),
cacheableKeyRingProvider: cacheableKeyRingProvider,
defaultKeyResolver: null, defaultKeyResolver: null,
loggerFactory: NullLoggerFactory.Instance); loggerFactory: NullLoggerFactory.Instance)
{
CacheableKeyRingProvider = cacheableKeyRingProvider
};
} }
private static ICacheableKeyRingProvider CreateKeyRingProvider(IKeyManager keyManager, IDefaultKeyResolver defaultKeyResolver, KeyManagementOptions keyManagementOptions= null) private static ICacheableKeyRingProvider CreateKeyRingProvider(IKeyManager keyManager, IDefaultKeyResolver defaultKeyResolver, KeyManagementOptions keyManagementOptions= null)
@ -612,7 +614,6 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
return new KeyRingProvider( return new KeyRingProvider(
keyManager: keyManager, keyManager: keyManager,
keyManagementOptions: Options.Create(keyManagementOptions), keyManagementOptions: Options.Create(keyManagementOptions),
cacheableKeyRingProvider: null,
defaultKeyResolver: defaultKeyResolver, defaultKeyResolver: defaultKeyResolver,
loggerFactory: NullLoggerFactory.Instance); loggerFactory: NullLoggerFactory.Instance);
} }

View File

@ -251,8 +251,7 @@ namespace Microsoft.AspNetCore.DataProtection
var policyResolver = new RegistryPolicyResolver( var policyResolver = new RegistryPolicyResolver(
registryKey, registryKey,
activator: SimpleActivator.DefaultWithoutServices, activator: SimpleActivator.DefaultWithoutServices);
loggerFactory: NullLoggerFactory.Instance);
return policyResolver.ResolvePolicy(); return policyResolver.ResolvePolicy();
}); });

View File

@ -0,0 +1,67 @@
// 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;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Xunit;
namespace Microsoft.AspNetCore.DataProtection
{
public class ServiceCollectionTests
{
[Fact]
public void AddsOptions()
{
var services = new ServiceCollection()
.AddDataProtection()
.Services
.BuildServiceProvider();
Assert.NotNull(services.GetService<IOptions<DataProtectionOptions>>());
}
[Fact]
public void DoesNotOverrideLogging()
{
var services1 = new ServiceCollection()
.AddLogging()
.AddDataProtection()
.Services
.BuildServiceProvider();
var services2 = new ServiceCollection()
.AddDataProtection()
.Services
.AddLogging()
.BuildServiceProvider();
Assert.Equal(
services1.GetRequiredService<ILoggerFactory>().GetType(),
services2.GetRequiredService<ILoggerFactory>().GetType());
}
[Fact]
public void CanResolveAllRegisteredServices()
{
var serviceCollection = new ServiceCollection()
.AddDataProtection()
.Services;
var services = serviceCollection.BuildServiceProvider(validateScopes: true);
Assert.Null(services.GetService<ILoggerFactory>());
foreach (var descriptor in serviceCollection)
{
if (descriptor.ServiceType.Assembly.GetName().Name == "Microsoft.Extensions.Options")
{
// ignore any descriptors added by the call to .AddOptions()
continue;
}
Assert.NotNull(services.GetService(descriptor.ServiceType));
}
}
}
}