Add activator fallback to support rc1 keys
This commit is contained in:
Родитель
acb8732ffd
Коммит
47d3ffdddc
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Cryptography;
|
||||
using Microsoft.AspNetCore.DataProtection.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
@ -40,52 +39,5 @@ namespace Microsoft.AspNetCore.DataProtection
|
|||
? (serviceProvider.GetService<IActivator>() ?? new SimpleActivator(serviceProvider))
|
||||
: SimpleActivator.DefaultWithoutServices;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A simplified default implementation of <see cref="IActivator"/> that understands
|
||||
/// how to call ctors which take <see cref="IServiceProvider"/>.
|
||||
/// </summary>
|
||||
private sealed class SimpleActivator : IActivator
|
||||
{
|
||||
/// <summary>
|
||||
/// A default <see cref="SimpleActivator"/> whose wrapped <see cref="IServiceProvider"/> is null.
|
||||
/// </summary>
|
||||
internal static readonly SimpleActivator DefaultWithoutServices = new SimpleActivator(null);
|
||||
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public SimpleActivator(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
public object CreateInstance(Type expectedBaseType, string implementationTypeName)
|
||||
{
|
||||
// Would the assignment even work?
|
||||
var implementationType = Type.GetType(implementationTypeName, throwOnError: true);
|
||||
expectedBaseType.AssertIsAssignableFrom(implementationType);
|
||||
|
||||
// If no IServiceProvider was specified, prefer .ctor() [if it exists]
|
||||
if (_services == null)
|
||||
{
|
||||
var ctorParameterless = implementationType.GetConstructor(Type.EmptyTypes);
|
||||
if (ctorParameterless != null)
|
||||
{
|
||||
return Activator.CreateInstance(implementationType);
|
||||
}
|
||||
}
|
||||
|
||||
// If an IServiceProvider was specified or if .ctor() doesn't exist, prefer .ctor(IServiceProvider) [if it exists]
|
||||
var ctorWhichTakesServiceProvider = implementationType.GetConstructor(new Type[] { typeof(IServiceProvider) });
|
||||
if (ctorWhichTakesServiceProvider != null)
|
||||
{
|
||||
return ctorWhichTakesServiceProvider.Invoke(new[] { _services });
|
||||
}
|
||||
|
||||
// Finally, prefer .ctor() as an ultimate fallback.
|
||||
// This will throw if the ctor cannot be called.
|
||||
return Activator.CreateInstance(implementationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
throw new ArgumentNullException(nameof(services));
|
||||
}
|
||||
|
||||
services.AddSingleton<IActivator, RC1ForwardingActivator>();
|
||||
services.AddOptions();
|
||||
services.TryAdd(DataProtectionServices.GetDefaultServices());
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// 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.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.DataProtection
|
||||
{
|
||||
internal class RC1ForwardingActivator: SimpleActivator
|
||||
{
|
||||
private const string From = "Microsoft.AspNet.DataProtection";
|
||||
private const string To = "Microsoft.AspNetCore.DataProtection";
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public RC1ForwardingActivator(IServiceProvider services) : this(services, null)
|
||||
{
|
||||
}
|
||||
|
||||
public RC1ForwardingActivator(IServiceProvider services, ILoggerFactory loggerFactory) : base(services)
|
||||
{
|
||||
_logger = loggerFactory?.CreateLogger(typeof(RC1ForwardingActivator));
|
||||
}
|
||||
|
||||
public override object CreateInstance(Type expectedBaseType, string implementationTypeName)
|
||||
{
|
||||
if (implementationTypeName.Contains(From))
|
||||
{
|
||||
var forwardedImplementationTypeName = implementationTypeName.Replace(From, To);
|
||||
var type = Type.GetType(forwardedImplementationTypeName, false);
|
||||
if (type != null)
|
||||
{
|
||||
_logger?.LogDebug("Forwarded activator type request from {FromType} to {ToType}",
|
||||
implementationTypeName,
|
||||
forwardedImplementationTypeName);
|
||||
|
||||
implementationTypeName = forwardedImplementationTypeName;
|
||||
}
|
||||
}
|
||||
return base.CreateInstance(expectedBaseType, implementationTypeName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// 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 System.Reflection;
|
||||
using Microsoft.AspNetCore.DataProtection.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.DataProtection
|
||||
{
|
||||
/// <summary>
|
||||
/// A simplified default implementation of <see cref="IActivator"/> that understands
|
||||
/// how to call ctors which take <see cref="IServiceProvider"/>.
|
||||
/// </summary>
|
||||
internal class SimpleActivator : IActivator
|
||||
{
|
||||
/// <summary>
|
||||
/// A default <see cref="SimpleActivator"/> whose wrapped <see cref="IServiceProvider"/> is null.
|
||||
/// </summary>
|
||||
internal static readonly SimpleActivator DefaultWithoutServices = new SimpleActivator(null);
|
||||
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public SimpleActivator(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
public virtual object CreateInstance(Type expectedBaseType, string implementationTypeName)
|
||||
{
|
||||
// Would the assignment even work?
|
||||
var implementationType = Type.GetType(implementationTypeName, throwOnError: true);
|
||||
expectedBaseType.AssertIsAssignableFrom(implementationType);
|
||||
|
||||
// If no IServiceProvider was specified, prefer .ctor() [if it exists]
|
||||
if (_services == null)
|
||||
{
|
||||
var ctorParameterless = implementationType.GetConstructor(Type.EmptyTypes);
|
||||
if (ctorParameterless != null)
|
||||
{
|
||||
return Activator.CreateInstance(implementationType);
|
||||
}
|
||||
}
|
||||
|
||||
// If an IServiceProvider was specified or if .ctor() doesn't exist, prefer .ctor(IServiceProvider) [if it exists]
|
||||
var ctorWhichTakesServiceProvider = implementationType.GetConstructor(new Type[] { typeof(IServiceProvider) });
|
||||
if (ctorWhichTakesServiceProvider != null)
|
||||
{
|
||||
return ctorWhichTakesServiceProvider.Invoke(new[] { _services });
|
||||
}
|
||||
|
||||
// Finally, prefer .ctor() as an ultimate fallback.
|
||||
// This will throw if the ctor cannot be called.
|
||||
return Activator.CreateInstance(implementationType);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.DataProtection
|
||||
{
|
||||
public class RC1ForwardingActivatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void CreateInstance_ForwardsToNewNamespaceIfExists()
|
||||
{
|
||||
// Arrange
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddDataProtection();
|
||||
var services = serviceCollection.BuildServiceProvider();
|
||||
var activator = services.GetActivator();
|
||||
|
||||
// Act
|
||||
var name = "Microsoft.AspNet.DataProtection.RC1ForwardingActivatorTests+ClassWithParameterlessCtor, Microsoft.AspNet.DataProtection.Test";
|
||||
var instance = activator.CreateInstance<object>(name);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<ClassWithParameterlessCtor>(instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateInstance_DoesNotForwardIfClassDoesNotExist()
|
||||
{
|
||||
// Arrange
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddDataProtection();
|
||||
var services = serviceCollection.BuildServiceProvider();
|
||||
var activator = services.GetActivator();
|
||||
|
||||
// Act & Assert
|
||||
var name = "Microsoft.AspNet.DataProtection.RC1ForwardingActivatorTests+NonExistentClassWithParameterlessCtor, Microsoft.AspNet.DataProtection.Test";
|
||||
var exception = Assert.ThrowsAny<Exception>(()=> activator.CreateInstance<object>(name));
|
||||
|
||||
Assert.Contains("Microsoft.AspNet.DataProtection.Test", exception.Message);
|
||||
}
|
||||
|
||||
private class ClassWithParameterlessCtor
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче