Masstransit can';t从c#应用程序连接到RabbitMQ中的队列
我在RabbitMQ中有一个队列。我无法配置此队列,我必须使用其中的消息。Publisher不使用Masstransit进行发布。我正在使用Masstransit来使用队列中的消息 当我试图配置与队列的连接时,我收到以下错误: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'
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的预期。