Как получить доступ/передать данные из разных областей

#asp.net-core #asp.net-core-mvc #asp.net-core-webapi #asp.net-core-3.1

Вопрос:

По какой-то причине мне нужно получить доступ к данным из другой области, которая задана в другой области. Пожалуйста, посоветуйте, как этого можно достичь. Вот тот же код, в котором я задаю значение 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();
        }
    }
 

В приведенном выше коде я устанавливаю значение ThreadId и URL в CallContext от CustomerSerive и хотел бы получить то же значение от SecondCustomerService, которое находится в новой области, созданной в CustomerService.

Комментарии:

1. Я думаю, с переходом services.AddTransient<IHttpContextAccessor, HttpContextAccessor>(); на AddHttpContextAccessor() вашу проблему будет решена

2. @mohammadreza Я попробовал ваше предложение, но оно не сработало.