Unable to connect RabbitBus to RabbitMQ - c#

I am creating a RabbitBus.Bus with the RabbitBus.BusBuilder in my RabbitAdapter class.
public class RabbitAdapter
{
private Bus _bus;
public RabbitAdapter()
{
// The exchange and queue values are the same as what I see in RabbitMQ in browser
_bus = new BusBuilder()
.Configure(ctx => ctx.Consume<StatusUpdate>()
.WithExchange("exchange")
.WithQueue("Log"))
.Build();
}
public void Init()
{
// The [url] and [port] values are the same as what I see in browser
_bus.Connect("amqp://guest:guest#[url]:[port]/#/", TimeSpan.FromSeconds(10));
_bus.Subscribe<StatusUpdate>(OnHandle);
}
private void OnHandle(IMessageContext<StatusUpdate> statusUpdateContext)
{
Console.WriteLine(statusUpdateContext.Id);
}
public void Start()
{
}
}
I know that I'm probably just missing something here. The _connectionFactory is not null in the Bus, but the _connection is. It seems to timeout, I've even tried making the timeout one minute.

What you miss is although the console listens on 15672, the actual server listens on 5672 port.

Related

Publishing to Azure Service Bus Topic fails without error

Update oct. 20, 2021
It seems that publishing to a queue works as expected. When I publish to a queue, the message is persisted on the queue. Conversely, when I publish to a topic, the message is not persisted.
Updated
I have added a simple console app that reproduces the same behavior down below.
I am trying to send a message to a topic in service bus from an Azure Function. I have tried this with a managed identity using Mass Transit. I have also tried this with a shared access key using the Azure.Messaging.ServiceBus nuget package. Both methods complete without exception, but the message is not in the topic.
This is what I see when sending from my function:
Additional settings on the topic:
I am able to put messages on the topic using the Service Bus Explorer within the Azure portal.
There are no subscriptions on this topic. I did have one setup as a test earlier, but it has since been deleted.
Mass Transit Setup (in Startup.cs)
private void ConfigureMassTransit(IServiceCollection services, IConfiguration config) {
const string KEY_QUEUE_SERVER = "REDACTED";
const string EMAIL_RETRY_TOPIC = "REDACTED";
const string EMAIL_SENT_TOPIC = "REDACTED";
services.AddMassTransit(x => {
x.UsingAzureServiceBus((context, cfg) => {
cfg.Host(new Uri(config[KEY_QUEUE_SERVER]), host => {
host.TokenProvider = TokenProvider.CreateManagedIdentityTokenProvider();
});
cfg.Message<EmailSentEvent>(m => m.SetEntityName(EMAIL_SENT_TOPIC));
cfg.Message<TransactionEmailFailedEvent>(m => m.SetEntityName(EMAIL_RETRY_TOPIC));
cfg.ConfigureEndpoints(context);
});
});
}
MassTransitQueueAdapter.cs
public class MassTransitQueueAdapter : IQueueAdapter {
#region attributes
private readonly IBus _bus;
#endregion
#region ctor
public MassTransitQueueAdapter(IBus bus) {
_bus = bus;
}
#endregion
#region methods
public void PublishFailure(TransactionEmailFailedEvent failedEvent) {
_bus.Publish(failedEvent);
}
public void PublishSuccess(EmailSentEvent sentEvent) {
_bus.Publish(sentEvent);
}
#endregion
}
ServiceBusQueueAdapter.cs
public class ServiceBusQueueAdapter : IQueueAdapter {
#region attributes
private readonly QueueContext _context;
#endregion
#region ctor
public ServiceBusQueueAdapter(QueueContext context) {
_context = context;
}
#endregion
#region methods
private static ServiceBusClient BuildClient(string connectionString) => new ServiceBusClient(connectionString);
public void PublishFailure(TransactionEmailFailedEvent failedEvent) {
throw new System.NotImplementedException();
}
public void PublishSuccess(EmailSentEvent sentEvent) {
ServiceBusClient client = BuildClient(_context.SentTopicConnectionString);
ServiceBusSender sender = client.CreateSender(_context.SentTopicName);
Task.Run(() => sender.SendMessageAsync(new ServiceBusMessage(JsonConvert.SerializeObject(sentEvent))));
}
#endregion
}
Simple Console App
class Program {
static void Main() {
string cs = "Endpoint=sb://REDACTED.servicebus.windows.net/;SharedAccessKeyName=test_with_manage;SharedAccessKey=REDACTED;";
ServiceBusClient client = new ServiceBusClient(cs);
ServiceBusSender sender = client.CreateSender("test_1");
sender.SendMessageAsync(new ServiceBusMessage("Hello World!"))
.Wait();
}
}
The problem here is with my understanding of topics in Azure Service Bus. I was expecting the Topic to act as a type of storage for messages. I was wrong in that assumption. The topic will only forward messages to subscriptions. The subscription can either persist the message or forward to another topic or queue.
With that knowledge in mind, I was able to get my Service Bus specific implementations working. I apparently still have a bit to learn about Mass Transit.

