【问题标题】:How do you resolve a per-request item using service location in ASP.NET Core 3.1 and Autofac?如何使用 ASP.NET Core 3.1 和 Autofac 中的服务位置解析每个请求项?
【发布时间】:2020-10-27 19:30:11
【问题描述】:

我已经使用这个 sn-p 来设置我的应用程序:

 public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureContainer<ContainerBuilder>(Startup.Register)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
  public static void Register(ContainerBuilder builder)
        {
            builder.RegisterType<UserService>().As<IUserServcice>().InstancePerLifetimeScope();
        }

我已经以下面提到的方式使用它:

  public interface IUserServcice
    {
        public long Tick { get; } 
    }

    public class UserService : IUserServcice
    {
        private long _tick;
        public UserService()
        {
            _tick = DateTime.Now.Ticks;
        }


        public long Tick => _tick;
    }




   public WeatherForecastController(IUserServcice userServcice)
        {
          //  _logger = logger;
            iUserServcice = userServcice;
            var g = Startup.AutofacContainer.Resolve<IUserServcice>();
            tick2 = g.Tick;
        }

        private async Task Get1()
        {
            var list = new List<long>();
            list.Add(iUserServcice.Tick);
            var g=Startup.AutofacContainer.Resolve<IUserServcice>(); 
            list.Add(g.Tick);
            list.Add(tick2);
            //using (var scope= SorviceLocator.Container.BeginLifetimeScope("t1"))
            //        {
            for (int i = 0; i < 3; i++)
            {
                await Task.Factory.StartNew(() =>
                {
                 
                        var sr = Startup.AutofacContainer.Resolve<IUserServcice>();
                        list.Add(sr.Tick);
                  
                 
                });
            }

              //      }
         
        }

        [HttpGet]
        public async Task<IEnumerable<WeatherForecast>> Get()
        {
            await Get1();

            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

不幸的是,调试的结果就像下面上传的图片:

您可以在顶部的图片中看到项目是控制器构造函数注入的结果,而其他项目位于控制器内部,我的问题是我如何才能让所有这些项目具有相同的值。

【问题讨论】:

  • 问题不在于如何使用每个请求的生命周期范围;问题是如何在服务位置的上下文中获取请求生命周期范围。我已经相应地更新了标题。

标签: asp.net-core dependency-injection autofac


【解决方案1】:

当您使用 ASP.NET Core 时,虽然您可以让 Autofac 作为后备容器,但在大多数情况下,您在 Startup 类之外直接放弃使用 Autofac。你在 Startup 中注册你的东西,但在控制器和其他地方,它都是标准的依赖注入(没有 Autofac 引用)和 Microsoft 依赖注入抽象。

这很重要,因为它可以帮助您在 Google 上找到答案。不要寻找“我如何使用 Autofac 做到这一点?” - 寻找“我如何在 ASP.NET Core 中执行此操作?”

首先,避开服务地点。我明白你在做什么,我明白你在做什么......但你需要使用服务位置来证明问题的事实似乎是一个危险信号。

现在不碍事了:

你想要的是HttpContext.RequestServices。当您拥有控制器时,您将拥有 HttpContextRequestServices 对象,那里是请求生命周期范围。它由 Autofac 支持,但界面是 Microsoft 界面。

You can read about RequestServices in the Microsoft docs.

private readonly IUserService injected;

public WeatherForecastController(IUserService userService)
{
  this.injected = userService;
}

public async Task Get()
{
  var located = this.HttpContext.RequestServices.GetService<IUserService>();
  // located and injected will be the same instance.
}

再次,如果您需要开始子生命周期范围,那是 MS DI 的事情。你需要一个IServiceScopeFactory。这可以是构造函数依赖项,也可以像以前一样使用服务位置。

var scopeFactory = this.HttpContext.RequestServices.GetService<IServiceScopeFactory>();
using(var scope = scopeFactory.CreateScope())
{
  // Now you have a scope to work with.
}

如果您绝对必须出于任何原因从IServiceProvider 获取 Autofac 生命周期,您可以解决一个问题。从生命周期范围解析生命周期范围会返回自身。

var requestScope = this.HttpContext.RequestServices.GetService<ILifetimeScope>();

但是,您会再次注意到,我们在这里所做的一切都是使用 Microsoft DI 抽象,所以当您寻找答案时,我建议您更广泛地寻找答案,而不是将您的搜索限制在 Autofac。无论您使用哪种支持容器,此答案基本相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 2019-01-08
    • 2020-06-23
    • 2020-05-20
    • 1970-01-01
    相关资源
    最近更新 更多