Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带有IoC容器的C#ASP.NET依赖项注入_C#_Dependency Injection_Ioc Container - Fatal编程技术网

带有IoC容器的C#ASP.NET依赖项注入

带有IoC容器的C#ASP.NET依赖项注入,c#,dependency-injection,ioc-container,C#,Dependency Injection,Ioc Container,我很抱歉这么长时间,我知道有一些答案,但我搜索了很多,没有找到正确的解决方案, 所以请容忍我 我正在尝试为遗留应用程序创建一个框架,以便在ASP.NET webforms中使用DI。我可能会使用温莎城堡 作为框架 这些遗留应用程序在某些地方将部分使用MVP模式 演示者的外观如下所示: class Presenter1 { public Presenter1(IView1 view, IRepository<User> userRepository)

我很抱歉这么长时间,我知道有一些答案,但我搜索了很多,没有找到正确的解决方案, 所以请容忍我

我正在尝试为遗留应用程序创建一个框架,以便在ASP.NET webforms中使用DI。我可能会使用温莎城堡 作为框架

这些遗留应用程序在某些地方将部分使用MVP模式

演示者的外观如下所示:

class Presenter1
{
    public Presenter1(IView1 view, 
        IRepository<User> userRepository)
    {
    }
}
public partial class MyPage1 : System.Web.UI.Page, IView1
{
    private Presenter1 _presenter;
}
public Presenter1 Presenter { get; set; }

public MyPage1() 
{
    ObjectFactory.BuildUp(this);
    this.Presenter.View = this;
}
在使用DI之前,我会在页面的OnInit中实例化演示者,如下所示:

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    _presenter = new Presenter1(this, new UserRepository(new SqlDataContext()));
}
private  void InjectDependencies(object page)
{
    Type pageType = page.GetType().BaseType;
    // hack
    foreach (var intf in pageType.GetInterfaces())
    {
        if (typeof(IView).IsAssignableFrom(intf))
        {
            _container.Bind(intf, () => page); 
        }
    }

    // injectDependencies to page...    
} 
所以现在我想使用DI

首先,我必须创建一个处理程序工厂来覆盖页面的构造。 我发现这个答案很有帮助:

现在,我可以按照Mark Seeman建议使用Global.asax在我的合成根目录中轻松设置容器 (这意味着创建一个静态容器,该容器必须是线程安全且密封的,才能添加进一步的注册)

现在我可以在页面上声明构造函数注入了

public MyPage1() : base()
{
}

public MyPage1(Presenter1 presenter) : this()
{
    this._presenter =  presenter;
}
现在我们遇到第一个问题,我有一个循环依赖。 Presenter1依赖于IView1,但页面依赖于presenter

我知道现在有人会说,当你有循环依赖时,设计可能是不正确的。 首先,我不认为Presenter的设计是错误的,因为它将构造函数中的依赖项带到了视图中,我可以这么说 通过查看大量的MVP实现

有些人可能建议将页面更改为Presenter1成为属性的设计,然后使用属性注入

public partial class MyPage1 : System.Web.UI.Page, IView1
{
    [Dependency]
    public Presenter1 Presenter
    {
        get; set;
    }
}
有些人甚至建议完全删除对presenter的依赖,然后通过一系列事件简单地连接起来,但这是错误的 这不是我想要的设计,坦率地说,我不明白为什么我需要做出这样的改变来适应它

无论如何,不管建议如何,都存在另一个问题:

当处理程序工厂收到页面请求时,只有一个类型可用(而不是视图界面):

现在,使用这种类型,您可以通过IoC及其依赖项解析页面:

container.Resolve(pageType)
class Presenter1Factory : IPresenter1Factory 
{
    public Presenter1Factory(Container container)
    {
        this._container = container;
    }
    public Presenter1 Create(IView1 view)
    {
        return new Presenter1(view, _container.Resolve<IUserRepository>,...)
    }
}
这将知道有一个名为Presenter1的属性,并能够将其注入。 但是Presenter1需要IView1,但我们从未通过容器解析IView1,因此容器不会知道 为了提供具体实例,处理程序工厂刚刚创建,因为它是在容器外部创建的

