Поскольку HttpContext
нет, поскольку запрос RabbitMq не является запросом Http, как указано в ответе @ istepaniuk, я создал свой собственный контекст и назвал его AmqpContext
:
public interface IAmqpContext
{
void ClearHeaders();
void AddHeaders(IDictionary<string, object> headers);
string GetHeaderByKey(string headerKey);
}
public class AmqpContext : IAmqpContext
{
private readonly Dictionary<string, object> _headers;
public AmqpContext()
{
_headers = new Dictionary<string, object>();
}
public void ClearHeaders()
{
_headers.Clear();
}
public void AddHeaders(IDictionary<string, object> headers)
{
foreach (var header in headers)
_headers.Add(header.Key, header.Value);
}
public string GetHeaderByKey(string headerKey)
{
if (_headers.TryGetValue(headerKey, out object headerValue))
{
return Encoding.Default.GetString((byte[])headerValue);
}
return null;
}
}
И при отправке сообщения RabbitMq я отправляю идентификатор арендатора через заголовки следующим образом:
var properties = channel.CreateBasicProperties();
if (tenantId != null)
{
var headers = new Dictionary<string, object>
{
{ "tid", tenantId }
};
properties.Headers = headers;
}
channel.BasicPublish(exchange: BROKER_NAME,
routingKey: eventName,
mandatory: true,
basicProperties: properties,
body: body);
Затем, когда в службе приема я регистрирую AmqpContext
в качестве службы с ограничениями в Startup.cs
:
services.AddScoped<IAmqpContext, AmqpContext>();
При получении сообщения RabbitMq внутри потребительского канала создается область действия и контекст Amqp:
consumer.Received += async (model, ea) =>
{
var eventName = ea.RoutingKey;
var message = Encoding.UTF8.GetString(ea.Body);
var properties = ea.BasicProperties;
using (var scope = _serviceProvider.CreateScope())
{
var amqpContext = scope.ServiceProvider.GetService<IAmqpContext>();
if (amqpContext != null)
{
amqpContext.ClearHeaders();
if (properties.Headers != null && amqpContext != null)
{
amqpContext.AddHeaders(properties.Headers);
}
}
var handler = scope.ServiceProvider.GetService(subscription.HandlerType);
if (handler == null) continue;
var eventType = _subsManager.GetEventTypeByName(eventName);
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
}
channel.BasicAck(ea.DeliveryTag, multiple: false);
};
Затем, когда создается служба соединения с областью действия Db (см. Мой вопрос)Я могу получить доступ к идентификатору клиента из заголовков сообщения:
services.AddScoped<IDocumentSession>(ds =>
{
var store = ds.GetRequiredService<IDocumentStore>();
string tenant = null;
var httpContextAccessor = ds.GetRequiredService<IHttpContextAccessor>();
if (httpContextAccessor.HttpContext != null)
{
tenant = httpContextAccessor.HttpContext.User?.Claims.FirstOrDefault(c => c.Type == "tid")?.Value;
}
else
{
var amqpContext = ds.GetRequiredService<IAmqpContext>();
tenant = amqpContext.GetHeaderByKey("tid");
}
return tenant != null ? store.OpenSession(tenant) : store.OpenSession();
});