From e64c0f1fe04bc70b80237bb8fc7bf11caa01eddf Mon Sep 17 00:00:00 2001 From: Matt Rutledge Date: Fri, 5 Feb 2021 10:23:39 -0700 Subject: [PATCH 1/9] Add logging to the dependency injection assembly reader. --- .../DotNetNuke.DependencyInjection.csproj | 4 ++ .../Extensions/TypeExtensions.cs | 52 +++++++++++++------ .../DependencyInjectionInitialize.cs | 2 +- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/DNN Platform/DotNetNuke.DependencyInjection/DotNetNuke.DependencyInjection.csproj b/DNN Platform/DotNetNuke.DependencyInjection/DotNetNuke.DependencyInjection.csproj index 8d8286c8a22..bdc81da8d48 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/DotNetNuke.DependencyInjection.csproj +++ b/DNN Platform/DotNetNuke.DependencyInjection/DotNetNuke.DependencyInjection.csproj @@ -30,6 +30,10 @@ + + + + diff --git a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs index 04d5a5c1c5f..55e509b678c 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs +++ b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs @@ -1,23 +1,25 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.DependencyInjection.Extensions { using System; using System.Linq; - using System.Reflection; + using System.Reflection; + using DotNetNuke.Instrumentation; + /// /// specific extensions to be used /// in Dependency Injection invocations. /// public static class TypeExtensions - { - // There is no logging in this file by design as - // it would create a dependency on the Logging library - // and this library can't have any dependencies on other - // DNN Libraries. - + { + // There is no logging in this file by design as + // it would create a dependency on the Logging library + // and this library can't have any dependencies on other + // DNN Libraries. + /// /// Safely Get all Types from the assembly. If there /// is an error while retrieving the types it will @@ -26,10 +28,15 @@ public static class TypeExtensions /// /// The assembly to retrieve all types from. /// + /// + /// A optional object. This will log any messages from the exception catching to the logs as an Error. + /// /// /// An array of all in the given . - /// - public static Type[] SafeGetTypes(this Assembly assembly) + /// +#pragma warning disable CS3001 // Argument type is not CLS-compliant + public static Type[] SafeGetTypes(this Assembly assembly, ILog logger = null) +#pragma warning restore CS3001 // Argument type is not CLS-compliant { Type[] types = null; try @@ -38,13 +45,26 @@ public static Type[] SafeGetTypes(this Assembly assembly) } catch (ReflectionTypeLoadException ex) { - // TODO: We should log the reason of the exception after the API cleanup - // Ensure that Dnn obtains all types that were loaded, ignoring the failure(s) + if (logger != null) + { + logger.Error($"Unable to configure services for {assembly.FullName}, see exception for details", ex); + + foreach (var loaderEx in ex.LoaderExceptions) + { + logger.Error($"LoaderException for {assembly.FullName}, details", loaderEx); + } + } + + // Ensure that Dnn obtains all types that were loaded, ignoring the failure(s) types = ex.Types.Where(x => x != null).ToArray(); } - catch (Exception) + catch (Exception ex) { - // TODO: We should log the reason of the exception after the API cleanup + if (logger != null) + { + logger.Error($"Unable to configure services for {assembly.FullName}, see exception for details", ex); + } + types = new Type[0]; } diff --git a/DNN Platform/DotNetNuke.Web/DependencyInjectionInitialize.cs b/DNN Platform/DotNetNuke.Web/DependencyInjectionInitialize.cs index 5270e1f7173..6445bd9ef53 100644 --- a/DNN Platform/DotNetNuke.Web/DependencyInjectionInitialize.cs +++ b/DNN Platform/DotNetNuke.Web/DependencyInjectionInitialize.cs @@ -39,7 +39,7 @@ private static void ConfigureAllStartupServices(IServiceCollection services) assembly => assembly.FullName.StartsWith("DotNetNuke", StringComparison.OrdinalIgnoreCase) ? 0 : assembly.FullName.StartsWith("DNN", StringComparison.OrdinalIgnoreCase) ? 1 : 2) .ThenBy(assembly => assembly.FullName) - .SelectMany(assembly => assembly.SafeGetTypes().OrderBy(type => type.FullName ?? type.Name)) + .SelectMany(assembly => assembly.SafeGetTypes(Logger).OrderBy(type => type.FullName ?? type.Name)) .Where(type => typeof(IDnnStartup).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract); var startupInstances = startupTypes.Select(CreateInstance).Where(x => x != null); From 59aaa78d7a10398865b4364512e7dc3d6fdab3b0 Mon Sep 17 00:00:00 2001 From: Matt Rutledge Date: Fri, 5 Feb 2021 12:28:35 -0700 Subject: [PATCH 2/9] Add logger to the MVC and WebAPI Startup Extensions. --- .../Extensions/StartupExtensions.cs | 20 ++++++++++++++++--- .../Api/Extensions/StartupExtensions.cs | 9 ++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/DNN Platform/DotNetNuke.Web.Mvc/Extensions/StartupExtensions.cs b/DNN Platform/DotNetNuke.Web.Mvc/Extensions/StartupExtensions.cs index 05ba2c91327..5da4717ed23 100644 --- a/DNN Platform/DotNetNuke.Web.Mvc/Extensions/StartupExtensions.cs +++ b/DNN Platform/DotNetNuke.Web.Mvc/Extensions/StartupExtensions.cs @@ -10,17 +10,31 @@ namespace DotNetNuke.Web.Mvc.Extensions using System.Text; using System.Threading.Tasks; - using DotNetNuke.DependencyInjection.Extensions; + using DotNetNuke.DependencyInjection.Extensions; + using DotNetNuke.Instrumentation; using DotNetNuke.Web.Mvc.Framework.Controllers; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; + /// + /// Adds DNN MVC Contoller Specific startup extensions to simplify the + /// Class. + /// public static class StartupExtensions - { + { + private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(StartupExtensions)); + + /// + /// Configures all of the 's to be used + /// with the Service Collection for Dependency Injection. + /// + /// + /// Service Collection used to registering services in the container. + /// public static void AddMvcControllers(this IServiceCollection services) { var controllerTypes = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(TypeExtensions.SafeGetTypes) + .SelectMany(x => x.SafeGetTypes(Logger)) .Where(x => typeof(IDnnController).IsAssignableFrom(x) && x.IsClass && !x.IsAbstract); diff --git a/DNN Platform/DotNetNuke.Web/Api/Extensions/StartupExtensions.cs b/DNN Platform/DotNetNuke.Web/Api/Extensions/StartupExtensions.cs index d4d65dc29b7..82c31628c89 100644 --- a/DNN Platform/DotNetNuke.Web/Api/Extensions/StartupExtensions.cs +++ b/DNN Platform/DotNetNuke.Web/Api/Extensions/StartupExtensions.cs @@ -7,7 +7,8 @@ namespace DotNetNuke.Web.Extensions using System; using System.Linq; - using DotNetNuke.DependencyInjection.Extensions; + using DotNetNuke.DependencyInjection.Extensions; + using DotNetNuke.Instrumentation; using DotNetNuke.Web.Api; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -17,7 +18,9 @@ namespace DotNetNuke.Web.Extensions /// Class. /// internal static class StartupExtensions - { + { + private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(StartupExtensions)); + /// /// Configures all of the 's to be used /// with the Service Collection for Dependency Injection. @@ -28,7 +31,7 @@ internal static class StartupExtensions public static void AddWebApi(this IServiceCollection services) { var controllerTypes = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(x => x.SafeGetTypes()) + .SelectMany(x => x.SafeGetTypes(Logger)) .Where(x => typeof(DnnApiController).IsAssignableFrom(x) && x.IsClass && !x.IsAbstract); From c2f7329a1bfc676937d54904ba3c2b4e6c191126 Mon Sep 17 00:00:00 2001 From: Matt Rutledge Date: Fri, 5 Feb 2021 15:00:58 -0700 Subject: [PATCH 3/9] Make sure the loader exceptions only show distinct messages. --- .../Extensions/TypeExtensions.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs index 55e509b678c..8a26c1dcab5 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs +++ b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs @@ -47,12 +47,12 @@ public static Type[] SafeGetTypes(this Assembly assembly, ILog logger = null) { if (logger != null) { - logger.Error($"Unable to configure services for {assembly.FullName}, see exception for details", ex); + // The loaderexceptions will repeat. Need to get distinct messages here. + string distinctLoaderExceptions = string.Join( + Environment.NewLine, + ex.LoaderExceptions.Select(i => i.Message).Distinct().Select(i => $"- LoaderException: {i}")); - foreach (var loaderEx in ex.LoaderExceptions) - { - logger.Error($"LoaderException for {assembly.FullName}, details", loaderEx); - } + logger.Error($"Unable to configure services for {assembly.FullName}, see exception for details {Environment.NewLine}{distinctLoaderExceptions}", ex); } // Ensure that Dnn obtains all types that were loaded, ignoring the failure(s) From e83e8d6c7f35148fcf08954840ff3feb5cbd979c Mon Sep 17 00:00:00 2001 From: Matt Rutledge Date: Fri, 5 Feb 2021 16:31:51 -0700 Subject: [PATCH 4/9] Remove Comment --- .../Extensions/TypeExtensions.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs index 8a26c1dcab5..68782dce528 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs +++ b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs @@ -15,11 +15,6 @@ namespace DotNetNuke.DependencyInjection.Extensions /// public static class TypeExtensions { - // There is no logging in this file by design as - // it would create a dependency on the Logging library - // and this library can't have any dependencies on other - // DNN Libraries. - /// /// Safely Get all Types from the assembly. If there /// is an error while retrieving the types it will From 5fcf9a049caab27bdd0e48fda475f6c79f265502 Mon Sep 17 00:00:00 2001 From: Matt Rutledge Date: Fri, 5 Feb 2021 16:33:26 -0700 Subject: [PATCH 5/9] Make instrumentation library CLSCompliant --- .../Extensions/TypeExtensions.cs | 2 -- .../DotNetNuke.Instrumentation/Properties/AssemblyInfo.cs | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs index 68782dce528..7ec0f7a7083 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs +++ b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs @@ -29,9 +29,7 @@ public static class TypeExtensions /// /// An array of all in the given . /// -#pragma warning disable CS3001 // Argument type is not CLS-compliant public static Type[] SafeGetTypes(this Assembly assembly, ILog logger = null) -#pragma warning restore CS3001 // Argument type is not CLS-compliant { Type[] types = null; try diff --git a/DNN Platform/DotNetNuke.Instrumentation/Properties/AssemblyInfo.cs b/DNN Platform/DotNetNuke.Instrumentation/Properties/AssemblyInfo.cs index 4b25f5d813f..9fec5582843 100644 --- a/DNN Platform/DotNetNuke.Instrumentation/Properties/AssemblyInfo.cs +++ b/DNN Platform/DotNetNuke.Instrumentation/Properties/AssemblyInfo.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information +using System; using System.Reflection; using System.Runtime.InteropServices; @@ -15,6 +16,8 @@ // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] + +[assembly: CLSCompliant(true)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("cb8f5692-4ea1-4397-85ec-094334605289")] From e73cc1b8744714f2e3df4aaf9b5aabba71a99f48 Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Sun, 7 Feb 2021 23:16:40 -0500 Subject: [PATCH 6/9] Added new dependency on nuspec file This clearly marks the new dependency in our nuget packages. --- Build/Tools/NuGet/DotNetNuke.DependencyInjection.nuspec | 1 + 1 file changed, 1 insertion(+) diff --git a/Build/Tools/NuGet/DotNetNuke.DependencyInjection.nuspec b/Build/Tools/NuGet/DotNetNuke.DependencyInjection.nuspec index a29f0328723..6d065ff717b 100644 --- a/Build/Tools/NuGet/DotNetNuke.DependencyInjection.nuspec +++ b/Build/Tools/NuGet/DotNetNuke.DependencyInjection.nuspec @@ -16,6 +16,7 @@ Copyright (c) .NET Foundation and Contributors, All Rights Reserved. + From 1ca5b98ba39fa93f92b6ed100d434da06cbbe9b4 Mon Sep 17 00:00:00 2001 From: Matt Rutledge Date: Mon, 8 Feb 2021 10:41:22 -0700 Subject: [PATCH 7/9] Add an overload method and mark it as obsolete to prevent a breaking change. --- .../Extensions/TypeExtensions.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs index 7ec0f7a7083..f831b3dbc5b 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs +++ b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs @@ -15,6 +15,20 @@ namespace DotNetNuke.DependencyInjection.Extensions /// public static class TypeExtensions { + /// + /// Safely Get all Types from the assembly. If there + /// is an error while retrieving the types it will + /// return an empty array of . + /// + /// The assembly to retrieve all types from. + /// An array of all in the given . + /// This is obsolete because logging is not added. Please use the SafeGetTypes with the ILog parameter + [Obsolete("Please use the SafeGetTypes with the ILog parameter.")] + public static Type[] SafeGetTypes(this Assembly assembly) + { + return assembly.SafeGetTypes(null); + } + /// /// Safely Get all Types from the assembly. If there /// is an error while retrieving the types it will From 0f7b5a73511284ecb441d4783dbec5bb36681ae5 Mon Sep 17 00:00:00 2001 From: Matt Rutledge Date: Mon, 8 Feb 2021 12:23:14 -0700 Subject: [PATCH 8/9] remove optional param --- .../DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs index f831b3dbc5b..63fc01032dc 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs +++ b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs @@ -22,7 +22,7 @@ public static class TypeExtensions /// /// The assembly to retrieve all types from. /// An array of all in the given . - /// This is obsolete because logging is not added. Please use the SafeGetTypes with the ILog parameter + /// This is obsolete because logging is not added. Please use the SafeGetTypes with the ILog parameter. [Obsolete("Please use the SafeGetTypes with the ILog parameter.")] public static Type[] SafeGetTypes(this Assembly assembly) { From ef18297ed3bc8294113d26c3934df583fb5b0ce1 Mon Sep 17 00:00:00 2001 From: Brian Dukes Date: Mon, 8 Feb 2021 14:30:25 -0600 Subject: [PATCH 9/9] Update deprecation wording --- .../Extensions/TypeExtensions.cs | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs index 63fc01032dc..cff6ea68dfb 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs +++ b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs @@ -1,57 +1,57 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information -namespace DotNetNuke.DependencyInjection.Extensions -{ - using System; - using System.Linq; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information +namespace DotNetNuke.DependencyInjection.Extensions +{ + using System; + using System.Linq; using System.Reflection; using DotNetNuke.Instrumentation; - - /// - /// specific extensions to be used - /// in Dependency Injection invocations. - /// - public static class TypeExtensions + + /// + /// specific extensions to be used + /// in Dependency Injection invocations. + /// + public static class TypeExtensions { /// - /// Safely Get all Types from the assembly. If there - /// is an error while retrieving the types it will + /// Safely Get all Types from the assembly. If there + /// is an error while retrieving the types it will /// return an empty array of . /// /// The assembly to retrieve all types from. /// An array of all in the given . /// This is obsolete because logging is not added. Please use the SafeGetTypes with the ILog parameter. - [Obsolete("Please use the SafeGetTypes with the ILog parameter.")] + [Obsolete("Deprecated in DotNetNuke 9.9.0. Please use the SafeGetTypes overload with the ILog parameter. Scheduled removal in v11.0.0.")] public static Type[] SafeGetTypes(this Assembly assembly) { return assembly.SafeGetTypes(null); } - /// - /// Safely Get all Types from the assembly. If there - /// is an error while retrieving the types it will - /// return an empty array of . - /// - /// - /// The assembly to retrieve all types from. - /// - /// - /// A optional object. This will log any messages from the exception catching to the logs as an Error. - /// - /// - /// An array of all in the given . + /// + /// Safely Get all Types from the assembly. If there + /// is an error while retrieving the types it will + /// return an empty array of . + /// + /// + /// The assembly to retrieve all types from. + /// + /// + /// A optional object. This will log any messages from the exception catching to the logs as an Error. + /// + /// + /// An array of all in the given . /// public static Type[] SafeGetTypes(this Assembly assembly, ILog logger = null) - { - Type[] types = null; - try - { - types = assembly.GetTypes(); - } - catch (ReflectionTypeLoadException ex) - { + { + Type[] types = null; + try + { + types = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { if (logger != null) { // The loaderexceptions will repeat. Need to get distinct messages here. @@ -63,19 +63,19 @@ public static Type[] SafeGetTypes(this Assembly assembly, ILog logger = null) } // Ensure that Dnn obtains all types that were loaded, ignoring the failure(s) - types = ex.Types.Where(x => x != null).ToArray(); - } - catch (Exception ex) - { + types = ex.Types.Where(x => x != null).ToArray(); + } + catch (Exception ex) + { if (logger != null) { logger.Error($"Unable to configure services for {assembly.FullName}, see exception for details", ex); } - types = new Type[0]; - } - - return types; - } - } -} + types = new Type[0]; + } + + return types; + } + } +}