您如何使用 ASP.NET Core 3.1 和 Autofac 中的服务位置解决每个请求的项目?

How do you resolve a per-request item using service location in ASP.NET Core 3.1 and Autofac?

我已使用此代码段来设置我的应用程序:

 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 时,虽然您可以将 Autofac 作为后备容器,但在大多数情况下,您会在 Startup 之外 直接 放弃使用 Autofac class。您在 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 生命周期,您可以解决一个问题。从生命周期范围 returns 本身解析生命周期范围。

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

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