#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 Я попробовал ваше предложение, но оно не сработало.