ASP.NET WebForms 网站中的 .NET 4.7.2 依赖注入 - 构造函数注入不起作用 [英] .NET 4.7.2 Dependency Injection in ASP.NET WebForms Website - Constructor injection not working

查看:23
本文介绍了ASP.NET WebForms 网站中的 .NET 4.7.2 依赖注入 - 构造函数注入不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

它目前的目标是 .NET 4.7.2:

<httpRuntime targetFramework="4.7.2"/>

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

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

公共接口 IDependencyTest{字符串 GetName();}公共类 DependencyTest : IDependencyTest{公共字符串 GetName(){return "Mwuhahaha!!!";}}

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

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

所需的命名空间已导入:

<%@Import Namespace="Microsoft.AspNet.WebFormsDependencyInjection.Unity" %><%@ 导入命名空间="Unity" %>

创建了一个测试页面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="服务器"><title></title><身体><form id="form1" runat="server"><div><asp:Label ID="lblDisplay" runat="server" Text="运气不好..."></asp:Label>

</表单>

后面有以下代码:

公共部分类 Teste : System.Web.UI.Page{私人 IDependencyTest _dependencyTest;公共测试(IDependencyTestdependencyTest){_dependencyTest =dependencyTest;}protected void Page_Load(object sender, EventArgs e){lblDisplay.Text = _dependencyTest.GetName();}}

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

C:WindowsMicrosoft.NETFramework64v4.0.30319Temporary ASP.NET Files
oot7a04dd7281815e95App_Web_teste.aspx.cdcab7d2.rtms4_ja.0.cs(187): 错误 CS7036: 没有给出对应于Teste.Teste(IDependencyTest)"所需形式参数dependencyTest"的参数

然而,属性注入确实有效:

使用 Unity.Attributes;公共部分类 Teste : System.Web.UI.Page{[依赖]公共 IDependencyTest DependencyTest { 获取;放;}protected void Page_Load(object sender, EventArgs e){lblDisplay.Text = DependencyTest.GetName();}}

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

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

是因为它是一个 ASP.NET 网站而不是一个 ASP.NET Web 应用程序吗?

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

解决方案

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

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

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

error CS7036:没有给出对应于Teste.Teste(IDependencyTest)"所需形式参数dependencyTest"的参数

<小时>

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

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 框架,例如团结,Ninject.以下示例演示了通过构造函数注入 ILog 对象.

公共类 SimpleActivator : IServiceProvider{公共对象 GetService(类型 serviceType){var ctors = serviceType.GetConstructors();构造函数信息 targetCtor = null;foreach(ctors 中的 var c){var 参数 = c.GetParameters();if (parameters.Count() == 1 && parameters[0].ParameterType == typeof(ILog)){targetCtor = c;休息;}}if(targetCtor != null){返回 targetCtor.Invoke(new object[] { new DebuggingLoger() });}别的{返回 Activator.CreateInstance(服务类型,BindingFlags.Instance |BindingFlags.NonPublic |BindingFlags.Public |BindingFlags.CreateInstance,空值,空值,空值);}}}

<块引用>

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

公共类全局:System.Web.HttpApplication{公共覆盖无效初始化(){HttpRuntime.WebObjectActivator = new SimpleActivator();基地.Init();}}

<块引用>

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

 公共部分类 WebForm2 : System.Web.UI.Page{私人 ILog _log;公共 WebForm2(ILog l){_log = l;}}

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

<小时>

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

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:WindowsMicrosoft.NETFramework64v4.0.30319Temporary ASP.NET Files
oot7a04dd7281815e95App_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();
    }    
}

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?

解决方案

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.

这篇关于ASP.NET WebForms 网站中的 .NET 4.7.2 依赖注入 - 构造函数注入不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