Просмотр исходного кода

Add activator fallback to support rc1 keys

Pavel Krymets 9 лет назад
Родитель
Сommit
47d3ffdddc

+ 0 - 48
src/Microsoft.AspNetCore.DataProtection/ActivatorExtensions.cs

@@ -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);
-            }
-        }
     }
 }

+ 1 - 0
src/Microsoft.AspNetCore.DataProtection/DataProtectionServiceCollectionExtensions.cs

@@ -24,6 +24,7 @@ namespace Microsoft.Extensions.DependencyInjection
                 throw new ArgumentNullException(nameof(services));
             }
 
+            services.AddSingleton<IActivator, RC1ForwardingActivator>();
             services.AddOptions();
             services.TryAdd(DataProtectionServices.GetDefaultServices());
 

+ 42 - 0
src/Microsoft.AspNetCore.DataProtection/RC1ForwardingActivator.cs

@@ -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);
+        }
+    }
+}

+ 56 - 0
src/Microsoft.AspNetCore.DataProtection/SimpleActivator.cs

@@ -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);
+        }
+    }
+}

+ 49 - 0
test/Microsoft.AspNetCore.DataProtection.Test/RC1ForwardingActivatorTests.cs

@@ -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
+        {
+        }
+    }
+}