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. + 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..cff6ea68dfb 100644 --- a/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs +++ b/DNN Platform/DotNetNuke.DependencyInjection/Extensions/TypeExtensions.cs @@ -1,54 +1,81 @@ // 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; +namespace DotNetNuke.DependencyInjection.Extensions +{ + using System; + using System.Linq; + using System.Reflection; - /// - /// 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. - - /// - /// 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 . - /// - public static Type[] SafeGetTypes(this Assembly assembly) - { - Type[] types = null; - try - { - types = assembly.GetTypes(); - } - 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) - types = ex.Types.Where(x => x != null).ToArray(); - } - catch (Exception) - { - // TODO: We should log the reason of the exception after the API cleanup - types = new Type[0]; - } - - return types; - } - } -} + using DotNetNuke.Instrumentation; + + /// + /// 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 + /// 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("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 . + /// + public static Type[] SafeGetTypes(this Assembly assembly, ILog logger = null) + { + Type[] types = null; + try + { + types = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + if (logger != null) + { + // 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}")); + + 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) + 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; + } + } +} 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")] 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); 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);