| File: TypeForwardingActivator.cs | Web Access |
| Project: src\aspnetcore\src\DataProtection\DataProtection\src\Microsoft.AspNetCore.DataProtection.csproj (Microsoft.AspNetCore.DataProtection) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; namespace Microsoft.AspNetCore.DataProtection; #pragma warning disable CA1852 // Seal internal types internal class TypeForwardingActivator : SimpleActivator #pragma warning restore CA1852 // Seal internal types { private const string OldNamespace = "Microsoft.AspNet.DataProtection"; private const string CurrentNamespace = "Microsoft.AspNetCore.DataProtection"; private readonly ILogger _logger; public TypeForwardingActivator(IServiceProvider services) : this(services, NullLoggerFactory.Instance) { } public TypeForwardingActivator(IServiceProvider services, ILoggerFactory loggerFactory) : base(services) { _logger = loggerFactory.CreateLogger(typeof(TypeForwardingActivator)); } public override object CreateInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type expectedBaseType, string originalTypeName) => CreateInstance(expectedBaseType, originalTypeName, out var _); // for testing [UnconditionalSuppressMessage("Trimmer", "IL2057", Justification = "Type.GetType is only used with forwarded types that are referenced by DataProtection assembly.")] internal object CreateInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type expectedBaseType, string originalTypeName, out bool forwarded) { if (TryForwardTypeName(originalTypeName, out var forwardedTypeName)) { var type = Type.GetType(forwardedTypeName, false); if (type != null) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Forwarded activator type request from {FromType} to {ToType}", originalTypeName, forwardedTypeName); } forwarded = true; return base.CreateInstance(expectedBaseType, forwardedTypeName); } } forwarded = false; return base.CreateInstance(expectedBaseType, originalTypeName); } internal static bool TryForwardTypeName(string originalTypeName, out string forwardedTypeName) { forwardedTypeName = originalTypeName; var candidate = false; if (originalTypeName.Contains(OldNamespace)) { candidate = true; forwardedTypeName = originalTypeName.Replace(OldNamespace, CurrentNamespace); } if (candidate || forwardedTypeName.StartsWith(CurrentNamespace + ".", StringComparison.Ordinal)) { candidate = true; forwardedTypeName = RemoveVersionFromAssemblyName(forwardedTypeName); } return candidate; } protected static string RemoveVersionFromAssemblyName(string forwardedTypeName) { // Type, Assembly, Version={Version}, Culture={Culture}, PublicKeyToken={Token} var versionStartIndex = forwardedTypeName.IndexOf(", Version=", StringComparison.Ordinal); while (versionStartIndex != -1) { var versionEndIndex = forwardedTypeName.IndexOf(',', versionStartIndex + ", Version=".Length); if (versionEndIndex == -1) { // No end index, so are done and can remove the rest return forwardedTypeName.Substring(0, versionStartIndex); } forwardedTypeName = forwardedTypeName.Remove(versionStartIndex, versionEndIndex - versionStartIndex); versionStartIndex = forwardedTypeName.IndexOf(", Version=", StringComparison.Ordinal); } // No version left return forwardedTypeName; } }