我让 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<ISessionFactory>().OpenSession()).InstancePerApiRequest();
containerBuilder.Register(x => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)).InstancePerApiRequest();
containerBuilder.RegisterType<NHibernateDaoFactory>().As<IDaoFactory>().InstancePerApiRequest();
containerBuilder.RegisterType<StreamusManagerFactory>().As<IManagerFactory>().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<ILog>();
DaoFactory = DependencyResolver.Current.GetService<IDaoFactory>();
Session = DependencyResolver.Current.GetService<ISession>();
ManagerFactory = DependencyResolver.Current.GetService<IManagerFactory>();
}
[TearDown]
public void TearDown()
{
HttpSimulator.Dispose();
}
不幸的是,没有DependencyResolver.Current在 WebAPI 中。所以我想知道如何正确地做到这一点?
这可以构建,但不正确。我收到消息“会话已关闭!”当我尝试执行测试用例时:
[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
method.
在 WebAPI 中您会注意到的一件大事是您实际上不需要在全局静态值中设置任何内容- 也就是说,您不需要设置全局配置/解析器,因为现在一切都是基于实例的。
对于测试来说,这意味着:
- 您的设置将创建一个
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
方法,而不必担心全局静态数据被篡改。
- 代替
RegisterAndSetResolver
修改全局静态配置,您可能会考虑只需将解析器设置为HttpConfiguration
连接到其中的对象WebApiConfig.Register
methodWebAPI 为您提供了。采取一个HttpConfiguration
对象作为参数,并在该对象上设置解析器而不是全局的。
- 如果您在单元测试中对所有内容进行每次注册,那么您的单元测试可能更接近“集成测试”。您可能会考虑仅查看您正在测试的内容所需的内容,并且使用模拟框架来注册存根,而不是实际注册大量“真实的东西”。
Anyway, HttpRequestMessage
是 WebAPI 的出路。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)