ASP.NET WebForms 网站中的 .NET 4.7.2 依赖注入 - 构造函数注入不起作用

Mih*_*tea 11 .net c# asp.net dependency-injection webforms

我们目前正在处理一个较旧的项目(ASP.NET Web 窗体网站)并尝试查看是否可以为其设置依赖项注入。

需要强调的是:这不是一个 Web 应用程序项目......它是旧类型的网站。

它目前的目标是 .NET 4.7.2:

<httpRuntime targetFramework="4.7.2" />
Run Code Online (Sandbox Code Playgroud)

到目前为止,我们已经包含了 NuGet 包:

<package id="Microsoft.AspNet.WebFormsDependencyInjection.Unity" version="1.0.0" targetFramework="net472" />
Run Code Online (Sandbox Code Playgroud)

定义了一些虚拟接口和实现:

public interface IDependencyTest
{
    string GetName();
}

public class DependencyTest : IDependencyTest
{
    public string GetName()
    {
        return "Mwuhahaha!!!";
    }
}
Run Code Online (Sandbox Code Playgroud)

并在 global.asax 中的 Application_Start 事件处理程序中连接 DI 容器:

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

    container.RegisterType<IDependencyTest, DependencyTest>();
}
Run Code Online (Sandbox Code Playgroud)

导入了所需的命名空间:

<%@ Import Namespace="Microsoft.AspNet.WebFormsDependencyInjection.Unity" %>
<%@ Import Namespace="Unity" %>
Run Code Online (Sandbox Code Playgroud)

创建了一个测试页面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>
Run Code Online (Sandbox Code Playgroud)

后面有以下代码:

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();
    }    
}
Run Code Online (Sandbox Code Playgroud)

所有这些设置都将失败,但出现以下异常:

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)'
Run Code Online (Sandbox Code Playgroud)

但是,属性注入确实有效:

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();
    }    
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

老实说,我真的很想使用构造函数注入...

为什么它不适用于我们当前的设置?

是因为它是 ASP.NET 网站而不是 ASP.NET WebApplication 吗?

有什么办法可以让它在这里工作吗?

Lut*_*lho 11

为什么它不适用于我们当前的设置?

Asp.Net WebForms 的默认配置 System.Web.UI.Page 需要一个无参数构造函数来实例化页面并启动页面生命周期

这就是尝试使用构造函数依赖注入时出现此错误的原因。

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

有什么办法可以让它在这里工作吗?

Asp.Net WebForms 的依赖注入(DI)在 WebForms 的黄金时代并不是很常见,所以很难在官方文档中找到一些东西。

在 StackOverflow 和 Google 上进行了一些搜索后,我找到了一些可以帮助您解决问题的有用信息。


直到 4.7.2 版,Asp.Net WebForms 才很好地支持 DI

因此,如果您使用的是 4.7.2 之前的版本,并且无法更新到较新的版本,则需要使用PageHandlerFactory. 由于我从未尝试过,因此我更愿意为您提供我找到的两个参考文献的链接。

当PageHandlerFactory和IHttpHandlerFactory存在时,为什么每个人都说ASP.NET webforms中的依赖注入很难?

ASP.NET Web 窗体中的依赖注入


如果您使用比 4.7.2 更新的版本,或者您可以更改到此版本。您可以使用 WebForms 更好地支持 DI。

步骤 1 – 实施 IServiceProvider。您可以在其中实现自己的 DI 逻辑或插入另一个 DI 框架,例如 Unity、Ninject。以下示例演示如何通过构造函数注入 ILog 对象。

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

步骤 2 – 在 Global.asax 中设置 WebObjectActivator。

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

        base.Init();
    }
}
Run Code Online (Sandbox Code Playgroud)

第 3 步 – 在您的 Web 表单页面中使用依赖注入。

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

    public WebForm2(ILog l)
    {
        _log = l;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在此链接中查看此示例以及有关它的更多信息:https ://devblogs.microsoft.com/dotnet/annoucing-the-net-framework-4-7-2/


在我看来,如果您可以迁移到较新版本的 .NetFramework,您应该尝试实现IServiceProvider. 如果你不能,那么你应该分析实施是否PageHandlerFactory会在未来为你节省更多的时间而不是你将花费的时间来实施它。如果它不会在将来为您节省任何时间,您可以继续进行 [Dependency]财产注入。