3

I used article "Use Dependency Injection In WebForms Application" https://devblogs.microsoft.com/aspnet/use-dependency-injection-in-webforms-application/ The project retargeted to .NET Framework 4.7.2 in project properties and in web.config:

    <system.web>
    <httpRuntime targetFramework="4.72" ...

AspNet.WebFormsDependencyInjection.Unity NuGet package is installed.
Type is registered in Global:

    public class Global : System.Web.HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            var container = this.AddUnity();
            container.RegisterType<IVCRole, eVCRole>();
        }
        ...

I checked container and it is working and registering interface IVCRole mapping to class eVCRole. Default.aspx.cs is refactored:

  public partial class Default : System.Web.UI.Page
  {
    private IVCRole vcr; 
    public Default(IVCRole avcr) 
    { 
      vcr = avcr;
    }   
    protected void Page_Load(object sender, EventArgs e)
    {
    ...

But when I run web application there is an error "Constructor on type 'ASP.default_aspx' not found." If I add this constructor:

  public partial class Default : System.Web.UI.Page
  {
    private IVCRole vcr;
    public Default() {}
    public Default(IVCRole avcr)
    { 
      vcr = avcr;
    }   
    protected void Page_Load(object sender, EventArgs e)
    {
    ...

the constructor for DI

    public Default(IVCRole avcr) 
    { 
      vcr = avcr;
    }

is never called and "vcr" is always null in Page_Load. There is an article: "Dependency Injection in ASP.NET Web Forms": https://makingloops.com/dependency-injection-in-web-forms/ where this error is mentioned: "On occasion you may see a build error complaining about the lack of a zero-argument constructor on the page. I notice that this error will magically go away depending on the context. Someone else suggested using property injection with the Dependency attribute on pages to get around this, but i didn’t find that was necessary." But in my case there is no "magic". There is similar question in Stackoverflow: .NET 4.7.2 Dependency Injection in ASP.NET WebForms Website - Constructor injection not working But in my case property injection is not working:

public partial class Default : System.Web.UI.Page
{
    [Dependency]
    public IVCRole vcr { get; set; }    

    protected void Page_Load(object sender, EventArgs e)
    {
    ...

"vcr" in Page_Load is still null. There is solution to get it working with custom implementation of DI provider but I already using .NET 4.7.2 an Unity. Author mentioned that for web application should not be any problem as the problem is with website compiler. How to get DI constructor or property injection to working in Default page using .NET 4.7.2 and Unity?

This is Stack:

[MissingMethodException: Constructor on type 'ASP.default_aspx' not found.]
   System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark) +1173
   System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) +130
   System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture) +21
   Microsoft.AspNet.WebFormsDependencyInjection.Unity.ContainerServiceProvider.DefaultCreateInstance(Type type) +17
   Microsoft.AspNet.WebFormsDependencyInjection.Unity.ContainerServiceProvider.GetService(Type serviceType) +161
   __ASP.FastObjectFactory_app_web_mmaneivx.Create_ASP_default_aspx() in c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\vs\19e4d468\8c7800a0\App_Web_mmaneivx.2.cs:0
   System.Web.Compilation.BuildResultCompiledType.CreateInstance() +31
   System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(VirtualPath virtualPath, Type requiredBaseType, HttpContext context, Boolean allowCrossApp) +104
   System.Web.UI.PageHandlerFactory.GetHandlerHelper(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath) +33
   System.Web.UI.PageHandlerFactory.GetHandler(HttpContext context, String requestType, String virtualPath, String path) +39
   System.Web.MaterializeHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +386
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +50
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +163
Ildar
  • 93
  • 2
  • 9
  • What NuGet package are you using, exactly? The NuGet packages based on Unity are rather old, have you looked at packages that use `Microsoft.Extensions.DependencyInjection` instead, such as this one ( https://github.com/Jehoel/AspNetDependencyInjection )? (shameless plug: I wrote this one) – Dai Aug 04 '20 at 00:45
  • 1
    Is this a typo in the question or the config file? ` – stuartd Aug 04 '20 at 00:59
  • @Dai, I am using Microsoft.AspNet.WebFormsDependencyInjection.Unity 1.0.0 published June 4 2018. – Ildar Aug 04 '20 at 03:53
  • @stuartd, yes it was type in my web.config but after fixing it to 4.7.2 it still not working. – Ildar Aug 04 '20 at 03:58

4 Answers4

3

Disclaimer: I maintain this NuGet package and project that use Microsoft.Extensions.DependencyInjection for ASP.NET WebForms (and MVC, SignalR and WCF) in the .NET Framework 4.7.2 - however the content of this post isn't specific to my implementation of DI for ASP.NET.


  • Check your .csproj:

    • Ensure you're targeting .NET Framework 4.7.2 or later (note that many shared web-hosts - including Azure App Services - may be running older versions of the .NET Framework):

      <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
      
  • Check your web.config

    • Ensure you have <system.web><compilation targetFramework="4.7.2">
    • Ensure you have <system.web><httpRuntime targetFramework="4.7.2"/>
    • If you have <assemblies><clear /> ensure you have <add assembly="*"/> after the <clear /> or otherwise ensure you're explicitly listing all required assemblies in <add /> elements.
  • Your ConfigureServices method (or anything that configures DI) must run before Global.asax's Application_Start!

    • Currently your code is instantiating the Unity container as a local inside Application_Start - this is a bad idea (as you aren't preserving a strong-reference in a field - a bug elsewhere could cause the GC to collect your DI container, which would be a bad thing.

    • You also need to add a IHttpModule to support scoped DI containers (my package does this for you already).

    • This is done by using the PreApplicationStartMethod attribute (from WebActivatorEx.

      • Note that PreApplicationStartMethod is not the same as OWIN's [assembly: Microsoft.Owin.OwinStartup() attribute! Your project may need to use both if you're using DI with SignalR.
      • Your Startup class code should look like this:
      [assembly: PreApplicationStartMethod ( typeof( global::MyProject.RssStartup ), methodName: nameof( global::MyProject.MyStartup.OnPreStart ) )]
      
      namespace MyProject
      {
          internal static class MyStartup
          {
              internal static void OnPreStart()
              {
                  // Set-up your DI system here and then call your `ConfigureServices` method before this method returns.
              }
          }
      }
      
Dai
  • 141,631
  • 28
  • 261
  • 374
  • .csproj: v4.7.2 web.config: . I do not know what you are talking about "Your ConfigureServices method (or anything that configures DI)" - I do not have anything else what I put in my question. That is exactly how it instructed in my first link to Microsoft. Where should I put "PreApplicationStartMethod"? What StartUp class do you mean? Is it Global or Page class? – Ildar Aug 04 '20 at 03:50
  • about your disclaimer. I am in process of moving this web application to MVC Core. So your NuGet package and project may me related to extended form of this question. – Ildar Aug 04 '20 at 05:21
  • 1
    Dai, Thanks for this. In my case adding `targetFramework` to `` fixed it. All the other criteria you listed were already in place. I can use ctor injection in WebForms now. – Ken Hadden May 12 '21 at 23:19
2

I had exactly the same problem (exception MissingMethodException: Constructor on type 'ASP.*my_page*_aspx' not found.) and it turned out that there was error in creating inner dependency.

I mean, I had:

public class Global :  System.Web.HttpApplication
{
    private IUnityContainer container;

    protected void Application_Start(object sender, EventArgs e)
    {
        container = this.AddUnity();

        container.RegisterType<IDataStorage>(
            new InjectionFactory(c => DataStorageBuilder.GetDefaultStorage()));

        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

and Page:

public partial class Contact : System.Web.UI.Page
{
    private IDataStorage storage { get; set; }

    public Contact(IDataStorage storage)
    {
        this.storage = storage;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        storage.DoRequest();
    }
}

And DataStorageBuilder.GetDefaultStorage() actually threw exception, which Unity wrapped in Constructor on type 'ASP.contact_aspx' not found.

So maybe, you need to check that container can correctly create all inner dependencies of page (in your example it is eVCRole).

  • Thank you! Turned on "Common Language Runtime" exceptions in Exception Settings and there it was:- a failure to create an inner exception. – Warren Feb 17 '22 at 11:09
1

For me the solution was to remove optimizeCompilations="true" from:

<system.web>
    <compilation debug="true" targetFramework="4.8" optimizeCompilations="true">
    </compilation>
</system.web>

in Web.Config

ThomasH
  • 526
  • 2
  • 8
0

I had a very similar issue as the above answer by Света Нестерова https://stackoverflow.com/a/65205408/6901318

One of the dependencies I was trying to register was from an internally maintained Nuget package.

For whatever reason, it is not able to register the type when it is defined in a dll like that. I have done this with .Net Core and it works fine. I am assuming that those references have not been resolved at this point in the application startup. I could be wrong though. It is just a guess, if anyone knows please comment on it.

I ended up making an empty class that inherited from the class I wanted to inject. And, that also implemented the interface that was defined in the NuGet package.

public interface IADAuthenticationManager: IADManager
{

}

IADAuthenticationManager is the wrapper interface and IADManager is the interface defined in the package.

public class ADAuthenticationManager: ADManager, IADAuthenticationManager
{
    public ADAuthenticationManager(IADProvider aDProvider, IErrorLogger logger) : 
    base(aDProvider, logger)
    {
    }
}

ADAuthenticationManager is the wrapper class. ADManager is the class that implements IADManager and is also defined in the NuGet package. IADAuthenticationManager is the wrapper interface from above.

In my Global.asax.cs

protected void Application_Start(object sender, EventArgs e)
    {
        ...            
        var container = this.AddUnity();
        ...
        container.RegisterType<IADManager, ADAuthenticationManager>();
        container.RegisterType<IADAuthenticationManager, ADAuthenticationManager>();
    }

The classes in the NuGet package also had some dependencies that needed wrapper classes created as well. It was a process. But, everything is working now.

LazyDog
  • 317
  • 4
  • 5