DNN Forums

Ask questions about your website to get help learning DNN and help resolve issues.

Dependency Injection in Theme Objects?

 9 Replies
 3 Subscribed to this topic
 26 Subscribed to this forum
Sort:
Author
Messages
Senior Member
Posts: 1607
Senior Member
MVP
MVP
You're an MVP!
New Poster
New Poster
Congrats on posting!

Hello Everyone: 

Are we not supporting dependency injection in theme objects yet?  I'm having issues trying every way I've done prior to include the INavigationManager in a theme object, but I can't find a way to both get it to compile and also not throw exceptions at runtime.  

In short, after adding the Nuget references to <code>DotNetNuke,Core</code>, <code>.Abstractions</code>, and .<code>DependencyInjection</code>, the following code snippets that normally would work do not.  

        using DotNetNuke.Abstractions;

        private readonly INavigationManager _NavigationManager;

        public User()
        {
            this._NavigationManager = this.DependencyProvider.GetRequiredService();  
        }

In the snippet above, I can't find a way to get <code>DependencyProvider</code> to resolve.  I've tried with/without this. and <code><INavagationManager></code> to no avail.  Without in some way to initialize the <code>DependencyProvider</code> in the theme object, the <code>_NavigationManager</code> object is <code>null</code>.  

When looking at the source code for SkinObjectBase, it looks like the base class doesn't include any references to dependency injection.  Am I missing something obvious? 🤔 

Senior Member
Posts: 1607
Senior Member
MVP
MVP
You're an MVP!
New Poster
New Poster
Congrats on posting!

Oh, and I've also added the following to the C# class and csproj.  

<code>using Microsoft.Extensions.DependencyInjection;</code>

<code><Reference Include="netstandard" /></code>

Senior Member
Posts: 1607
Senior Member
MVP
MVP
You're an MVP!
New Poster
New Poster
Congrats on posting!

I just found a core theme object that's doing almost exactly what I'm doing, but I don't see any differences.  🤔 

https://github.com/dnnsof...User.ascx.cs#L11-L35

I still can't get the <code>DependencyProvider</code> to resolve, even when using <code>Globals.</code>.

Advanced Member
Posts: 159
Advanced Member
MVP
MVP
You're an MVP!

WebForms DI support will be available in DNN 10, which will support regular constructor injection without having to do any other tricks.

<code>Globals.DependencyProvider</code> is internal, so that's why the core skin object can use it but your skin object cannot.

Until DNN 10, you can use the following technique to get the DI scope for the request:

<code>
using DotNetNuke.Abstractions;
using DotNetNuke.Common.Extensions;

private readonly INavigationManager _NavigationManager;

public User()
{
    IServiceScope currentScope = HttpContext.Current.GetScope();
    IServiceProvider serviceProvider = scope.ServiceProvider;
    this._NavigationManager = serviceProvider.GetRequiredService<INavigationManager>();  
}
</code>
Senior Member
Posts: 1607
Senior Member
MVP
MVP
You're an MVP!
New Poster
New Poster
Congrats on posting!
Posted By Brian Dukes on 1/14/2025 1:36 PM

Until DNN 10, you can use the following technique to get the DI scope for the request:

<code>
using DotNetNuke.Abstractions;
using DotNetNuke.Common.Extensions;

private readonly INavigationManager _NavigationManager;

public User()
{
    IServiceScope currentScope = HttpContext.Current.GetScope();
    IServiceProvider serviceProvider = scope.ServiceProvider;
    this._NavigationManager = serviceProvider.GetRequiredService<INavigationManager>();  
}
</code>

This was exactly what I needed... Thanks, Brian!  🥳💪🏽

 

Veteran Member
Posts: 350
Veteran Member
3 Helpful Replier
Helpful Replier
Thanks for being such a helpful replier!
MVP
MVP
You're an MVP!
2 Engaged Reader
Engaged Reader
You are an engaged reader!
Avid Reader
Avid Reader
Avid Reader art thou!
To expand on Brian's excellent trick here (I have done this in many places). You can prepare for the future by having both the parameterless contructor and the one with dependency injection and then the parameterless one you can make it call the "new" one and mark it obsolete or add a todo comment to remove it later.
Growing Member
Posts: 66
Growing Member
4 Helpful Replier
Helpful Replier
Thanks for being such a helpful replier!
New Poster
New Poster
Congrats on posting!
5 Engaged Reader
Engaged Reader
You are an engaged reader!
2 Avid Reader
Avid Reader
Avid Reader art thou!
2 Most Liked
Most Liked
Congrats, your posts are really liked!

