2012-12-09 49 views
1

我们有一个MVC3控制器,其中有一些'常见'工作,我们将其放入控制器构造函数中。一些常见的工作是通过一个可以通过Unity动态解析(用于IoC /依赖注入)的失败耦合类(例如ourService)完成的。 ourService在Controller的构造函数中为空(即未解析),但在正常的Controller方法中正确解析。下面这个简单的演示代码显示问题:Unity不解决MVC3控制器构造函数中的依赖关系

public class Testing123Controller : BaseController 
{ 
    [Dependency] 
    public IOurService ourService { get; set; } 

    public Testing123Controller() 
    { 
      ourService.SomeWork(1); // ourService=null here !! 
      ... 
    } 

    public ActionResult Index() 
    { 
      ourService.SomeWork(1); // resolved properly here here !! 
      ... 
    } 
    ... 
} 

问题

  1. 为什么会出现在Unity解析行为有何不同?我会期待一致的行为。
  2. 我该如何解决这个问题,即使在控制器的构造器中,Unity也解决了这个问题?

的方式,我们已经建立统一2.0:

的Global.asax

Application_Start() 
{ 
    ... 
    Container = new UnityContainer(); 
    UnityBootstrapper.ConfigureContainer(Container); 
    DependencyResolver.SetResolver(new UnityDependencyResolver(Container)); 
    ... 
} 

public static void ConfigureContainer(UnityContainer container) 
{ 
    ... 
    container.RegisterType<IOurService, OurService>(); 
    ... 
} 

IOurService.cs

public interface IOurService 
{ 
    bool SomeWork(int anInt); 
} 

OurService.cs

public class OurService: IOurService 
{ 
    public bool SomeWork(int anInt) 
    { 
     return ++anInt; //Whew! Time for a break ... 
    } 
} 
+0

好阅读这里:http://www.fascinatedwithsoftware.com/blog/post/2012/02/01/Prefer-Constructor-Injection-Over-Property-Injection.aspx这里有一个很好的解释:http:// stackoverflow.com/questions/11125883/property-dependency-injection-used-in-constructor-using-unity – timothyclifford

回答

5

作为类的基本原理,在可以设置实例属性之前,必须实例化实例。

Unity需要设置依赖项属性,但它不能这样做,直到实例完全实例化 - 即构造函数必须完成执行。

如果您在构造函数中引用了依赖项属性,那么这就太早了 - Unity没有办法设置它 - 因此它将被取消设置(即null)。

如果您需要在构造函数中使用依赖项,那么您的必须使用构造函数注入。虽然在一般情况下,使用构造器注入通常是无论如何更好的方法:

public class Testing123Controller : BaseController 
{ 
    public IOurService ourService { get; set; } 

    public Testing123Controller(IOurService ourService) 
    { 
      this.ourService = ourService; 
      this.ourService.SomeWork(1); // ourService no longer null here 
      ... 
    } 

    public ActionResult Index() 
    { 
      ourService.SomeWork(1); // also resolved properly here 
      ... 
    } 
    ... 
} 

注意:在这个例子中我的情况下,离开ourService作为一个公共gettable &设置属性您的代码的其他部分需要访问它。另一方面,如果它只能在类中访问(并且只是为了Unity的目的而公开),那么随着构造器注入的引入,最好将其设置为private readonly字段。

+0

你能解释一下为什么它应该是一个'field'('private readonly IOurService ourService;')而不是'property'('public IOurService ourService {get;}')?大多数文档(MSDN,论坛)都建议使用字段。同意他们应该被隔离的概念('{get; set;}'是'public'是另一个dev的代码) – DeepSpace101

+0

它真的取决于用法。如果需要公开访问并公开设置,则使用公共“获取”和“设置”访问器的公共属性。如果需要公开访问但只能私人设置,则使用公共“获取”的公共财产,但使用私人“集合”。如果不应该公开访问并需要在类中操作(即设置,读取,更新),请使用私有(非只读)字段。如果不应该公开访问并且只需要私人阅读(在初始设置之后),则使用专用只读字段。 –

+0

但Unity的'[Dependency]'装饰在字段上无效,它需要属性,索引器或参数。如果属性,那么你必须{get; set;},所以我们可以在同一个类的构造函数中设置它 - 只要你的答案。所以我把它改成私有{get; set;} – DeepSpace101

1

您正在使用属性注入(通过使用Dependency属性)而不是构造函数注入,因此只有在控制器实例化之后才解析依赖项。如果你想访问的依赖是构造函数,只需将其添加到构造函数:

private readonly IOurService _ourService { get; set; } 

public Testing123Controller(IOurService ourService) 
{ 
    _ourService = ourService; 
    _ourService.SomeWork(1); // ourService=null here !! 
    ... 
} 
+0

谁会设置传递给控制器​​构造函数的'ourService'? AFAIK,无参数控制器构造函数是从外部MVC框架调用的第一个用户代码。 – DeepSpace101

+0

如果您的UnityDependencyResolver工作正常(您可能会比使用Unity.Mvc3 NuGet包做得更糟),那么当框架试图实例化控制器时,它将确定为了实例化它,需要实现IOurService 。如果IOurService的实现注册到Unity,它将实例化它,然后用它来实例化控制器。 –

0

恐怕团结对构造工作,例如本身必须使用Unity解决。 Service构造函数中的Service属性为null的事实支持此构想。如果你自己调用控制器(不适用于Unity),Unity没有时间解决该属性。

相关问题