PiranhaCMS / piranha.core

Piranha CMS is the friendly editor-focused CMS for .NET that can be used both as an integrated CMS or as a headless API.
http://piranhacms.org
MIT License
1.99k stars 555 forks source link

Page Models don't allow Dependency Injection in Razor Pages #1433

Open FergusCoulter opened 3 years ago

FergusCoulter commented 3 years ago

Piranha 8.4.2

Page Models currently don't allow for Parameterised Constructors and as a result Dependency Injection.

Will only except parameterless constructors.

See Below for more information:

Fergus Coulter @FergusCoulter 13:00 Hey all, I was just wondering. Is there a way of doing dependency injection with the SinglePage? Where T is a custom page model? It always seems to revert to a parameterless constructor instead of the one with DI

Håkan Edling @tidyui 13:33 @FergusCoulter Could you give an example of what you’re trying to do? @FergusCoulter But generally speaking I'd say that you can never inject an undefined generic type. The DI container is built for resolving types, how could it resolve an undefined type?

Fergus Coulter @FergusCoulter 14:01 code

[PageType(Title = "Standard Page")]
    public class GenericPage : Page<GenericPage>
    {
        public GenericPage(//Something in here to inject)
            {

        }

    }

sorry I was a bit vague I meant in the model itself, so In this case I would be using the "Generic Page" model for each view (SinglePage) I would like to have functionality though, so in the above example I have a constructor which I want to pass in a dependency to inject. However, it won't allow it. It only accepts parameterless constructors

Håkan Edling @tidyui 14:08 Ok I get it. The repository layer is responsible for creating the model objects when transforming them from the data representation. This is simply done by calling Activator.CreateInstance(T) and is not passed through any kind of DI-container. Add an issue for this at our GitHub repo and we'll take a look at it! Technically it shouldn't be impossible to support, but obviously it needs to be tested thoroughly :)

tidyui commented 3 years ago

This is my comment from Gitter.

There's a BIG problem here though. At the moment the system supports both regular models and Dynamic models that can be constructed without having access to, or knowing the type of the real model. As the constructor that accepts input will never be available for the dynamic models, the behavior will be different depending on which model you use.

Now, in the long run we're looking into abandoning the dynamic models for many reasons. First reason is it will slim down the code base and make it easier to maintain. Secondly stuff like this can be easily implemented, things like:

And all of these things that can't be done on dynamic models. But at the moment it's hard to get a consistent behavior, especially as the manager interface currently only uses the dynamic models.

Given the circumstances this would need to be implemented in conjunction with #1224 which will consolidate the manager models and move away from dynamic models.

tidyui commented 3 years ago

Scheduled this for 10.0 but missed that it is dependent on #1224 which we won't have time to complete for 10.0. Need to move this out of the upcoming release

Neutrino-Sunset commented 2 years ago

I'm looking around for a CMS I can easily integrate into an ASP Core project I'm working on. Piranha looks great but this bug has me worried. Am I misunderstanding this or does dependency injection not work for Razor page models at all? Because if dependency injection doesn't work for page models at all then that would be a big problem.

How does a page model acquire services in order to reach out to REST apis or access databases, or even perform logging? Do you store a global reference to the ServiceProvider somewhere and manually create ServiceProvider scopes to instantiate services or something?

If this is a problem is it just for Razor pages? Does DI work using MVC?

tidyui commented 2 years ago

@Neutrino-Sunset If you’re talking about this model https://github.com/PiranhaCMS/piranha.core/blob/master/core/Piranha.AspNetCore/Models/SinglePage.cs it is just a simple wrapper that loads the real page model on GET. To inject services into this model just use it as a base class and inject the services you want in the constructor.

This issue is rather about allowing injection into the real CMS model which is completely different and not related to Razor Pages.

Best regards