Add activator fallback to support rc1 keys
This commit is contained in:
parent
acb8732ffd
commit
47d3ffdddc
|
|
@ -2,7 +2,6 @@
|
||||||
// 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 System;
|
using System;
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.AspNetCore.Cryptography;
|
using Microsoft.AspNetCore.Cryptography;
|
||||||
using Microsoft.AspNetCore.DataProtection.Internal;
|
using Microsoft.AspNetCore.DataProtection.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -40,52 +39,5 @@ namespace Microsoft.AspNetCore.DataProtection
|
||||||
? (serviceProvider.GetService<IActivator>() ?? new SimpleActivator(serviceProvider))
|
? (serviceProvider.GetService<IActivator>() ?? new SimpleActivator(serviceProvider))
|
||||||
: SimpleActivator.DefaultWithoutServices;
|
: 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));
|
throw new ArgumentNullException(nameof(services));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
services.AddSingleton<IActivator, RC1ForwardingActivator>();
|
||||||
services.AddOptions();
|
services.AddOptions();
|
||||||
services.TryAdd(DataProtectionServices.GetDefaultServices());
|
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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue