I don't have very much experience using MSMQ and someone recommended I look at MassTransit to help implement a solution but I am having a hard time trying to figure out if using MassTransit + MSMQ is the right tool for the job.
We have a WPF application (3.5) that is used by multiple users. Persistence is done from the application (via NHibernate) to the database. Up until now, users would periodically refresh there view's in order to ensure they had the latest updates. However, we now want to send notification to each application instance when an entity is persisted using pub/sub messaging. The client applications are all run within the same domain and should be able to fulfill most dependencies required (e.g. installation of MSMQ on client machines).
To summarize: Client1 开发者_如何学Pythonpublishes an update message ---> ????? ----> All other active clients receive it.
As I am new to MSMQ, I'm not even sure what the architecture should look like.
- Does each client machine need to have a local MSMQ queue to receive messages?
- Do we just need to create a queue on a server and all clients listen for messages there? If so, will just a queue(s) suffice or do we need to create a service in order to distribute the messages correctly?
- Is this even the right tool for the job?
I created a little POC hoping that it would work, but I ended up with what I think is termed "Competing Consumer". What I would like to happen is one application instance sends a message, and all application instances receive it.
Any suggestions, direction or advice would be greatly appreciated!
Here is the POC view model code (note - in my mind localhost would be replaced with a server that each app instance would send messages to):
Update: Added Network Key (kittens)
Update: I've uploaded the sample code https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0ByDMJXKmYB7zMjBmYzYwNDEtYzMwOC00Y2RhLTk1MDYtZjc0NTI2M2E3Y2Qy&hl=en_US
public class MainViewModel : IDisposable, INotifyPropertyChanged
{
private Guid id;
public MainViewModel()
{
id = Guid.NewGuid();
Publish = new RelayCommand(x => OnExecutePublishCommand(), x => !string.IsNullOrEmpty(Message));
Messages = new ObservableCollection<MessagePayload>();
Bus.Initialize(sbc =>
{
sbc.UseMsmq();
sbc.SetNetwork("Kittens");
sbc.VerifyMsmqConfiguration();
sbc.UseMulticastSubscriptionClient();
sbc.ReceiveFrom(string.Format("msmq://localhost/{0}", ConfigurationManager.AppSettings["queue"]));
sbc.Subscribe(subs => subs.Handler<MessagePayload>(OnReceiveMessage));
});
}
public ICommand Publish { get; private set; }
private string message;
public string Message
{
get { return message; }
set
{
message = value;
SendPropertyChanged("Message");
}
}
public ObservableCollection<MessagePayload> Messages { get; private set; }
private void OnReceiveMessage(MessagePayload msg)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
new Action(() => Messages.Add(msg)));
}
private void OnExecutePublishCommand()
{
Bus.Instance.Publish(new MessagePayload{ Sender= id, Message = Message});
Message = null;
}
public event PropertyChangedEventHandler PropertyChanged;
private void SendPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public void Dispose()
{
Bus.Instance.Dispose();
}
}
Update: Just in case anyone is interested we ended up splitting our "Event Bus" into two. For the server, we are using MassTransit. However, because Mass Transit requires "full profile" (.NET 4.0) and we wanted to stick with "client profile" for our WPF instances we are using SignalR for the client side event bus. An "observer" on the server event bus forwards messages to the client event bus.
All the machines on the same network can subscribe to given messages. They all need a local queue to read off of. Don't read off remote queues unless there's absolutely no other way.
What you described generally seems right. There's an message that gets published to all subscribers, they'll receive it and update their state. I have not worked with WPF in a while but generally how you're handling it seems acceptable. Note that it might take a little time to spin up the MT configuration, so you might want to do that on a background thread so you aren't blocking the UI.
Additionally, using the Multicast Subscription, you need to set a network key. It's automatically set to the machine name if not provided. You'll want to make sure they can talk to each other successfully.
精彩评论