• Login
  • Register

DNN Forums

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

Abstractions Interfaces

You are not authorized to post a reply.
Sort:


New Member


Posts:5
New Member

    I am working on refactoring my 80+ custom modules to remove all deprecated DNN calls. I am coding against DNN 9.8.0. I have researched and understand that I am supposed to use interfaces in the abstractions namespace but I am not sure how to use the interfaces. I have read up on dependency injection and still don't quite understand. The item I am working on at the moment is simple and an explanation would help me understand how to use these interfaces in general.

    I am currently trying to get a list of portal aliases using portal ID. My old code is:

    Dim portal As New Portals.PortalAliasController
    Dim aliases As List(Of Portals.PortalAliasInfo) = portal.GetPortalAliasesByPortalId(ActiveModule.PortalID)

    My new code is:

    Dim portalService As Abstractions.Portals.IPortalAliasService
    Dim aliases As List(Of Abstractions.Portals.IPortalAliasInfo) = portalService.GetPortalAliasesByPortalId(ActiveModule.PortalID)

    Since interfaces are just abstract classes, I know I am missing something here. As expected, I am getting a "Object reference not set to an instance of an object" on the second line of the new code since I have no concrete instance.

    How do I implement these interfaces correctly? How do I get a list of portal aliases using dependency injection?



    Basic Member


    Posts:97
    Basic Member

      It depends on how you're running this code. If this code is inside of a Web API controller, an MVC controller, or a scheduled task, you can add IPortalAliasService as a parameter to the constructor, and DNN will automatically supply a value when it creates the component.

      We expect to also support constructor injection for WebForms modules in DNN 10, but for now these dependencies need to be explicitly requested in WebForms modules. PortalModuleBase exposes a DependencyProvider property, which you can use to get the dependency. Here's an example:

      Imports Microsoft.Extensions.DependencyInjection
      
      Public Partial Class View
          Inherits PortalModuleBase
      
          Private ReadOnly portalAliasService As IPortalAliasService
      
          Public Sub New()
              Me.portalAliasService = DependencyProvider.GetService(Of IPortalAliasService)()
          End Sub
      End Class

      There are other components which do not currently have access to the dependency injection container, and in those components it is not entirely possible to remove these warnings. We expect to resolve these issues in DNN 10. Some examples of these include the business controller class (where you would implement searching, import/export, and upgrade logic, among other things), folder providers, prompt commands, and connectors.

      Note that you can create your own classes that you register with the dependency injection container, and those classes can also have constructor dependencies on other classes registered with the dependency injection container. Here's an example with a custom class that's used from multiple places:

      Imports DotNetNuke.DependencyInjection
      Imports Microsoft.Extensions.DependencyInjection
      
      Public Class Startup
          Inherits IDnnStartup
      
          Public Sub ConfigureServices(ByVal services As IServiceCollection)
              services.AddScoped(Of MyService)()
          End Sub
      End Class
      
      Public Class MyService
          Private ReadOnly portalAliasService As IPortalAliasService
      
          Public Sub New(ByVal portalAliasService As IPortalAliasService)
              Me.portalAliasService = portalAliasService
          End Sub
      End Class
      
      Public Partial Class View
          Inherits PortalModuleBase
      
          Private ReadOnly myService As MyService
      
          Public Sub New()
              Me.myService = DependencyProvider.GetService(Of MyService)()
          End Sub
      End Class
      
      Public Class MyController
          Inherits DnnApiController
      
          Private ReadOnly myService As MyService
      
          Public Sub New(ByVal myService As MyService)
              Me.myService = myService
          End Sub
      End Class
      
      Public Class MyBusinessController
          Inherits IUpgradeable
      
          Private ReadOnly myService As MyService
      
          Public Sub New()
              Me.myService = New MyService(New PortalAliasController())
          End Sub
      
          Public Function UpgradeModule(ByVal Version As String) As String
          End Function
      End Class

      Hope it helps!

      DNN partner specializing in custom, enterprise DNN development https://engagesoftware.com/showcase


      New Member


      Posts:5
      New Member

        Thanks Brian! That's exactly what I needed. This code above was indeed in a WebAPI class that inherited from DnnApiController. I added this code:

        Protected portalAliasService As Abstractions.Portals.IPortalAliasService

        Public Sub New(ByVal portalAliasService As Abstractions.Portals.IPortalAliasService)

        Me.portalAliasService = portalAliasService

        End Sub



        I now can get a list of aliases from portalAliasService. Big thumbs up and thank you again.

        I have a couple of follow up questions:

        1. If I need access to multiple services, do I add each as another parameter in the constructor above? For example, if I need access to iNavigationManager also, would my code look like:
        Protected portalAliasService As Abstractions.Portals.IPortalAliasService
        Protected navigationManager As Abstractions.INavigationManager
        Public Sub New(ByVal portalAliasService As Abstractions.Portals.IPortalAliasService, ByVal navigationManager as Abstractions.INavigationManager)
        Me.portalAliasService = portalAliasService
        Me.navigationManager = navigationManager
        End Sub

        Does this seem correct?

        2. What can I do in custom business classes to expose these services? In other words, how can I get access to the dependency provider that is in portalModuleBase but in my custom classes?



        Basic Member


        Posts:97
        Basic Member

          1. Yes, that's correct.
          2. That's like the MyService class in the example above. You can register it in the DI container, and then request it from whatever components are using it (or manually create it).
          DNN partner specializing in custom, enterprise DNN development https://engagesoftware.com/showcase


          New Member


          Posts:5
          New Member

            I understood MyService above to be "creating" a new custom service and that is registered using the ConfigureServices method. However, I need to know how to pull or expose that service in a custom class that does not inherit from portalModuleBase or DnnApiController. After reading through the code once more, I see you are showing 3 ways to pull the service. The first way requires inheriting portalModuleBase, the second requires inheriting DnnApiController, the third is manual. Since my class would not inherit portalModuleBase nor DnnApiController, my only option is the manual option.

            I guess the hard part of the manual option is knowing which controller implements the interface I need. I will start working to figure that out. I really appreciate the feedback. Thanks again.



            Basic Member


            Posts:97
            Basic Member

              Using a manual approach is always available, and what you'll need to fall back to if another approach won't work. That said, my intention above is that MyService would represent your custom class that doesn't inherit from PortalModuleBase, etc.

              All of your code that runs inside DNN should be getting called by some component within DNN itself. So, ultimately, after some changes in DNN 10, there's nowhere that your custom code can't take advantage of dependency injection. If you design your custom code to take any dependencies it needs as constructor parameters, you can supply constructor arguments either via DI support or manually. That may happen transitively, if you class relies on another class that relies on a separate interface.

              Hope that helps!

              DNN partner specializing in custom, enterprise DNN development https://engagesoftware.com/showcase


              New Member


              Posts:5
              New Member

                Okay I think I see now. My custom class would use the constructor above. Then, instead of creating a new instance of my class elsewhere, I would call an instance of it through the dependency provider using the methods you showed. I will give it a try. 

                I have tried the DependencyProvider.getService(of MyService) method in modulebase, but I get a "Function GetService(serviceType As Type) As Object' has no type parameters and so cannot have type arguments" error in visual studio. It doesn't like the "Of MyService" parameter for some reason. Any chance there is a typo in the code above or is the MyService class missing an implementation of something?



                Basic Member


                Posts:97
                Basic Member

                  Yes, sorry, that should be GetRequiredService. It's an extension method, so you need the Microsoft.Extensions.DependencyInjection import.

                  DNN partner specializing in custom, enterprise DNN development https://engagesoftware.com/showcase


                  New Member


                  Posts:5
                  New Member

                    That got it. Appreciate your time.

                    You are not authorized to post a reply.

                    These Forums are dedicated to discussion of DNN Platform.

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

                    1. No Advertising. This includes promotion of commercial and non-commercial products or services which are not directly related to DNN.
                    2. 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.
                    3. Discussion or promotion of DNN Platform product releases under a different brand name are strictly prohibited.
                    4. No Flaming or Trolling.
                    5. No Profanity, Racism, or Prejudice.
                    6. Site Moderators have the final word on approving / removing a thread or post or comment.
                    7. 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