Dnn.Platform: Dynamically compiled Web APIs don't resolve since DNN 9.4

Description of bug

When a system has WebApi controllers which are compiled dynamically - in our case 2sxc Apps can include .cs files which are compiled on the fly - they must be given to the .net framework for activation. This worked well till DNN 9.4, which accidentally broke this functionality because DNN 9.4 replaced the IHttpControllerActivator.

I already found out how to fix this.

Steps to reproduce

List the steps to reproduce the behavior:

  1. Create a DNN 9.2 and a 9.4.x and install 2sxc on both
  2. Add an app-module (2sxc) to a page and install the angular demo app from https://2sxc.org/en/apps/app/tutorial-angular-8
  3. In the UI, click on the WebAPI demo
  4. As you can see, it works in <9.4 and fails in 9.4.x

Result in Pre 9.4

image

Result in 9.4

image

Result in 9.4 with fix applied

image

Current result

In 9.4 the WebApi calls fail with this message:

{"Message":"No HTTP resource was found that matches the request URI 'http://dnn940rc1raw2.dnndev.me/API/2sxc/app/auto/live/api/simple/hello'.","MessageDetail":"No controller was created to handle this request."}

Expected result

This should work

Additional context

The solution is fairly simple, I believe @ahoefling should be able to confirm this.

Affected version

  • 9.4.1 nightly build
  • 9.4.0 latest supported release
  • 9.2 (not affected)

Affected browser

  • all

Solution

The solution is to correct the code in the DnnHttpControllerActivator in DotNetNuke.Web. Here’s the fix:

using DotNetNuke.Common;
using System;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using Microsoft.Extensions.DependencyInjection;

namespace DotNetNuke.Web.Api
{
    public class DnnHttpControllerActivator : IHttpControllerActivator
    {
        public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
        {
            // first try to just get it from the DI - if it's there
            return (IHttpController) Globals.DependencyProvider.GetService(controllerType) ??
                   // If it's not found (null), then it's probably a dynamically compiled type from a .cs file or similar
                   // Such types are never registered in the DI catalog, as they may change on-the-fly.
                   // In this case we must use ActivatorUtilities, which will create the object and if it expects 
                   // any DI parameters, they will come from the DependencyInjection as should be best practice
                   (IHttpController) ActivatorUtilities.CreateInstance(Globals.DependencyProvider, controllerType);
        }
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 11
  • Comments: 19 (14 by maintainers)

Commits related to this issue

Most upvoted comments

@eXistenZe This was in a RC for more than 3 months, and others are already using it, we cannot reverse it at this time

@mitchelsellers & @valadas could you point me in the direction how dynamically compiled webapis would be done according to the mentioned best practices? The solution we had was IMHO best practice and I simply don’t know a better way. Many thanks!

I agree with this decision, 9.4.0 is a feature release and this is a feature that was added with extensive documentation, examples, blog posts, etc. There was a good effort done to verify this was not a breaking change for all the module pipelines and good overall awareness for anyone to point out issue with this before it has been released for 3 months. So at this point in time and because any developer could already be using it, we cannot revert this now.

We are meeting on this later this week, there is a lot more to this than appears.

Also, this was not mentioned at all during the almost 3 months of Release Candidates. But regardless we will address this, in some manner, ASAP.

A short video explaining it more https://www.screencast.com/t/WQibFL6yx4on