从 MVC 的 DependencyResolver 过渡到 AutofacWebApiDependencyResolver - .Current 在哪里? [英] Transitioning to AutofacWebApiDependencyResolver from MVC's DependencyResolver - Where is .Current?

查看:42
本文介绍了从 MVC 的 DependencyResolver 过渡到 AutofacWebApiDependencyResolver - .Current 在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我让 AutoFac 与 MVC4 一起正常工作.我正在尝试过渡到 Web API 2.这是我设置 AutoFac 的条件:

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;
    }
}

我非常有信心所有这些都是正确的.当我尝试设置一些测试用例时,我的问题就出现了.我的测试用例的基类不是控制器,因此它不会自动传递任何内容.在 MVC4 中,我做了以下事情:

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();
}

遗憾的是,WebAPI 中没有 DependencyResolver.Current.所以我想知道如何正确地做到这一点?

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));
    }
}

推荐答案

使用 WebAPI,您不需要访问当前解析器,因为当前依赖范围通常与入站 HttpRequestMessage 一起出现.该消息也是负责生成新请求范围的内容.

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.

您可以在 System.Net.Http.HttpRequestMessageExtensions.GetDependencyScope 方法中查看此代码.

You can see the code for this in the System.Net.Http.HttpRequestMessageExtensions.GetDependencyScope method.

您会在 WebAPI 中注意到的一件大事是您实际上不需要在全局静态值中设置任何内容 - 也就是说,您不需要设置全局配置/解析器因为现在一切都是基于实例的.

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.

对于测试,这意味着:

  • 您的设置将使用适当的依赖项解析器和配置创建一个 HttpRequestMessage.
  • 您的拆解将处理 HttpRequestMessage,而后者又将处理依赖范围等.
  • 个别测试将使用 HttpRequestMessage.GetDependencyScope() 如果他们需要手动解析某些内容,并且请求消息将用于协调/传递范围.
  • 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.

您可能想知道为什么要传递整个请求消息而不只是依赖解析器 - 原因是请求消息协调和控制依赖范围的生命周期.否则,当您多次调用 GetDependencyScope 时,您将获得多个不同的范围,而不是您期望的相同范围.

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:

  • 您可能希望将事物的实际注册放入 Autofac 模块,以便它可以在两个测试和您的 RegisterAndSetResolver 方法中重用,而不必担心全局静态被篡改.
  • 代替 RegisterAndSetResolver 修改全局静态配置,您可以考虑只在 HttpConfiguration 对象上设置解析器,该对象连接到该 WebAPI 为您提供的 WebApiConfig.Register 方法.将 HttpConfiguration 对象作为参数,并在其上设置解析器,而不是全局.
  • 如果您对单元测试中的所有内容进行每次注册,您的单元测试可能更接近于集成测试".您可能会考虑仅查看您正在测试的内容所需的内容,并使用模拟框架注册存根,而不是实际注册大量真实内容".
  • 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 the HttpConfiguration object that gets wired up in that WebApiConfig.Register method that WebAPI gives you. Take an HttpConfiguration 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."

无论如何,HttpRequestMessage 是使用 WebAPI 的方法.

Anyway, HttpRequestMessage is the way to go for WebAPI.

这篇关于从 MVC 的 DependencyResolver 过渡到 AutofacWebApiDependencyResolver - .Current 在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