因此,我们需要破解处理程序工厂并替换视图界面: 因此,处理程序工厂解析页面的位置:

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    _presenter = new Presenter1(this, new UserRepository(new SqlDataContext()));
}
private  void InjectDependencies(object page)
{
    Type pageType = page.GetType().BaseType;
    // hack
    foreach (var intf in pageType.GetInterfaces())
    {
        if (typeof(IView).IsAssignableFrom(intf))
        {
            _container.Bind(intf, () => page); 
        }
    }

    // injectDependencies to page...    
} 
这带来了另一个问题,像Castle Windsor这样的大多数容器都不允许您重新注册此接口 指向它现在指向的实例。此外,由于容器已在Global.asax中注册,因此 此时,容器应为只读

另一种解决方案是创建一个函数,在每个web请求上重建容器,然后检查以查看 如果容器包含组件IView,则设置实例。但这似乎是浪费,与建议的用途背道而驰

另一个解决方案是创建一个名为 IPresenterFactory并将依赖项放入页面构造函数中:

public MyPage1(IPresenter1Factory factory) : this()
{
    this._presenter = factory.Create(this);
}
问题是您现在需要为每个演示者创建一个工厂,然后调用容器 要解决其他依赖项,请执行以下操作:

container.Resolve(pageType)
class Presenter1Factory : IPresenter1Factory 
{
    public Presenter1Factory(Container container)
    {
        this._container = container;
    }
    public Presenter1 Create(IView1 view)
    {
        return new Presenter1(view, _container.Resolve<IUserRepository>,...)
    }
}
class Presenter1工厂:iPresenter1工厂
{
公共演示者1工厂(容器)
{
这个._容器=容器;
}
公共演示者1创建(IView1视图)
{
返回新的Presenter1(视图,_container.Resolve,…)
}
}

这个设计看起来也很麻烦和复杂,有没有人有更优雅的解决方案的想法?

也许我误解了你的问题,但解决方案对我来说似乎相当简单:将
IView
升级到
Presenter1
上的属性:

class Presenter1
{
    public Presenter1(IRepository<User> userRepository)
    {
    }

    public IView1 View { get; set; }            
}
或者,在没有属性注入的情况下,您可以按如下方式执行:

private Presenter1 _presenter;

public MyPage1() 
{
    this._presenter = ObjectFactory.Resolve<Presenter1>();
    this._presenter.View = this;
}
私人演讲者1\u演讲者;
公共MyPage1()
{
这是。_presenter=ObjectFactory.Resolve();
this.\u presenter.View=此;
}
类和用户控件中的构造函数注入将永远不会真正起作用。您可以让它在完全信任()的情况下工作,但在部分信任的情况下会失败。因此,您必须为此调用容器


所有DI容器都是线程安全的,只要在初始化阶段之后您自己不手动添加注册,并且使用一些线程安全的容器(甚至禁止在初始化之后注册类型)。永远不需要这样做(除了大多数容器支持的未注册类型解析)。但是,使用Castle时,您需要预先注册所有具体类型,这意味着在解析它之前,它需要了解您的
Presenter1
。注册此项,更改此行为,或者移动到默认情况下允许解析具体类型的容器。

也许我误解了您的问题,但解决方案对我来说相当简单:将
IView
升级到
Presenter1
上的属性:

class Presenter1
{
    public Presenter1(IRepository<User> userRepository)
    {
    }

    public IView1 View { get; set; }            
}
或者,在没有属性注入的情况下,您可以按如下方式执行:

private Presenter1 _presenter;

public MyPage1() 
{
    this._presenter = ObjectFactory.Resolve<Presenter1>();
    this._presenter.View = this;
}
私人演讲者1\u演讲者;
公共MyPage1()
{
这是。_presenter=ObjectFactory.Resolve();
this.\u presenter.View=此;
}
类和用户控件中的构造函数注入将永远不会真正起作用。您可以让它在完全信任()的情况下工作,但在部分信任的情况下会失败。因此,您必须为此调用容器

所有DI容器都是线程安全的,只要在初始化阶段之后您自己不手动添加注册,并且使用一些线程安全的容器(甚至禁止在初始化之后注册类型)。永远不需要这样做(除了大多数容器支持的未注册类型解析)。然而,对于Castle,您需要注册所有具体类型的upf