-
Notifications
You must be signed in to change notification settings - Fork 751
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add List-Services command to Prompt (#3932)
* Load DNN types first in DI startup Fixes #3335 * Simplify main DI Startup class It doesn't need to implement IDnnStartup, it can just configure the service provider and be done. This also allows us to stop ignoring other IDnnStartup instances in the DotNetNuke.Web project, were they to be created later. * Fix error message when calling ConfigureServices * Move AddWebApi call to regular IDnnStartup This ensures that it's called at the right time relative to all other DI configuration. * Fix ordering of IDnnStartup for real * Add List-Services debugging command for Prompt
- Loading branch information
Showing
6 changed files
with
731 additions
and
621 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
DNN Platform/DotNetNuke.Web/DependencyInjectionInitialize.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// 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.Web | ||
{ | ||
using System; | ||
using System.Linq; | ||
|
||
using DotNetNuke.DependencyInjection; | ||
using DotNetNuke.DependencyInjection.Extensions; | ||
using DotNetNuke.Instrumentation; | ||
using DotNetNuke.Services.DependencyInjection; | ||
|
||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
/// <summary>Initializes the Dependency Injection container.</summary> | ||
public static class DependencyInjectionInitialize | ||
{ | ||
private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(DependencyInjectionInitialize)); | ||
|
||
internal static IServiceCollection ServiceCollection { get; private set; } | ||
|
||
/// <summary>Builds the service provider.</summary> | ||
/// <returns>An <see cref="IServiceProvider"/> instance.</returns> | ||
public static IServiceProvider BuildServiceProvider() | ||
{ | ||
var services = new ServiceCollection(); | ||
services.AddSingleton<IScopeAccessor, ScopeAccessor>(); | ||
ConfigureAllStartupServices(services); | ||
|
||
ServiceCollection = services; | ||
return services.BuildServiceProvider(); | ||
} | ||
|
||
private static void ConfigureAllStartupServices(IServiceCollection services) | ||
{ | ||
var startupTypes = AppDomain.CurrentDomain.GetAssemblies() | ||
.OrderBy( | ||
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)) | ||
.Where(type => typeof(IDnnStartup).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract); | ||
|
||
var startupInstances = startupTypes.Select(CreateInstance).Where(x => x != null); | ||
foreach (var startup in startupInstances) | ||
{ | ||
try | ||
{ | ||
startup.ConfigureServices(services); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Logger.Error($"Unable to configure services for {startup.GetType().FullName}, see exception for details", ex); | ||
} | ||
} | ||
} | ||
|
||
private static IDnnStartup CreateInstance(Type startupType) | ||
{ | ||
try | ||
{ | ||
return (IDnnStartup)Activator.CreateInstance(startupType); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Logger.Error($"Unable to instantiate startup code for {startupType.FullName}", ex); | ||
return null; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// 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.Web.Prompt | ||
{ | ||
using System; | ||
using System.Linq; | ||
using System.Net; | ||
|
||
using DotNetNuke.Abstractions.Portals; | ||
using DotNetNuke.Abstractions.Prompt; | ||
using DotNetNuke.Abstractions.Users; | ||
using DotNetNuke.Prompt; | ||
|
||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
/// <summary> | ||
/// This is a (Prompt) Console Command. You should not reference this class directly. It is to be used solely through Prompt. | ||
/// </summary> | ||
[ConsoleCommand("list-services", "Prompt_DebugCategory", "Prompt_ListServices_Description")] | ||
public class ListServices : ConsoleCommand | ||
{ | ||
public override string LocalResourceFile => Constants.DefaultPromptResourceFile; | ||
|
||
public override void Initialize(string[] args, IPortalSettings portalSettings, IUserInfo userInfo, int activeTabId) | ||
{ | ||
base.Initialize(args, portalSettings, userInfo, activeTabId); | ||
if (!userInfo.IsSuperUser) | ||
{ | ||
this.AddMessage(this.LocalizeString("Prompt_ListServices_Unauthorized")); | ||
} | ||
|
||
this.ParseParameters(this); | ||
} | ||
|
||
public override IConsoleResultModel Run() | ||
{ | ||
if (!this.User.IsSuperUser) | ||
{ | ||
return new ConsoleErrorResultModel(this.LocalizeString("Prompt_ListServices_Unauthorized")); | ||
} | ||
|
||
var services = DependencyInjectionInitialize.ServiceCollection.Select( | ||
descriptor => new | ||
{ | ||
LifeTime = descriptor.Lifetime.ToString("G"), | ||
Service = this.GetTypeName(descriptor.ServiceType), | ||
Implementation = this.GetImplementationText(descriptor), | ||
}) | ||
.OrderBy(desc => desc.Service) | ||
.ThenBy(desc => desc.Implementation) | ||
.ToList(); | ||
return new ConsoleResultModel | ||
{ | ||
Data = services, | ||
Records = services.Count, | ||
}; | ||
} | ||
|
||
private string GetImplementationText(ServiceDescriptor descriptor) | ||
{ | ||
if (descriptor.ImplementationInstance != null) | ||
{ | ||
return this.LocalizeString("Prompt_ListServices_ImplementationInstance"); | ||
} | ||
|
||
if (descriptor.ImplementationFactory != null) | ||
{ | ||
return this.LocalizeString("Prompt_ListServices_ImplementationFactory"); | ||
} | ||
|
||
return this.GetTypeName(descriptor.ImplementationType); | ||
} | ||
|
||
private string GetTypeName(Type type) | ||
{ | ||
if (type == null) | ||
{ | ||
return this.LocalizeString("Prompt_ListServices_None"); | ||
} | ||
|
||
return WebUtility.HtmlEncode(type.FullName ?? type.Name); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,20 @@ | ||
// 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.Web | ||
{ | ||
using DotNetNuke.DependencyInjection; | ||
using DotNetNuke.Web.Extensions; | ||
|
||
namespace DotNetNuke.Web | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
using DotNetNuke.DependencyInjection; | ||
using DotNetNuke.DependencyInjection.Extensions; | ||
using DotNetNuke.Instrumentation; | ||
using DotNetNuke.Services.DependencyInjection; | ||
using DotNetNuke.Web.Extensions; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
public class Startup : IDnnStartup | ||
{ | ||
private static readonly ILog _logger = LoggerSource.Instance.GetLogger(typeof(Startup)); | ||
|
||
public Startup() | ||
{ | ||
this.Configure(); | ||
} | ||
|
||
public IServiceProvider DependencyProvider { get; private set; } | ||
|
||
public void ConfigureServices(IServiceCollection services) | ||
{ | ||
var startupTypes = AppDomain.CurrentDomain.GetAssemblies() | ||
.Where(x => x != Assembly.GetAssembly(typeof(Startup))) | ||
.SelectMany(x => x.SafeGetTypes()) | ||
.Where(x => typeof(IDnnStartup).IsAssignableFrom(x) && | ||
x.IsClass && | ||
!x.IsAbstract); | ||
|
||
var startupInstances = startupTypes | ||
.Select(x => this.CreateInstance(x)) | ||
.Where(x => x != null); | ||
|
||
foreach (IDnnStartup startup in startupInstances) | ||
{ | ||
try | ||
{ | ||
startup.ConfigureServices(services); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.Error($"Unable to configure services for {typeof(Startup).FullName}, see exception for details", ex); | ||
} | ||
} | ||
|
||
services.AddWebApi(); | ||
} | ||
|
||
private void Configure() | ||
{ | ||
var services = new ServiceCollection(); | ||
services.AddSingleton<IScopeAccessor, ScopeAccessor>(); | ||
this.ConfigureServices(services); | ||
this.DependencyProvider = services.BuildServiceProvider(); | ||
} | ||
|
||
private object CreateInstance(Type startupType) | ||
{ | ||
IDnnStartup startup = null; | ||
try | ||
{ | ||
startup = (IDnnStartup)Activator.CreateInstance(startupType); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.Error($"Unable to instantiate startup code for {startupType.FullName}", ex); | ||
} | ||
|
||
return startup; | ||
} | ||
} | ||
} | ||
/// <summary>Configures services for The DotNetNuke.Web project.</summary> | ||
public class Startup : IDnnStartup | ||
{ | ||
/// <inheritdoc /> | ||
public void ConfigureServices(IServiceCollection services) | ||
{ | ||
services.AddWebApi(); | ||
} | ||
} | ||
} |
Oops, something went wrong.