Masstransit can';t从c#应用程序连接到RabbitMQ中的队列

Masstransit can';t从c#应用程序连接到RabbitMQ中的队列,c#,rabbitmq,queue,masstransit,consumer,C#,Rabbitmq,Queue,Masstransit,Consumer,我在RabbitMQ中有一个队列。我无法配置此队列,我必须使用其中的消息。Publisher不使用Masstransit进行发布。我正在使用Masstransit来使用队列中的消息 当我试图配置与队列的连接时,我收到以下错误: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text='PRECONDITION_FAILED - inequivalent arg 'type'

我在RabbitMQ中有一个队列。我无法配置此队列,我必须使用其中的消息。Publisher不使用Masstransit进行发布。我正在使用Masstransit来使用队列中的消息

当我试图配置与队列的连接时,我收到以下错误:

The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text='PRECONDITION_FAILED - inequivalent arg 'type' for exchange 'my_queue' in vhost 'my_vhost': received 'fanout' but current is 'direct'', classId=40, methodId=10
我的配置如下所示:

Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    cfg.Host("127.0.0.1", "my_virtual_host", credintials =>
    {
        credintials.Username("myuser");
        credintials.Password("mypassword");
    });

    cfg.ReceiveEndpoint("my_queue", e =>
    {

        e.UseRawJsonSerializer();
        e.Consumer(() => _messageConsumer);
    });
}).Start();
private async Task InitMasstransitBusAsync(CancellationToken cancellationToken)
{
    await Bus.Factory.CreateUsingRabbitMq(cfg =>
    {
        cfg.Host(new Uri(_rabbitMqConfig.HostName), credintials =>
        {
            credintials.Username(_rabbitMqConfig.UserName);
            credintials.Password(_rabbitMqConfig.Password);

        });
        cfg.ReceiveEndpoint(_rabbitMqConfig.QueueName, e =>
        {
            e.PrefetchCount = 20;
            e.ExchangeType = "direct";
            e.ConfigureConsumeTopology = false;
            e.AddMessageDeserializer(new ContentType("text/plain"),
                () => new CustomMessageDeserializer("text/plain"));
            e.Consumer(() => _messageConsumer);
        });
    }).StartAsync(cancellationToken);
}
队列的配置持久=true,仅此而已,没有什么特别之处

当我试图通过RabbitMQ.Client连接到队列时,它连接没有问题。消费也很有效


如何解决此问题?

问题是
我的队列
已存在直接交换类型的交换。默认情况下,MassTransit将此交换创建为扇出交换。直接交换用于通过路由密钥路由消息。有关与MassTransit使用直接交换的示例,请查看示例


