问题描述
我AutoFac与MVC4正常工作。我试图转型为网页API 2.以下是我已经有了设立AutoFac:
公共类AutofacRegistrations
{
公共静态无效RegisterAndSetResolver()
{
//创建容器制造商。
VAR containerBuilder =新ContainerBuilder(); //注册的Web API控制器。
containerBuilder.RegisterApiControllers(Assembly.GetExecutingAssembly()); //只产生一个会话工厂以往,因为它是昂贵的。
containerBuilder.Register(X =>新建NHibernateConfiguration()配置()BuildSessionFactory()。)SingleInstance()。 //其他一切希望会议的每个HTTP请求的一个实例,因此表明:
containerBuilder.Register(X => x.Resolve&下; ISessionFactory方式>()的openSession())InstancePerApiRequest();
containerBuilder.Register(X =方式&gt; LogManager.GetLogger(MethodBase.GetCurrentMethod()DeclaringType))。InstancePerApiRequest(); containerBuilder.RegisterType<NHibernateDaoFactory>().As<IDaoFactory>().InstancePerApiRequest();
containerBuilder.RegisterType<StreamusManagerFactory>().As<IManagerFactory>().InstancePerApiRequest(); //构建容器。
ILifetimeScope容器= containerBuilder.Build(); //创建depenedency解析器。
VAR dependencyResolver =新AutofacWebApiDependencyResolver(容器); //配置Web API的依赖解析器。
GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;
}
}
我是pretty相信这一切是正确的。当我试图建立一些测试用例我的问题就出现了。我为我的测试情况下,基类是不是一个控制器,所以它不会自动传递任何东西。在MVC4我做了以下内容:
[设置]
公共无效设置()
{
HttpSimulator =新HttpSimulator()SimulateRequest()。 记录仪= DependencyResolver.Current.GetService&LT;&ILog的GT;();
DaoFactory = DependencyResolver.Current.GetService&LT; IDaoFactory&GT;();
会话= DependencyResolver.Current.GetService&LT;&ISession的GT;();
ManagerFactory = DependencyResolver.Current.GetService&LT; IManagerFactory&GT;();
}[拆除]
公共无效TearDown中的()
{
HttpSimulator.Dispose();
}
不幸的是,没有DependencyResolver.Current在的WebAPI。所以我在想如何正确地做到这一点?
这个版本,但不正确。我收到消息会议闭幕!当我尝试执行测试用例:
[设置]
公共无效设置()
{
使用(VAR范围= GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
{
// TODO:考虑安装过程中初始化助手保持这种干燥。
记录仪=(ILog的)scope.GetService(typeof运算(的ILog));
DaoFactory =(IDaoFactory)scope.GetService(typeof运算(IDaoFactory));
会话=(ISession的)scope.GetService(typeof运算(ISession的));
ManagerFactory =(IManagerFactory)scope.GetService(typeof运算(IManagerFactory));
}
}
使用的WebAPI,你不需要访问当前解析,因为当前的依赖范围一般与入站走来的Htt prequestMessage
。这消息也什么是负责产生了新的要求范围。
您可以看到在 System.Net.Http.Htt prequestMessageExtensions.GetDependencyScope
方法code这一点。
你会注意到的WebAPI一件大事是,您实际上并不需要在全局静态值设置任何东西 - 那就是,你不需要设置一个全局配置/解析器因为一切现在是基于实例的。
有关测试,这是什么意思是:
- 您的安装程序会创建一个
的Htt prequestMessage
与适当的依赖解析器和配置。 - 您拆解将部署的
的Htt prequestMessage
这将反过来,处置的依赖范围,等下了线。 - 个人测试将使用
的Htt prequestMessage.GetDependencyScope()
,如果他们需要做的事情,并请求消息手动分辨率将用于协调/绕过范围。
在一个更具体的方式,它可能是这样的:
私人的Htt prequestMessage _REQUEST;[建立]
公共无效设置()
{
VAR建设者=新ContainerBuilder();
//注册东西。
变种容器= builder.Build();
VAR解析器=新AutofacWebApiDependencyResolver(容器); 无功配置=新HttpConfiguration();
config.DependencyResolver =解析器;
config.EnsureInitialized(); this._request =新的Htt prequestMessage();
this._request.SetConfiguration(配置);
}[拆除]
公共无效TearDown中的()
{
this._request.Dispose();
}[测试]
公共无效测试()
{
//当你需要解决的东西,使用请求消息
。this._request.GetDependencyScope()GetService的(typeof运算(TheThing));
}
什么是关于这个漂亮的是,你不必与全局配置设置或每次测试后重新静态值进行战斗。
您可能会问,为什么你会绕过整个请求消息,而不是仅仅依赖解析器 - 的原因是,请求消息是协调和控制的依赖范围的寿命,否则。 ,当你调用 GetDependencyScope
多次,你会得到多个不同的范围,而不是同一个作为你所期望的。
有些事情从设计的角度考虑:
- 您可能希望把事情的实际注册到Autofac模块这样就可以在两个测试,并在你的
RegisterAndSetResolver
方法被重用而不必担心全球静态越来越篡改。 - 而不是一个
RegisterAndSetResolver
修改全局静态配置,你可能会考虑的只设置解析器上的HttpConfiguration
,获取在WebApiConfig.Register
方法接线对象是的WebAPI给你。以一个HttpConfiguration
对象作为参数,并设置解析器上,而不是全球性的。 - 如果你正在做的一切每登记在单元测试,单元测试可能会更接近集成测试。你可能会考虑在看只有什么需要你在测试和材料的使用模拟框架来登记存根,而不是实际的注册一船真正的东西。
总之,的Htt prequestMessage
是去的WebAPI的方式。
I had AutoFac working properly with MVC4. I'm trying to transition to Web API 2. Here's what I've got for setting up 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;
}
}
I'm pretty confident all of that is correct. My problem arises when I'm trying to setup some test cases. My base class for my test cases isn't a controller so it isn't automatically passed anything. In MVC4 I did the following:
[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();
}
Unfortunately, there's no DependencyResolver.Current in WebAPI. So I'm left wondering how to do this properly?
This builds, but is NOT correct. I received the message "Session Closed!" when I try to execute a test case:
[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));
}
}
With WebAPI, you don't need access to the current resolver because the current dependency scope generally comes along with the inbound HttpRequestMessage
. That message is also what's responsible for generating the new request scope.
You can see the code for this in the System.Net.Http.HttpRequestMessageExtensions.GetDependencyScope
method.
One big thing you'll notice in WebAPI is that you don't actually need to set anything in global static values - that is, you don't need to set a global configuration/resolver because everything is instance-based now.
For testing, what this means is:
- Your setup will create an
HttpRequestMessage
with the appropriate dependency resolver and configuration. - Your teardown will dispose of the
HttpRequestMessage
which will, in turn, dispose the dependency scopes, etc. down the line. - Individual tests will use
HttpRequestMessage.GetDependencyScope()
if they need to do manual resolution of something and the request message will be used to coordinate/pass around the scope.
In a more concrete fashion, it might look like:
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));
}
What's nice about this is that you don't have to fight with global configuration settings or resetting static values after every test.
You might wonder why you'd pass around the whole request message rather than just the dependency resolver - the reason is that the request message is what coordinates and controls the lifetime of the dependency scope. Otherwise, when you call GetDependencyScope
multiple times, you'll get multiple different scopes rather than the same one as you'd expect.
Some things to consider from a design perspective:
- You might want to put the actual registrations of things into an Autofac module so it can be reused in both tests and in your
RegisterAndSetResolver
method without having to worry about global statics getting tampered with. - Instead of a
RegisterAndSetResolver
modifying the global static configuration, you might consider just setting the resolver on theHttpConfiguration
object that gets wired up in thatWebApiConfig.Register
method that WebAPI gives you. Take anHttpConfiguration
object in as a parameter and set the resolver on that rather than the global. - If you're doing every registration for everything in a unit test, your unit tests might be closer to "integration tests." You might consider looking at only what's required for the stuff you're testing and using a mock framework to register stubs rather than actually registering a boatload of "real stuff."
Anyway, HttpRequestMessage
is the way to go for WebAPI.
这篇关于从MVC的DependencyResolver过渡到AutofacWebApiDependencyResolver - 哪里是.Current?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!