How to get the source address in Rebus? - servicebus

How do I get the source address in a message received?
The context is that I'm designing a monitor for a service bus implemented with Rebus. I use the publish - subscribe pattern thus a message is always published on a topic. The monitor subscribes to all topics in order to supervise that a service has send something and so is alive and healthy. Though in a message handler the received message don't contain any source address or information identifying the service publishing. This means it's not possible to supervise which services are alive and healthy. Of course I can create an attribute "Service" identifying the service publishing in all messages. This implies that each service have to set the attribute before publishing a message, which I find a bit cumbersome. The source address is there and can identify the service publishing.

When you're in a Rebus message handler, you can access the IMessageContext - either by having it injected by your IoC container (which is the preferrent way, because of the improved testability), or by accessing the static MessageContext.Current property.
The message context gives you access to a couple of things, where the headers of the incoming transport message can be used to get the return address of the message (which, by default, is set to the sender's input queue).
Something like this should do the trick:
public class SomeHandler : IHandleMessages<SomeMessage>
{
readonly IMessageContext _messageContext;
public class SomeHandler(IMessageContext messageContext)
{
_messageContext = messageContext;
}
public async Task Handle(SomeMessage message)
{
var headers = _messageContext.TransportMessage.Headers;
var returnAddress = headers[Headers.ReturnAddress];
// .. have fun with return address here
}
}

Related

How can we use #RabbitListener and #JMSListener alternatively based on env?

Actually, I have on premises spring boot application which consumes rabbitMQ messages using #RabbitListener and I have migrated the same application to azure which consumes AzureServiceBus messages using #JMSListener.
We are maintaining same code for both on premises and Azure . So, because of these two listeners, I'm planning to replicate the same consumer code in two different classes with same content with two different Listeners
consumer with JMSListener:
#JmsListener(destination = "${queue}", concurrency = "${threads}", containerFactory = "defaultContainer")
public Message processMessage(#Payload final String message) {
//do stuff with same content
}
consumer with RabbitListener:
#RabbitListener(queues = "${app.rabbitmq.queue}")
public Message processMessage(#Payload final String message) {
//do stuff with same content
}
Is there any possibility of avoiding the duplicate code in two classes ? How can we handle listeners on a fly with only one consumer? Can any one please suggest me out ?
You can add both annotations to the same method with the autoStartup property set according to which Spring profile is active.
For #RabbitListener there is an autoStartup property on the annotation itself but, in both cases, there are Spring Boot properties auto-startup to control whether the container starts or not.

How to set up handlers in RedMQ from events raised in my domain

Just getting my head around message queues and Redis MQ, excellent framework.
I understand that you have to use .RegisterHandler(...) to determine which handler will process the type of message/event that is in the message queue.
So if I have EventA, EventB etc should I have one Service which handles each of those Events, like :
public class DomainService : Service {
public object Any(EventA eventA) {...}
public object Any(EventB eventA) {...}
}
So these should be only queue/redis list created?
Also, what If I want a chain of events to happen, so for example a message of type EventA also has a handler that sends an Email providing handlers earlier on the chain are successful?
ServiceStack has no distinction between services created for MQ's, REST, HTML or SOAP services, they're the same thing. i.e. they each accept a Request DTO and optionally return a Response DTO and the same service can handle calls from any endpoint or format, e.g HTML, REST, SOAP or MQ.
Refer to ServiceStack's Architecture diagram to see how MQ fits in.
Limitations
The only things you need to keep in mind are:
Like SOAP, MQ's only support 1 Verb so your methods need to be named Post or Any
Only Action Filters are executed (i.e. not Global or Attribute filters)
You get MqRequest and MqResponse stubs in place of IHttpRequest, IHttpResponse. You can still use .Items to pass data through the request pipeline but any HTTP actions like setting cookies or HTTP Headers are benign
Configuring a Redis MQ Host
The MQ Host itself is completely decoupled from the rest of the ServiceStack framework, who doesn't know the MQ exists until you pass the message into ServiceStack yourself, which is commonly done inside your registered handler, e.g:
var redisFactory = new PooledRedisClientManager("localhost:6379");
var mqHost = new RedisMqServer(redisFactory, retryCount:2);
mqHost.RegisterHandler<Hello>(m => {
return this.ServiceController.ExecuteMessage(m);
});
//shorter version:
//mqHost.RegisterHandler<Hello>(ServiceController.ExecuteMessage);
mqHost.Start(); //Starts listening for messages
In your RegisterHandler<T> you specify the type of Request you want it to listen for.
By default you can only Register a single handler for each message and in ServiceStack a Request is tied to a known Service implementation, in the case of MQ's it's looking for a method signature first matching: Post(Hello) and if that doesn't exist it looks for the fallback Any(Hello).
Can add multiple handlers per message yourself
If you want to invoke multiple handlers then you would just maintain your own List<Handler> and just go through and execute them all when a request comes in.
Calling different services
If you want to call a different service, just translate it to a different Request DTO and pass that to the ServiceController instead.
When a MQ Request is sent by anyone, e.g:
mqClient.Publish(new Hello { Name = "Client" });
Your handler is invoked with an instance of type IMessage where the Request DTO is contained in the Body property. At that point you can choose to discard the message, validate it or alter it.
MQ Requests are the same as any other Service requests
In most cases you would typically just forward the message on to the ServiceController to process, the implementation of which is:
public object ExecuteMessage<T>(IMessage<T> mqMsg)
{
return Execute(mqMsg.Body, new MqRequestContext(this.Resolver, mqMsg));
}
The implementation just extracts the Request DTO from the mqMsg.Body and processes that message as a normal service being passed a C# Request DTO from that point on, with a MqRequestContext that contains the MQ IHttpRequest, IHttpResponse stubs.

Enabling WCF Reading of an already existing MSMQ Queue

I have developed a WCF Self hosted service using .Net Framework 4.0.
[ServiceContract(SessionMode=SessionMode.Required)]
[ServiceKnownType(typeof(XmlDocument))]
public interface IMyMSMQ
{
[OperationContract(IsOneWay=true, Action="*")]
void OnMessageReceived(MsmqMessage<XmlDocument> msg);
}
My Class implementation of this interface looks like this.
public class MyMSMQ : IMyMSMQ, IErrorHandler
{
public void OnMessageReceived(MsmqMessage<XmlDocument> msg)
{
// Log Message To appropriate destination
Logger.LogMessage(msg);
}
}
I have tried multiple scenarios.
Scenario 1:
Launch service.
Launch Client app.
Send Message to queue using Client App
Notice that the Queue does not appear to get populated with the message because the service already read the message.
Notice that nothing else happens in the service.
Send one more message
Notice that message stays in the queue
Scenario # 2: This is similar to Scenario 1 but starting the apps were in different order
Launch Client app.
Send Message to queue using Client App
Notice that the Queue does appear to get populated with the message because the service is not started and has not read the message.
Launch service.
Notice that the message disappears.
Notice that nothing else happens in the service.
Send one more message
Notice that message stays in the queue
Every time the service starts, a message is removed from the queue so, it appears that my service IS in fact reading the message but it is not able to figure out where to send it or what to do with it once it reads the message.
I found out that the code in the WCF Library was not the problem. It was how I was defining the endpoint binding.
MsmqIntegrationBinding binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
binding.ReceiveTimeout = new TimeSpan(0, 1, 0); // set timeout to 1 minute.
binding.ReceiveErrorHandling = ReceiveErrorHandling.Fault;
this.AddServiceEndpoint(typeof(eRxMsmqWCF.IeRxMSMQ), binding, GetMQUri());
It needed to have the MsmqIntegrationBinding (which requires you to include the following using statement: using System.ServiceModel.MsmqIntegration;.
Sometimes I rely on intellisense too much. The MsmqIntegrationBinding is not present under the standard System.ServiceModel where the other bindings are located. So I used the NetMsmqBinding instead.

WCF - how to write a publisher\subscriber service that publishes only to specific clients?

I am writing a WCF service in a Publish-Subscribe pattern.
When someone publishes an event, I don't want to straight away send it to all the clients.
I want to be able to, for each client, check if that client needs to be notified about that publish.
Basically this will be done by accessing a database, and checking if that client has subscribed for that specific event with those parameters (cannot be done in advance, needs to be checked only against database).
Currently I am working using this List-Based Publish-Subscriber sample, but it works in such a way - that when an event is published - client session is triggered separatly to send the message.
So for now, I am changing this :
public void PriceChangeHandler(object sender, PriceChangeEventArgs e)
{
_callback.PriceChange(e.Item, e.Price, e.Change);
}
to this :
public void PriceChangeHandler(object sender, PriceChangeEventArgs e)
{
// Perform some database checks using BL if this client needs to be notified about this event
// Only if answer is YES - call the callback function on that client
_callback.PriceChange(e.Item, e.Price, e.Change);
// Also - send the client an EMAIL + SMS
_emailServer.SendEmail(e.Item);
_smsServer.SendSMS(e.Item);
}
Two Questions :
Is this the right way ? and how can I know what 'this' client is ? should the client send me credentials in the 'subscribe' method that I will store ?
Or should I implement a custom 'UsernameValidator' that will store the Principal ?
And shouldn't I have a static list of all the clients, that I will send to my BL, and the BL will return me only the ones I have to send the message to ?
I think answering this question first will make life a whole lot easier:
and how can I know what 'this' client is ?
OperationContext.Current.GetCallbackChannel<T>
For each call the service receives there will be a client channel through which the call is made, this will give you the callback channel of the client that made that call only, this is a simple way in which you're able to distinguish your clients.
Regarding the approach to your scenario as a whole, I would first store a list of subscribers in a static dictionary as you suggested yourself, but also keep each clients callback instance along with their username:
private static Dictionary<IPriceChangeCallback, string> subscribers = new Dictionary<IPriceChangeCallback, string>();
Where IPriceChangeCallback is your callback contract and the string could be a unique Username or any identifier. So you now have the basic ability to distinguish your clients, for example say you want to publish the last received message to every client except the one who sent it, you would:
lock (subscribers)
{
foreach (var _subscriber in subscribers)
{
if (OperationContext.Current.GetCallbackChannel<IPriceChangeNotification>() == _subscriber.Key)
{
//if the person who sent the last message is the current subscriber, there is no need to
//publish the message to him, so skip this iteration
continue;
}
else
{
//GetCurrrentClient is a handy method, you can optionally include this
//in your callbacks just to let your clients know who exactly sent the publication
_subscriber.Key.PriceChangeCallback(e.Item, e.Price, e.Change, GetCurrentClient());
}
}
}
or distinguish your clients based on their usernames, which you should ideally have in your databse as well:
lock (subscribers)
{
foreach (var _subscriber in subscribers)
{
if(_subscriber.Value == "Jimmy86"))
{
//Identify a specific client by their username and don't send the notification to him
//here we send the notification to everyone but jimmy86
continue;
}
else
{
_subscriber.Key.PriceChangeCallback(e.Item, e.Price, e.Change, GetCurrentClient());
}
}
}
And again, whenever you want to find out who called the service operation, and tell your clients who sent that particular message, use the GetCurrentClient() method I mentioned earlier:
private string GetCurrentClient()
{
return clients[OperationContext.Current.GetCallbackChannel<IPriceChangeNotification>()];
}
Is this the right way ?
I'm not sure how advisable the approach above is, but I've done it before whenever I've wanted to keep a list of clients and call some method on them.
should the client send me credentials in the 'subscribe' method that I will store ?
Yes this is one common way of doing it. Have a Subscribe() operation on your service, which will be the first method your clients will call when they want to join your service:
[OperationContract(IsOneWay = true)]
public void Subscribe(string username)
{
lock (subscribers)
{
subscribers.Add(OperationContext.Current.GetCallbackChannel<IPriceChangeNotification>(), username);
}
}
I was working on a Pub/Sub Silverlight service a couple months ago, and I found this article and it's accompanying video to be invaluable.
The answer I have come up with is to implement the 'Custom UsernamePasswordValidator',
and so each service instance now KNOWS what client is connected to it (this way I don't have to pass anything in Subscribe).
When a 'publish' event arrives - I would check which user it is intended to (the same user might connect from several machines).
I would then raise a 'PriceChangeEvent' with the targeted user, and the 'PriceChangeHandler' event would be raised for all client instances.
Then, inside the event - I would check if the logged principal is the targeted user, and if so - I would call the callback function on the client machine.
This saves me the trouble of saving a list of connected clients, and also I don't need to pass anything in the 'Subscribe' method.

How can I callback the client and expose a new Channel with instance context

I'm making a WCF service with netTcpBinding which has a main lobby with multiple chatrooms which the clients can enter. The Lobby class implements ILobby as the service contract.
When a client wishes to enter a room I want to callback the client exposing a new Channel containing the InstanceContext for the room he just entered but after much searching I am doubting that this is possible.
For example on the Service side I might have
class Lobby : ILobby
{
Dictionary<string, Chatroom> rooms;
public void JoinRoom(string roomname)
{
if (rooms[roomname].TryEnter()) {}
}
}
class ChatRoom : IChatRoom
{
public bool TryEnter(string username)
{
ILobbyCallback callback =
OperationContext.Current.GetCallbackChannel<ILobbyCallback>();
// How do I do this next bit?
callback.JoinedRoom(pass some instance context here);
return true;
}
}
On the client side callback method I want
public void JoinedRoom(InstanceContext for the room on the service side)
{
// Create a new WCF proxy using above InstanceContext
// Create a WPF UI for the new room passing the proxy so it can communicate
// with the room class directly without going via the root service
}
Is this possible? What's the best practice for spawning new classes with their own contracts on the service side? Or do I just have to bundle everything into one massive MyService class and handle everything myself?
You cannot pass instance context as parameter to any operation contract. It doesn't make sense because that context has local scope. It is called "instance context" = it is context of current service instance. In duplex scenario both client and server has its own service:
Clients calls server's service through its proxy
Server calls client' service through received callback channel
Server's service instance context has meaning only on the server. It is not clear what you are trying to achieve (except very complex architecture).
If you want to share context on client you can try to pass around the instance context used for the very first proxy you created - I'm not sure if it will work but you can try it
If you want to share service instance context between multiple proxies you must develop your own IInstanceContextProvider and perhaps also your own IInstanceProvider (depending on what you want to achieve), wrap them in behavior and add them to the service. That will put whole complexity of session handling and correct instance releasing under your control (it obviously has its pros and cons).
But is it really needed? When I look at your code I see that one service and one proxy is enough. Also your JoinRoom operation doesn't need to use callback at all, it can be just request response method.