Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET 4.7.2 Dependency Injection in ASP.NET WebForms Website - Constructor injection not working

We are currently working with an older project (ASP.NET Web Forms Website) and trying to see if we can set up dependency injection for it.

Need to emphasize: this is NOT a Web Application project... it's the older type, the Website.

It is currently targeting .NET 4.7.2:

<httpRuntime targetFramework="4.7.2" />

So far, we've included the NuGet package:

<package id="Microsoft.AspNet.WebFormsDependencyInjection.Unity" version="1.0.0" targetFramework="net472" />

Defined some dummy interface and implementations:

public interface IDependencyTest
{
    string GetName();
}

public class DependencyTest : IDependencyTest
{
    public string GetName()
    {
        return "Mwuhahaha!!!";
    }
}

And wired the DI container in the Application_Start event handler in global.asax:

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

    container.RegisterType<IDependencyTest, DependencyTest>();
}

Required namespaces were imported:

<%@ Import Namespace="Microsoft.AspNet.WebFormsDependencyInjection.Unity" %>
<%@ Import Namespace="Unity" %>

Created a test page Teste.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Teste.aspx.cs" Inherits="Teste" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>    
        <asp:Label ID="lblDisplay" runat="server" Text="No luck..."></asp:Label>    
    </div>
    </form>
</body>
</html>

With the following code behind:

public partial class Teste : System.Web.UI.Page
{
    private IDependencyTest _dependencyTest;

    public Teste(IDependencyTest dependencyTest)
    {
        _dependencyTest = dependencyTest;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        lblDisplay.Text = _dependencyTest.GetName();
    }    
}

All this setup will fail with the following exception:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\7a04dd72\81815e95\App_Web_teste.aspx.cdcab7d2.rtms4_ja.0.cs(187): error CS7036: There is no argument given that corresponds to the required formal parameter 'dependencyTest' of 'Teste.Teste(IDependencyTest)'

However, property injection does work:

using Unity.Attributes;

public partial class Teste : System.Web.UI.Page
{
    [Dependency]
    public IDependencyTest DependencyTest { get; set; }    

    protected void Page_Load(object sender, EventArgs e)
    {
        lblDisplay.Text = DependencyTest.GetName();
    }    
}

enter image description here

To be honest, I'd really like to use the constructor injection...

Why isn't it working with our current setup?

Is it because it's a ASP.NET Website and NOT an ASP.NET WebApplication?

Can anything be done to get it working here, also?

like image 428
Mihai Caracostea Avatar asked Dec 04 '19 13:12

Mihai Caracostea


1 Answers

Why isn't it working with our current setup?

The default configuration of Asp.Net WebForms the System.Web.UI.Page requires a parameter less constructor to instantiate your page and start the Page Life Cycle.

Thats the reason you get this error when try to use Constructor Dependency Injection.

error CS7036: There is no argument given that corresponds to the required formal parameter 'dependencyTest' of 'Teste.Teste(IDependencyTest)'

Can anything be done to get it working here, also?

Dependency injection (DI) with Asp.Net WebForms wasn't very commom, on the gold times of WebForms, so is very difficult to find something in the official documentation.

After some searches on StackOverflow and Google I found some useful information that can help you to solve your problem.


DI wans't very well supported in Asp.Net WebForms until version 4.7.2

So if you are using an older version than 4.7.2, and can't update to a newer version, you will need to use PageHandlerFactory. As I never tried this I prefer to give you the links to the two references I found.

Why does everyone say dependency injection in ASP.NET webforms is hard when PageHandlerFactory and IHttpHandlerFactory exist?

Dependency Injection in ASP.NET Web Forms


If you a using a version newer then 4.7.2, or if you can change to this version. You can use WebForms with a better support for DI.

Step 1 – Implement IServiceProvider. You can implement your own DI logic in it or plug in another DI framework, e.g. Unity, Ninject. The following example demonstrates injecting an ILog object through the constructor.

public class SimpleActivator : IServiceProvider
{
    public object GetService(Type serviceType)
    {
        var ctors = serviceType.GetConstructors();
        ConstructorInfo targetCtor = null;
        foreach (var c in ctors)
        {
            var parameters = c.GetParameters();
            if (parameters.Count() == 1 && parameters[0].ParameterType == typeof(ILog))
            {
                targetCtor = c;
                break;
            }
        }

        if(targetCtor != null)
        {
            return targetCtor.Invoke(new object[] { new DebuggingLoger() });
        }
        else
        {
            return Activator.CreateInstance(
            serviceType,
            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance,
            null,
            null,
            null);
        }
    }
}

Step 2 – Set WebObjectActivator in Global.asax.

public class Global : System.Web.HttpApplication
{        
    public override void Init()
    {
        HttpRuntime.WebObjectActivator = new SimpleActivator();

        base.Init();
    }
}

Step 3 – Use Dependency Injection in your Webform page.

public partial class WebForm2 : System.Web.UI.Page
{
    private ILog _log;

    public WebForm2(ILog l)
    {
        _log = l;
    }
}

You can see this examples, and more inflortion about it in this link: https://devblogs.microsoft.com/dotnet/announcing-the-net-framework-4-7-2/


In my opinion if you can move to a newer version of .NetFramework you should try to implement the IServiceProvider. If you can't then you should analyse if the implementation of PageHandlerFactory will save you more time in the future than the time you will expend to implement it. If it will not save you any time in the future you can keep with [Dependency] property injection.

like image 54
Lutti Coelho Avatar answered Oct 03 '22 08:10

Lutti Coelho