首页 > 解决方案 > 如何访问/传递来自不同范围的数据

问题描述

出于某种原因,我需要从另一个范围中设置的不同范围访问数据。请告知如何实现这一点。这是我在一个范围内设置 CallContext 值并希望从新创建的范围中获取相同值的相同代码。

    public class CallContext
    {
        ConcurrentDictionary<string, AsyncLocal<object>> state = new ConcurrentDictionary<string, AsyncLocal<object>>();

        public void SetData(string name, object data) =>
            state.GetOrAdd(name, _ => new AsyncLocal<object>()).Value = data;

        public object GetData(string name) =>
            state.TryGetValue(name, out AsyncLocal<object> data) ? data.Value : null;
    }


    public interface ICustomerService
    {
        void Log();
    }


    public class CustomerService : ICustomerService
    {
        private CallContext _callContext;
        private static IHttpContextAccessor _httpContextAccessor;
        private IServiceScopeFactory _serviceScopeFactory;
        public CustomerService(CallContext callContext, IHttpContextAccessor httpContextAccessor, IServiceScopeFactory serviceScopeFactory)
        {
            _callContext = callContext;
            _httpContextAccessor = httpContextAccessor;
            _serviceScopeFactory = serviceScopeFactory;
        }

        public void Log()
        {
            var context = _httpContextAccessor.HttpContext;

            _callContext.SetData("ThreadId", context.TraceIdentifier);
            _callContext.SetData("URL", context?.Request?.Scheme + "://" + context?.Request?.Host.Value + context?.Request?.Path.Value);

            // For some reason I need to create a new scope
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                var customerPortalService = scope.ServiceProvider.GetRequiredService<ISecondCustomerService>();

                customerPortalService.Log();
            }
        }
    }


    public interface ISecondCustomerService
    {
        void Log();
    }


    public class SecondCustomerService : ISecondCustomerService
    {
        private CallContext _callContext;
        public SecondCustomerService(CallContext callContext)
        {
            _callContext = callContext;
        }
        public void Log()
        {
            var threadId = _callContext.GetData("ThreadId");
            var url = _callContext.GetData("URL");
        }
    }



    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped<CallContext>();
            services.AddScoped<ICustomerService, CustomerService>();
            services.AddScoped<ISecondCustomerService, SecondCustomerService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }


    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private readonly ICustomerService customerService;
        public WeatherForecastController(ICustomerService _customerService)
        {
            customerService = _customerService;
        }

        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

        public ActionResult Log()
        {
            customerService.Log();
            return Ok();
        }
    }

在上面的代码中,我在 CustomerServe 的 CallContext 中设置 ThreadID 和 URL 值,并希望从在 CustomerService 中创建的新范围内的 SecondCustomerService 获得相同的值。

标签: asp.net-coreasp.net-core-mvcasp.net-core-webapiasp.net-core-3.1

解决方案


推荐阅读