Enumerating available actors in Akka.NET cluster

I have two actors, lets call them ActorA and ActorB. Both actors reside in their own separate process as a Topshelf based Windows Service.
Basically they look like this.
public class ActorA : ReceiveActor
{
public ActorA()
{
this.Receive<ActorIdentity>(this.IdentifyMessageReceived);
}
private bool IdentifyMessageReceived(ActorIdentity obj)
{
return true;
}
}
public class ActorB : ReceiveActor
{
private readonly Cluster Cluster = Akka.Cluster.Cluster.Get(Context.System);
public ActorB()
{
this.Receive<ActorIdentity>(this.IdentifyMessageReceived);
this.ReceiveAsync<ClusterEvent.MemberUp>(this.MemberUpReceived);
}
protected override void PreStart()
{
this.Cluster.Subscribe(this.Self, ClusterEvent.InitialStateAsEvents, new[]
{
typeof(ClusterEvent.IMemberEvent),
typeof(ClusterEvent.UnreachableMember)
});
}
protected override void PostStop()
{
this.Cluster.Unsubscribe(this.Self);
}
private async Task<bool> MemberUpReceived(ClusterEvent.MemberUp obj)
{
if (obj.Member.HasRole("actora"))
{
IActorRef actorSelection = await Context.ActorSelection("akka.tcp://mycluster#localhost:666/user/actora").ResolveOne(TimeSpan.FromSeconds(1));
actorSelection.Tell(new Identify(1));
}
return true;
}
private bool IdentifyMessageReceived(ActorIdentity obj)
{
return true;
}
}
My config files are super simple
ActorA:
akka {
log-config-on-start = on
stdout-loglevel = DEBUG
loglevel = DEBUG
actor.provider = cluster
remote {
dot-netty.tcp {
port = 666
hostname = localhost
}
}
cluster {
seed-nodes = ["akka.tcp://mycluster#localhost:666"]
roles = [actora]
}
}
ActorB:
akka {
log-config-on-start = on
stdout-loglevel = DEBUG
loglevel = DEBUG
actor.provider = cluster
remote {
dot-netty.tcp {
port = 0
hostname = localhost
}
}
cluster {
seed-nodes = ["akka.tcp://mycluster#localhost:666"]
roles = [actorb]
}
}
I now want to identify all the given actors attached to my cluster. I do this by waiting for the cluster node MEMBER UP event and trying to send an Identify() message to the given actor to receive a reference to it.
The problem is that I cannot seem to be able to successfully send the message back to ActorA. Infact when executing the above code (despite the fact that I have the correct reference in the ActorSelection method) the ActorIdentity message is invoked in ActorB rather than ActorA.
I have tried handling all received message in ActorA and it appears I never receive the Identity message. However I can successfully send any other type of message ActorA using the same ActorSelection reference.
So can anyone provide any insight? Why is my identity message never reaching my target actor?
ActorIdentity message is invoked in ActorB rather than ActorA.
This works as intended, as you're sending Identify request from actor B → A, for which ActorIdentity is a response message (send automatically from A → B).
You can already observe this behavior in action, since:
Context.ActorSelection(path).ResolveOne(timeout)
is more or less an equivalent of
Context.ActorSelection(path).Ask<ActorIdentity>(new Identify(null), timeout: timeout)
Identify is a system message, which is handled always before any programmer-defined message handlers are invoked - for this reason you probably won't catch it in your own handlers.

