从MVC的DependencyResolver过渡到AutofacWebApiDependencyResolver – 哪里是.Current?
我让AutoFac与MVC4一起正常工作。 我正在尝试过渡到Web API 2.这是我设置AutoFac所得到的:
public class AutofacRegistrations { public static void RegisterAndSetResolver() { // Create the container builder. var containerBuilder = new ContainerBuilder(); // Register the Web API controllers. containerBuilder.RegisterApiControllers(Assembly.GetExecutingAssembly()); // Only generate one SessionFactory ever because it is expensive. containerBuilder.Register(x => new NHibernateConfiguration().Configure().BuildSessionFactory()).SingleInstance(); // Everything else wants an instance of Session per HTTP request, so indicate that: containerBuilder.Register(x => x.Resolve().OpenSession()).InstancePerApiRequest(); containerBuilder.Register(x => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)).InstancePerApiRequest(); containerBuilder.RegisterType().As().InstancePerApiRequest(); containerBuilder.RegisterType().As().InstancePerApiRequest(); // Build the container. ILifetimeScope container = containerBuilder.Build(); // Create the depenedency resolver. var dependencyResolver = new AutofacWebApiDependencyResolver(container); // Configure Web API with the dependency resolver. GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver; } }
我非常有信心所有这一切都是正确的。 当我试图设置一些测试用例时,我的问题出现了。 我的测试用例的基类不是控制器,因此它不会自动传递任何东西。 在MVC4中,我做了以下事情:
[SetUp] public void SetUp() { HttpSimulator = new HttpSimulator().SimulateRequest(); Logger = DependencyResolver.Current.GetService(); DaoFactory = DependencyResolver.Current.GetService(); Session = DependencyResolver.Current.GetService(); ManagerFactory = DependencyResolver.Current.GetService(); } [TearDown] public void TearDown() { HttpSimulator.Dispose(); }
不幸的是,WebAPI中没有DependencyResolver.Current 。 所以我想知道如何正确地做到这一点?
这构建,但不正确。 我收到了“会话已关闭!”的消息。 当我尝试执行测试用例时:
[SetUp] public void SetUp() { using (var scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope()) { // TODO: Consider initializing Helpers during setup to keep this DRY. Logger = (ILog)scope.GetService(typeof(ILog)); DaoFactory = (IDaoFactory)scope.GetService(typeof(IDaoFactory)); Session = (ISession)scope.GetService(typeof(ISession)); ManagerFactory = (IManagerFactory)scope.GetService(typeof(IManagerFactory)); } }
使用WebAPI,您不需要访问当前的解析程序,因为当前的依赖项范围通常与入站HttpRequestMessage
一起提供。 该消息也是负责生成新请求范围的消息。
您可以在System.Net.Http.HttpRequestMessageExtensions.GetDependencyScope
方法中查看此代码。
您在WebAPI中会注意到的一件大事是, 您实际上并不需要在全局静态值中设置任何内容 – 也就是说,您不需要设置全局配置/解析器,因为现在所有内容都是基于实例的。
对于测试,这意味着:
- 您的设置将创建一个带有相应依赖项解析器和配置的
HttpRequestMessage
。 - 你的拆解将处理
HttpRequestMessage
,而HttpRequestMessage
将依次处理依赖范围等。 - 如果他们需要手动解析某些内容并且请求消息将用于协调/传递范围,则各个测试将使用
HttpRequestMessage.GetDependencyScope()
。
以更具体的方式,它可能看起来像:
private HttpRequestMessage _request; [SetUp] public void SetUp() { var builder = new ContainerBuilder(); // Register stuff. var container = builder.Build(); var resolver = new AutofacWebApiDependencyResolver(container); var config = new HttpConfiguration(); config.DependencyResolver = resolver; config.EnsureInitialized(); this._request = new HttpRequestMessage(); this._request.SetConfiguration(config); } [TearDown] public void TearDown() { this._request.Dispose(); } [Test] public void Test() { // When you need to resolve something, use the request message this._request.GetDependencyScope().GetService(typeof(TheThing)); }
这样做的好处是你不必在每次测试后都使用全局配置设置或重置静态值。
您可能想知道为什么要传递整个请求消息而不仅仅是依赖解析器 – 原因是请求消息是协调和控制依赖范围的生命周期的原因。 否则,当您多次调用GetDependencyScope
时,您将获得多个不同的范围,而不是您期望的范围。
从设计角度考虑的一些事项:
- 您可能希望将事物的实际注册放入Autofac模块中,以便可以在两个测试和
RegisterAndSetResolver
方法中重用它,而不必担心全局静态被篡改。 - 您可以考虑在
HttpConfiguration
对象上设置解析器而不是RegisterAndSetResolver
来修改全局静态配置, 该对象在 WebAPI为您提供的WebApiConfig.Register
方法中连接。 将HttpConfiguration
对象作为参数并在其上设置解析器而不是全局。 - 如果您在unit testing中对所有内容进行了每次注册,那么您的unit testing可能更接近“集成测试”。 您可能会考虑仅查看您正在测试的内容所需的内容,并使用模拟框架来注册存根,而不是实际注册大量的“真实内容”。
无论如何, HttpRequestMessage
是WebAPI的方法。