您可以看到MassTransit为RabbitMQ配置的。我解决了我的问题。与Masstransit的连接如下所示:

Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    cfg.Host("127.0.0.1", "my_virtual_host", credintials =>
    {
        credintials.Username("myuser");
        credintials.Password("mypassword");
    });

    cfg.ReceiveEndpoint("my_queue", e =>
    {

        e.UseRawJsonSerializer();
        e.Consumer(() => _messageConsumer);
    });
}).Start();
private async Task InitMasstransitBusAsync(CancellationToken cancellationToken)
{
    await Bus.Factory.CreateUsingRabbitMq(cfg =>
    {
        cfg.Host(new Uri(_rabbitMqConfig.HostName), credintials =>
        {
            credintials.Username(_rabbitMqConfig.UserName);
            credintials.Password(_rabbitMqConfig.Password);

        });
        cfg.ReceiveEndpoint(_rabbitMqConfig.QueueName, e =>
        {
            e.PrefetchCount = 20;
            e.ExchangeType = "direct";
            e.ConfigureConsumeTopology = false;
            e.AddMessageDeserializer(new ContentType("text/plain"),
                () => new CustomMessageDeserializer("text/plain"));
            e.Consumer(() => _messageConsumer);
        });
    }).StartAsync(cancellationToken);
}
CustomMessageDeserializer:

    public class CustomMessageDeserializer : IMessageDeserializer
    {
        private readonly string _contentType;
        private readonly JsonSerializer _serializer = JsonSerializer.Create();

        public CustomMessageDeserializer(string contentType)
        {
            _contentType = contentType;
        }

        public ContentType ContentType => new(_contentType);

        public ConsumeContext Deserialize(ReceiveContext receiveContext)
        {
            try
            {
                var messageEncoding = GetMessageEncoding(receiveContext);
                using var body = receiveContext.GetBodyStream();
                using var reader = new StreamReader(body, messageEncoding, false, 1024, true);
                using var jsonReader = new JsonTextReader(reader);
                var messageToken = _serializer.Deserialize<JToken>(jsonReader);
                
                return new RawJsonConsumeContext(_serializer, receiveContext, messageToken);
            }
            catch (JsonSerializationException ex)
            {
                throw new SerializationException("A JSON serialization exception occurred while deserializing the message", ex);
            }
            catch (SerializationException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SerializationException("An exception occurred while deserializing the message", ex);
            }
        }

        public void Probe(ProbeContext context) { }

        public static Encoding GetMessageEncoding(ReceiveContext receiveContext)
        {
            var contentEncoding = receiveContext.TransportHeaders.Get("Content-Encoding", default(string));
            return string.IsNullOrWhiteSpace(contentEncoding) ? Encoding.UTF8 : Encoding.GetEncoding(contentEncoding);
        }

    }
公共类CustomMessageDeserializer:IMessageDeserializer
{
私有只读字符串_contentType;
私有只读JsonSerializer _serializer=JsonSerializer.Create();
公共CustomMessageDeserializer(字符串contentType)
{
_contentType=contentType;
}
public ContentType ContentType=>new(\u ContentType);
公共上下文反序列化(ReceiveContext ReceiveContext)
{
尝试
{
var messageEncoding=GetMessageEncoding(receiveContext);
使用var body=receiveContext.GetBodyStream();
使用var reader=newstreamreader(body,messageEncoding,false,1024,true);
使用var jsonReader=newjsontextreader(reader);
var messageToken=_serializer.Deserialize(jsonReader);
返回新的RawJsonConsumeContext(_序列化程序、receiveContext、messageToken);
}
捕获(JsonSerializationException ex)
{
抛出新的SerializationException(“反序列化消息时发生JSON序列化异常”,ex);
}
捕获(序列化异常)
{
投掷;
}
捕获(例外情况除外)
{
抛出新的SerializationException(“反序列化消息时发生异常”,ex);
}
}
公共void探测(ProbeContext){}
公共静态编码GetMessageEncoding(ReceiveContext ReceiveContext)
{
var contentEncoding=receiveContext.TransportHeaders.Get(“内容编码”,默认值(字符串));
返回字符串.IsNullOrWhiteSpace(contentEncoding)?Encoding.UTF8:Encoding.GetEncoding(contentEncoding);
}
}

我正在使用.NET5和
cfg.ConfigureMessageTopology()找不到扩展方法。在
cfg.ReceiveEndpoint
中,我添加了
endpoint.ConfigureConsumeTopology=false
endpoint.Bind
endpoint.Handler
。但我仍然有同样的错误。Masstransit似乎没有看到现有的队列。如果我设置另一个队列名称,如
cfg.ReceiveEndpoint(“direct.client.my_queue”,endpoint=>
,它将在RabbitMQ中创建队列。但我需要连接到名为
my_queue
的现有队列。是否可以不创建,只连接到现有队列(不是由Masstransit publisher创建的)?:)正如我在回答中所述,MassTransit使用具有相同名称的匹配exchange/队列对,RabbitMQ报告的错误是exchange类型与预期类型不匹配(扇出,为直接)。任何其他配置都必须在接收端点上–您可以在那里指定ExchangeType,但这超出了MassTransit的预期。