ASP.NET MVC 4.5 WebSocket server loses connection after a few messages have been transferred

I've just started to play around with WebSockets and ASP.NET and have run into a weird issue. I'm building a very primitive ASP.NET 4.5 WebAPI application that is supposed to function as an echo-server like so:
using Microsoft.Web.WebSockets;
// ...
namespace MyControllers
{
internal class EchoHandler : WebSocketHandler
{
public override void OnClose()
{
System.Diagnostics.Debug.Write("Close");
}
public override void OnError()
{
System.Diagnostics.Debug.Write("Error: " + this.Error.ToString());
}
public override void OnOpen()
{
System.Diagnostics.Debug.Write("Open");
}
public override void OnMessage(string message)
{
System.Diagnostics.Debug.Write("Message: " + message);
this.Send("Echo: " + message);
}
}
public class EchoController : ApiController
{
public HttpResponseMessage Get()
{
if (HttpContext.Current.IsWebSocketRequest)
{
HttpContext.Current.AcceptWebSocketRequest(new EchoHandler());
return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
}
}
I'm connecting to this service using a Windows Store Application written in C#. The relevant code looks like this:
class WebsocketTest
{
private MessageWebSocket webSocket;
private DataWriter messageWriter;
private async Task Connect()
{
var server = new Uri("ws://127.0.0.1:81/");
webSocket = new MessageWebSocket();
webSocket.Control.MessageType = SocketMessageType.Utf8;
webSocket.MessageReceived += messageWebSocket_MessageReceived;
webSocket.Closed += messageWebSocket_Closed;
await webSocket.ConnectAsync(server);
messageWebSocket = webSocket;
messageWriter = new DataWriter(webSocket.OutputStream);
}
private async Task Send(string message)
{
try
{
messageWriter.WriteString(message);
await messageWriter.StoreAsync();
}
catch (Exception ex)
{
var error = WebSocketError.GetStatus(ex.GetBaseException().HResult);
}
}
}
This works well for a while, but after an arbitrary number of messages have been sent back and forth, OnError() is invoked on the server and I get the following exception: "The I/O operation has been aborted because of either a thread exit or an application request" (It's the "this.Send(...)" that seems to be causing it). If I keep sending stuff on the client, I get a "ConnectionAborted" error when calling "dataWriter.StoreAsync()".
The error occurs every time, but it takes a varying number of messages before it does. Using longer messages seems to speed up the process.
For testing, I also tried using plain AspNetWebSockets instead of a WebSocketHandler but with the same outcome.
Any ideas?
Thanks a ton in advance,
Kai
Its a bug (reported by me):
https://connect.microsoft.com/VisualStudio/feedbackdetail/view/976851/server-websocket-closed-abruptly-the-i-o-operation-has-been-aborted-because-of-either-a-thread-exit-or-an-application-request
I have been trying to find a workaround for quite some time without being successful. I'm using the HttpListener but the symptom is the same. Now I have changed implementation to a third party library and the problem seems to have been resolved.

SignalR (v.1.1.1) Call from Server

I am using latest SignalR (v:1.1.1), and trying to simple call the Hub method periodically, every 3 seconds. I have seen many questions here and have duplicated the way, but GetHubContext method doesn't seem to be returning the correct instance of the class, so I can't call the methods of that class. You can duplicate the case with the following steps:
MyHub.cs:
public class MyHub : Hub
{
public void SendMessage(string message)
{
Clients.All.triggerMessage(message);
}
}
Global.asax:
Task.Factory.StartNew(() =>
{
while (true)
{
var myHub = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
myHub.Clients.All.SendMessage("Hello World");
System.Threading.Thread.Sleep(3000);
}
})
.ContinueWith(t => { throw new Exception("The task threw an exception", t.Exception); }, TaskContinuationOptions.OnlyOnFaulted);
I think this is as simple as it gets. I think this is correct way of doing it, but the debugger never hits SendMessage method. Does anyone know am I missing something very obvious? I am just trying to schedule a call to the SignalR client from the server for every 3 seconds.
On your Global.asax file, when you call 'myHub.Clients.All.SendMessage("Hello World")' it sends a message to the client, it does not call the SendMessage method in your class MyHub.
Please read SignalR Documentation to see some samples
I ended changing the way the hub was created:
MyHostHub.cs
private readonly MyHost _host;
public MyHostHub(){ _host = new MyHost(); }
MyHost:
private readonly static Lazy<IHubConnectionContext> _clients = new Lazy<IHubConnectionContext>(() => GlobalHost.ConnectionManager.GetHubContext<MyHostHub>().Clients);
private IHubConnectionContext Clients
{
get { return _clients.Value; }
}
public void SendMessage(string message)
{
Clients.All.triggerMessage(message);
}
My Global.asax:
Task.Factory.StartNew(() =>
{
while (true)
{
var myHost = ObjectFactory.GetInstance<MyHost>();
myHost.SendMessage();
Thread.Sleep(3000);
}
})
.ContinueWith(t => { throw new Exception("The task threw an exception", t.Exception); }, TaskContinuationOptions.OnlyOnFaulted);
This seems to be working just fine. Basically I moved out the code from the Hub class to another class that I can call in Global.asax but my hub has a reference for host.

SendOnly in NServiceBus

When creating a NServiceBus SendOnly endpoint, the purpose is to just fire-and-forget, i.e. just send a message and then someone else will take care of it. Which seems like the thing I need. I dont want any communication between the bus and the system handling messages. System "A" wants to notify system "B" about something.
Well the creation of an SendOnly endpoint if very straightforward but what about the system listening for messages from an SendOnly endpoint.
I'm trying to set up a listener in a commandline project that will handle messages. The messages get sent to the queue but they doesnt get handled by system "B".
Is this the wrong approach? Is a bus overkill for this type of functionality?
System A:
public class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
var bus = Configure.With()
.UnityBuilder(container)
.JsonSerializer()
.Log4Net()
.MsmqTransport()
.UnicastBus()
.SendOnly();
while(true)
{
Console.WriteLine("Send a message");
var message = new Message(Console.ReadLine());
bus.Send(message);
}
}
}
System B:
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
var bus = Configure.With()
.UnityBuilder(container)
.JsonSerializer()
.Log4Net()
.MsmqTransport()
.UnicastBus()
.LoadMessageHandlers()
.CreateBus()
.Start();
Console.WriteLine("Waiting for messages...");
while(true)
{
}
}
}
public class MessageHandler : IHandleMessages<Message>
{
public void Handle(Message message)
{
Console.WriteLine(message.Data);
}
}
public class Message : IMessage
{
public Message()
{
}
public Message(string data)
{
Data = data;
}
public string Data { get; set; }
}
In the MessageEndpointMappings you need to update it as follows:
Replace DLL with the name of the assembly containing your messages (e.g. "Messages")
Change the Endpoint to the name of the queue which System B is reading from (You can check the queue name by looking in the MSMQ snapin under private queues).
<add Messages="Messages" Endpoint="SystemB" />
NServiceBus 3 automatically creates the queue name based upon the namespace of the hosting assembly.
Additionally, you may want to look at using the NServiceBus.Host to host your handlers instead of your own console application.

Categories

Resources