dnnsoftware / Dnn.Platform

DNN (formerly DotNetNuke) is the leading open source web content management platform (CMS) in the Microsoft ecosystem.
https://dnncommunity.org/
MIT License
1.02k stars 745 forks source link

Allow registration of custom control factories #5605

Closed GerardSmit closed 1 year ago

GerardSmit commented 1 year ago

Description of problem

It's not possible to register or override a custom IModuleControlFactory in DNN. This is because the extensions are hard-coded in ModuleControlPipeline.

Description of solution

  1. Move the extension check out of the pipeline and into the factory.
  2. Add a Priority property, which the pipeline will use to determinate which factory to use. By default, DNN control factories have a priority of 100. If you register a custom control factory (for example for .html to modify the content) you can give it a priority of 200 to overrule the DNN factory.

The new factory would look like this:

public interface IModuleControlFactory
{
    /// <summary>
    /// Gets the priority of the factory.
    /// The factory with the highest priority will be used.
    /// </summary>
    /// <remarks>
    /// DNN Control factories (WebForms, Razor, HTML, MVC) have a priority of 100
    /// and the default factory (Reflected) has a priority of -1.
    /// </remarks>
    int Priority { get; }

    /// <summary>Validates if the factory supports the given configuration and <see cref="controlSrc"/>.</summary>
    /// <param name="moduleConfiguration">Module configuration.</param>
    /// <param name="controlSrc">Control source.</param>
    /// <returns><c>true</c> if the factory supports the control; otherwise, <c>false</c>.</returns>
    bool SupportsControl(ModuleInfo moduleConfiguration, string controlSrc);

    // CreateControl and CreateSettingsControl are unchanged.
}

The pipeline will be changed that it'll resolve all IModuleControlFactory and get the first supported factory.

Description of alternatives considered

While it is currently possible to override the IModuleControlPipeline in the service collection:

public class Extension : IDnnStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IModuleControlPipeline>()
    }
}

public class NewModuleControlPipeline : ModuleControlPipeline
{
    // ...
}

This brings two problems:

  1. If multiple extensions are changing the IModuleControlPipeline, the last one will be used. All other pipelines will be ignored.
  2. The default IModuleControlPipeline of DNN (ModuleControlPipeline) is in a class library (DotNetNuke.ModulePipeline) which is not in NuGet. So you'll have to add a DLL-reference. šŸ˜”
GerardSmit commented 1 year ago

I've created a PR (#5606) with the proposed solution.

bdukes commented 1 year ago

I don't have an issue with these changes, thought I am curious what your use case is for needing a custom module control factory.

GerardSmit commented 1 year ago

I'm prototyping a cross-platform CMS in ASP.NET Core uses the same database as DNN. My end goal is where you can make modules for both .NET Framework and .NET (Core).

I have a prototype working with the alternative solution (overriding IModuleControlPipeline) but this is quite hacky. šŸ˜…

GerardSmit commented 1 year ago

Closing as this is merged in the DNN 10 branch šŸŽ‰

Thanks!