【问题标题】:Why does IoC has influence on Controller creation and how to fix that?为什么 IoC 会影响控制器的创建以及如何解决这个问题?
【发布时间】:2013-03-19 11:17:20
【问题描述】:

我的 ASP .NET MVC 应用程序中有一个奇怪的问题。我有一些控制器和一些IHelper,它是这个控制器的实现Helper。当我像下面这样使用这个助手时:

public ActionResult SomeAction()
{
    var hepler = new Helper();
    helper.DoStuff();
    ...
}

一切正常。但是当我尝试将此帮助器作为控制器的属性注入时:

public IHelper Helper { private get; set; }
...    
public ActionResult SomeAction()
    {            
        Helper.DoStuff();
        ...
    }

在我的 IoC 配置类中,我有:

ObjectFactory.Initialize(x =>
          {
              // Helpers
              x.For<IHelper>().Use<Helper>();              
              ...
              x.FillAllPropertiesOfType<IHelper>().Use<Helper>();
              ...
          }

问题是我在 IoC 配置类中使用 IoC 模式初始化了许多不同的助手、管理器、存储库和其他东西,并成功注入到我的每个控制器中。但是当我尝试注入这个 Helper 我得到:

InvalidOperationException: An error occurred when trying to create a controller of type 'MyController'. Make sure that the controller has a parameterless public constructor.

我知道问题出在 IoC 和这个 Helper 中,因为我搜索了 this,从 IoC 配置类中删除了 Helper,像 var hepler = new Helper(); 一样使用它,一切正常。但我不明白问题出在哪里?以前有人见过这样的问题吗?我什至无法理解 确保控制器具有无参数的公共构造函数控制器属性之一的 IoC 初始化如何关联,当一切都对另一个助手很好时,等等

编辑
附言我正在使用 StructureMap IoC 框架和 ASP .NET MVC 4.0。

【问题讨论】:

  • 提及您正在使用 StructureMap 可能会有所帮助。
  • 不确定您使用的是哪个 IoC 系统,但您是否尝试过使用 set public 而不是 private
  • 我刚刚也注意到了……而且是 get 是私有的,而不是 set。那还能用吗?由于该属性甚至没有被使用,因此尚不清楚它的意图。
  • @Damien_The_Unbeliever,设置为公开。 Get 是私有的,以使该属性在当前控制器中以只读方式访问。 Set 具有与属性本身相同的访问级别 - public,以使其可用于测试(模拟)和 IoC 框架。
  • 一个属性,其 setter 比它的 getter 具有更高的可见性,这听起来像是一种反模式。改用构造函数参数注入。

标签: c# asp.net-mvc asp.net-mvc-4


【解决方案1】:

对于初学者,您实际上并没有在这里使用依赖注入:

public IHelper Helper { private get; set; }
...    
public ActionResult SomeAction()
{
    var hepler = new Helper();
    helper.DoStuff();
    ...
}

您已经创建了一个IHelper 类型的属性,也许您的 IoC 框架甚至试图用一个实现来填充该属性,但是在您的操作方法中,您仍然只是直接实例化Helper 的实例,而没有使用注入的属性,所以你仍然对Helper 有一个硬依赖而不是IHelper

更重要的是,您遇到的错误很可能取决于您使用的 IoC 框架和您使用的 ASP.NET MVC 版本。 IoC 看起来可能是 StructureMap,是这样吗?对于 MVC,是哪个版本的?

不同版本的 ASP.NET MVC 在其控制器构造函数中处理依赖关系解析的方式不同。例如,在 MVC 4 应用程序中,您可以创建 IDependencyResolver 的实现并将其用于控制​​器。像这样的:

public class DomainDependencyResolver : IDependencyResolver
{
    private readonly IoCContainer Container;

    public DomainDependencyResolver(IoCContainer container)
    {
        Container = container;
    }

    public object GetService(Type serviceType)
    {
        if (serviceType.IsAbstract || serviceType.IsInterface)
            return Container.TryGetInstance(serviceType);
        else
            return Container.GetInstance(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return Container.GetAllInstances()
                        .Where(s => s.GetType() == serviceType);
    }
}

这使用了一个通用的 IoCContainer 实例(类似于 Common Service Locator),但如果您只想直接使用您的 IoC 实现,那可能没问题。主要是实现GetServiceGetServices 以便您的IoC 容器返回任何请求类型的实现。然后,您将设置 ASP.NET MVC 以在应用程序启动时(在 Global.asax.cs 中)对其控制器使用此依赖关系解析器实现:

DependencyResolver.SetResolver(new DomainDependencyResolver(IoCContainerFactory.Current));

您唯一需要更改的是对 IoC 容器的引用。我正在使用我自己的通用版本,它的类型为IoCContainer,并且位于IoCContainerFactory 上名为Current 的静态属性中。您将使用您正在使用的任何框架,因此您只需更改依赖解析器实现的构造函数以匹配您要传递的任何内容。

【讨论】:

  • 没错! ASP.NET MVC 需要一个无参数的构造函数来创建控制器,或者在解析控制器实例时调用 DependencyResolver。另一个为 StructureMap 制作的自定义解析器可以在这个问题中找到:stackoverflow.com/questions/4706776/…
猜你喜欢
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-26
相关资源
最近更新 更多