2013-02-13 98 views
1

我正在使用Mvc3和Unity.Mvc3来构建可测试和解耦的站点,但我显然做错了事情。Unity无法解析Session_Start中的接口并解决错误的DbContext

在我Application_Start()我注册的依赖:

// container is a property of the MvcApplication 
// and the HierarchicalLifetimeManager should make sure that the registrations 
// only last for this request (or should it?) 
_container.Register<Interface, Class>(new HierarchicalLifetimeManager()) 

然后在Session_Start()我试图解决我的依赖将一些数据保存到会话:

var obj = _container.Resolve<Interface>(); 

在这一点上,我得到一个例外说Unity不能解析一个接口,但我认为我为那个接口注册了一个类?

我很茫然,而且越来越难找到解决方案。

编辑:

这里是我的全部代码,一些不必要的部分排除在外:

public class MvcApplication : System.Web.HttpApplication 
{ 
    // as EDIT 2 says, this is wrong... 
    //private IUnityContainer _container = new UnityContainer(); 

    protected void Application_Start() 
    { 
     // mvc stuff, routes, areas and whatnot 

     // create container here and it works, almost 
     var container = new UnityContainer(); 

     // register dependencies    
     string connectionString = "String from config"; 
     container.RegisterInstance<DbContext>(new CustomContext(connectionString), new HierarchicalLifetimeManager()) 
       .RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager()) 
       .RegisterType(typeof(IRepository<>), typeof(Repository<>), new HierarchicalLifetimeManager()); 

     // register controller resolver 
     DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 

     // if i try to resolve repos here, it works and they all have the same context 
     // just like the unit of work 
    } 

    protected void Session_Start() 
    { 
     // here the container complains that it can't resolve the interface 

     // wrong 
     //var userRepo = _container.Resolve<IRepository<User>>(); 

     // right, but still failes, because it is resolving DbContext 
     // instead of using the CustomContext instance 
     var userRepo = DependencyResolver.Current.GetService<IRepository<User>>(); 

     // save some user data to session   
    } 
} 


public class SampleController : Controller { 

    // here the container tries to resolve the System.Data.Entity.DbContext 
    // instead of just giving the repo that instance that I registered 
    public SampleController(IRepository<Entity> repo) { 
    } 

} 

我明明在这个单位-的工作,依赖注入的东西惨遭失败,和最糟糕的部分是,我不知道为什么... 所以请在我开始拔牙之前帮忙。

编辑2:

晴那里。如果我像上面那样创建容器,则在Session_Start()中失败。如果我将它作为局部变量在Application_Start()中创建,并使用DependencyResolver,则它可以工作。如何和为什么,击败我?

但它仍然试图解决DbContext而不是CustomContext实例。

SOLUTION:

好了,所以这里的交易:如在编辑2所描述的,利用本地容器变量解决了

问题1)访问容器中Session_Start() ,并通过DependencyResolver作品访问容器。

问题2)解决注册分贝上下文实例:

事实证明,注册一个实例不起作用。 这确实不过:

container.RegisterType<DbContext, CustomContext>(null, new HierarchicalLifetimeManager(), new InjectionConstructor(connectionString)) 

但我真的不觉得满意,因为我还没有搞清楚为什么这是这样工作的。看起来我需要长时间阅读一本书或一次。

非常感谢提前。

+0

你从哪里得到_container? – drch 2013-02-13 19:13:27

+0

我在MvcApplication类中创建一个实例,'private IUnityContainer _container = new UnityContainer();' – Pinetree 2013-02-13 19:15:12

回答

1

的问题是你使用RegisterInstanceHierarchecalLifetimeManager。我猜你试图为每个请求获取一个新实例,因为Unity.Mvc3项目使用该LifetimeManager来处理这个魔法(以及HttpModules来管理子容器的创建和销毁)。

问题是,随着新的请求进入,它将要构建一个新的对象,但不知道如何;您只需在应用程序启动时注册一次实例,而不是创建对象的方法。所以你需要使用RegisterType()来工作。

你有两个选择:RegisterType<DbContext, CustomContext>(new HierarchecalLifetimeManager(), new InjectionConstructor(connectionString))

  • 使用工厂:Container.RegisterType<DbContext>(new InjectionFactory(c => new CustomContext(connectionString)), new HierarcicalLifetimeManager())inspired by this

  • *注:参数顺序

    1. 使用InjectionConstructor指定注入价值可能是错的。

      如果你想为你的整个应用程序使用一个真正的单例实例,请使用ContainerControlledLifetimeManager()(这实际上是RegisterInstance的默认值,所以你甚至不需要指定它)。但是随着网站的使用,你的DbContext会变得相当庞大。

      此外,您的初始问题没有在在session_start()注册的项目:

      ASP.NET保持的HttpApplication类的游泳池。这意味着如果你将Unity容器变成一个成员变量,你将有几个实例都有自己的注册。 Application_Start()仅被调用一次,而Session_Start()可以使用不带注册的不同实例来调用。你需要使用一个静态变量来解决这个问题(这是你最终用DependencyResolver做的)。

    +0

    其实,1)中的注册是我以后试过的,它的工作原理。我只是把错误的代码片段放在我的问题编辑中(到那时真的很晚)。 但是,感谢您对正在发生的事情的解释。 – Pinetree 2013-02-14 10:03:46

    1

    不是直接访问容器(它不是从您的问与答清楚从哪里得到的参考容器?),为什么不让MVC依赖解析器解决呢?

    设置的依赖解析器(的Application_Start()):

    DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 
    

    解决您的界面(在session_start()):

    var obj = DependencyResolver.Current.GetService<IMyInterface>(); 
    
    +0

    我实际上使用UnityDependencyResolver。我会看看是否在Session_Start中使用它。但这很奇怪,因为它只是代表了我在问题中所做的。 – Pinetree 2013-02-13 20:15:32

    +0

    它有点工作,所以+1,但有一些其他的修改......我还没有那里.. – Pinetree 2013-02-13 20:54:26

    +0

    我接受这个,因为它确实带领我的解决方案,但对任何有类似问题的人来说,首先阅读全部内容... – Pinetree 2013-02-13 21:45:01

    相关问题