Create settings necessary for an MVC Pipeline#7290
Conversation
| bool ShowQuickModuleAddMenu { get; } | ||
|
|
||
| /// <summary>Gets the pipeline type for the portal.</summary> | ||
| string PagePipeline { get; } |
There was a problem hiding this comment.
We need a strategy for adding fields to interfaces without making a breaking change.
There was a problem hiding this comment.
Any ideas? IPortalSettingsPlus will get very silly very soon. Then I'd prefer IPortalSettings2.
There was a problem hiding this comment.
In this case, there is not a need to expose it from the interface (the places where the property is currently used, the variable's type is PortalSettings, not IPortalSettings). But it would obviously be helpful to switch references to the interface, or have it available for 3rd parties.
I see four options for adding members to an interface (in rough order of my preference).
- We create smaller named interfaces with only a small handful of properties, e.g.
public interface IRenderingSettings { PagePipeline.PortalRenderingPipeline PagePipeline { get; } } - We add a version number, e.g.
public interface IPortalSettingsV2 : IPortalSettings { PagePipeline.PortalRenderingPipeline PagePipeline { get; } } - We switch to abstract base classes instead of interfaces, e.g.
public abstract class PortalSettingsBase { PagePipeline.PortalRenderingPipeline PagePipeline { get; } } - We break interfaces when necessary on major versions
There was a problem hiding this comment.
But as long as you are not actively creating objects in your module to implement the interface, it wouldn't break, no? I mean: if I use an IPortalSettings in my module, my module wouldn't break because a new property gets added. Only when I create an object that implements the IPortalSettings would things go South, no? If this is true, then should we not have a strategy where certain interfaces are marked solely for consumption?
There was a problem hiding this comment.
There are basically 2 strategies to add to an interface I have seen.
- Extensions methods, if the new members are related, then they could be grouped into some extension to that basic interface. I have done so for the portal styles with .GetPortalStyles() which extends IPortalSettings or some such.
- I have seen in many libraries including some from Microsoft when interfaces are simply versioned and intherit an older interface within the new one. One example is Visual Studio SDK itself that has IVsSolution, IVsSolution2, IVsSolution3, IVsSolution4, IVsSolution5, IVsSolution6. It is ugly but it works for both adding new stuff, changing stuff and removing deprecated stuff. And if we have an inherithance chain, consumers only have to migrate to the new type and only handle what has changed. This would be one example https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/NuGet.VisualStudio/Extensibility/IVsPackageInstaller2.cs
With todays tooling (intellisense and AI), I personally don't have anything against option 2 which could allow us to move quite faster in some areas.
There was a problem hiding this comment.
Yes, if the thing is not meant for public usage, in this case I think people would want to be able to access those settings.
There was a problem hiding this comment.
@bdukes regarding:
I'm happy to add numbered versions of interfaces. Do we want to match major DNN version (e.g. this field would be on IPortalSettings11), or just start at 2 and make changes any time we want?
I am of the opinion we got go 2, 3, 4 that way we don't even need to wait for next major to move forward on "user non-breaking changes" as long as we keep the previous interface alive for 2 majors.
There was a problem hiding this comment.
The only thing I did not test and this may be pretty simple but for DI I think we would do something like:
services.AddScoped<IService, Service>();
services.AddScoped<Iservice2, Service>();Now that brings another interesting thought though, Service if it was public now has the breaking changes for anyone that inherited it, unless it was sealed. So we may need a Service and a Service2 as well... Maybe we should start sealing new classes we are adding unless there is a good reason to inherit from them. That might simplify future maintenance...
There was a problem hiding this comment.
It shouldn't be breaking to inherit from PortalSettings if we add IPortalSettings2, because the base class will already implement that interface.
There was a problem hiding this comment.
Are you saying that if we define the interface as
internalthen we don't need to worry about backward compatibility?
I was thinking, Yes.
If the interface is internal, we only need to preserve compatibility for components we control and ship together.
|
|
||
| PortalSettings.PortalAliasMapping GetPortalAliasMappingMode(int portalId); | ||
|
|
||
| string GetPortalPagePipeline(int portalId); |
There was a problem hiding this comment.
Adding a member to an interface here as well, needs discussion
There was a problem hiding this comment.
This would be a scenario where an extension methods might suffice
There was a problem hiding this comment.
But it would still be good to add it to the interface at some point in the future
Co-authored-by: Brian Dukes <bdukes@engagesoftware.com>
…/Dnn.Extensions/App_LocalResources/Extensions.resx Co-authored-by: Brian Dukes <bdukes@engagesoftware.com>
…/Dnn.Pages/App_LocalResources/Pages.resx Co-authored-by: Brian Dukes <bdukes@engagesoftware.com>
…/Dnn.SiteSettings/App_LocalResources/SiteSettings.resx Co-authored-by: Brian Dukes <bdukes@engagesoftware.com>
Co-authored-by: Brian Dukes <bdukes@engagesoftware.com>
Co-authored-by: Brian Dukes <bdukes@engagesoftware.com>
This PR creates the settings necessary for the MVC Pipeline. These are the following:
This is the first PR in a series of PRs that aim to build out the MVC Pipeline functionality in DNN. It targets a feature branch as all PRs will need to be in before this can be merged into the main branch of the project. The reason for a more granular approach to the PRs is to make them easier to verify for the reviewers.