Okay, so here we are a year later. v10 has been out for a while. I am interested in using the code versions of the new fluent CDF stuff in my skin. I don't want to use the skin objects because we generate a few different JS files sometimes and not others. So our auth.bundle.esm.js may or may not be there. So we like to wrap it in a utility/helper that calls System.IO.File.Exists().

So, I've added a partial to my theme and am including partials/preheader-cdf.ascx. My environment is DNN v10.02.01 and I really wanted to do the DI the new way. I did find the right interface, IClientResourceController. But no matter how many examples I found or things I read that seemed to be hinting that there was a new way in v10... I could not get it to work. 

Here is what I do have working:

<%@ Import Namespace="Microsoft.Extensions.DependencyInjection" %>
<%@ Import Namespace="DotNetNuke.Common.Extensions" %>
<%@ Import Namespace="DotNetNuke.Abstractions" %>
<%@ Import Namespace="DotNetNuke.Abstractions.ClientResources" %>
<%@ Import Namespace="DotNetNuke.Web.Client.ResourceManager" %>

<script runat="server">

  private IClientResourceController _clientResourceController;

  protected override void OnLoad(EventArgs e)
  {
      base.OnLoad(e);
      AddJs();
      // AddOpenGraph();
  }

  private void AddJs()
  {
    // TODO get the v10 way working, this also works in v9
    IServiceScope currentScope = HttpContext.Current.GetScope();
    IServiceProvider serviceProvider = currentScope.ServiceProvider;
    this._clientResourceController = serviceProvider.GetRequiredService(); 

    // TESTING Fluent CDF
    var cssAuth = _clientResourceController.CreateStylesheet("SkinAuth.css", PathNameAlias.SkinPath)
      .SetProvider(ClientResourceProviders.DnnFormBottomProvider)
      .SetPriority(FileOrder.Css.SkinCss)
    ;
    _clientResourceController.AddStylesheet(cssAuth);
    ...

So, anyone know what the DNN v10 way to do those first 3 lines under the // TODO?

Advanced Member
Posts: 159
Advanced Member
MVP
MVP
You're an MVP!
I don't think there's a way to use constructor injection from an .ascx file. You need to be able to create a new constructor, but you can't do that in an .ascx file because you don't know the class name. You have to do it from a codebehind .cs file that the .ascx file inherits from.

So, for your workflow, Jeremy, I think what you have is probably the best you can do.
Growing Member
Posts: 66
Growing Member
4 Helpful Replier
Helpful Replier
Thanks for being such a helpful replier!
New Poster
New Poster
Congrats on posting!
5 Engaged Reader
Engaged Reader
You are an engaged reader!
2 Avid Reader
Avid Reader
Avid Reader art thou!
2 Most Liked
Most Liked
Congrats, your posts are really liked!

If I wired up the code behind, is there an example somewhere of what that would look like?

Advanced Member
Posts: 159
Advanced Member
MVP
MVP
You're an MVP!
The example I posted above should work for a codebehind (introduce a constructor and add arguments for each item you'd like to pull from the DI container)

These Forums are for the discussion of the open source CMS DNN platform and ecosystem.

For the benefit of the community and to protect the integrity of the ecosystem, please observe the following posting guidelines:

  1. If you have (suspected) security issues, please DO NOT post them in the forums but instead follow the official DNN security policy
  2. No Advertising. This includes the promotion of commercial and non-commercial products or services which are not directly related to DNN.
  3. No vendor trolling / poaching. If someone posts about a vendor issue, allow the vendor or other customers to respond. Any post that looks like trolling / poaching will be removed.
  4. Discussion or promotion of DNN Platform product releases under a different brand name are strictly prohibited.
  5. No Flaming or Trolling.
  6. No Profanity, Racism, or Prejudice.
  7. Site Moderators have the final word on approving / removing a thread or post or comment.
  8. English language posting only, please.

Would you like to help us?

Awesome! Simply post in the forums using the link below and we'll get you started.

Get Involved