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 publishes 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.
Related
I'm currently trying to update application that was originally .NET Core 3.1 using MassTransit 6.3.2. It is now configured to use .NET 6.0 and MassTransit 7.3.0
Our application uses MassTransit to send messages via Azure Service Bus, publishing messages to Topics, which then have other Subscribers listening to those Topic.
Cut down, it was implemented like so:
// Program.cs
services.AddMassTransit(config =>
{
config.AddConsumer<AppointmentBookedMessageConsumer>();
config.AddBus(BusControlFactory.ConfigureAzureServiceBus);
});
// BusControlFactory.cs
public static class BusControlFactory
{
public static IBusControl ConfigureAzureServiceBus(IRegistrationContext<IServiceProvider> context)
{
var config = context.Container.GetService<AppConfiguration>();
var azureServiceBus = Bus.Factory.CreateUsingAzureServiceBus(busFactoryConfig =>
{
busFactoryConfig.Host("Endpoint=sb://REDACTED-queues.servicebus.windows.net/;SharedAccessKeyName=MyMessageQueuing;SharedAccessKey=MyKeyGoesHere");
busFactoryConfig.Message<AppointmentBookedMessage>(m => m.SetEntityName("appointment-booked"));
busFactoryConfig.SubscriptionEndpoint<AppointmentBookedMessage>(
"my-subscriber-name",
configurator =>
{
configurator.UseMessageRetry(r => r.Interval(5, TimeSpan.FromSeconds(60)));
configurator.Consumer<AppointmentBookedMessageConsumer>(context.Container);
});
return azureServiceBus;
}
}
}
It has now been changed and upgraded to the latest MassTransit and is implemented like:
// Program.cs
services.AddMassTransit(config =>
{
config.AddConsumer<AppointmentBookedMessageConsumer, AppointmentBookedMessageConsumerDefinition>();
config.UsingAzureServiceBus((context, cfg) =>
{
cfg.Host("Endpoint=sb://REDACTED-queues.servicebus.windows.net/;SharedAccessKeyName=MyMessageQueuing;SharedAccessKey=MyKeyGoesHere");
cfg.Message<AppointmentBookedMessage>(m => m.SetEntityName("appointment-booked"));
cfg.ConfigureEndpoints(context);
});
// AppointmentBookedMessageConsumerDefinition.cs
public class AppointmentBookedMessageConsumerDefinition: ConsumerDefinition<AppointmentBookedMessageConsumer>
{
public AppointmentBookedMessageConsumerDefinition()
{
EndpointName = "testharness.subscriber";
}
protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator, IConsumerConfigurator<AppointmentBookedMessageConsumer> consumerConfigurator)
{
endpointConfigurator.UseMessageRetry(r => r.Interval(5, TimeSpan.FromSeconds(60)));
}
}
The issue if it can be considered one, is that I can't bind to a subscription that already exists.
In the example above, you can see that the EndpointName is set as "testharness.subscriber". There was already a subscription to the Topic "appointment-booked" from prior to me upgrading. However, when the application runs, it does not error, but it receives no messages.
If I change the EndpointName to "testharness.subscriber2". Another subscriber appears in the Azure Service Bus topic (via the Azure Portal) and I start receiving messages. I can see no difference in the names (other than the change that I placed, in this case: the "2" suffix).
Am I missing something here? Is there something else I need to do to get these to bind? Is my configuration wrong? Was it wrong? While I'm sure I can get around this by managing the release more closely and removing unneeded queues once they're using new ones - it feels like the wrong approach.
With Azure Service Bus, ForwardTo on a subscription can be a bit opaque.
While the subscription may indeed visually indicate that it is forwarding to the correctly named queue, it might be that the queue was deleted and recreated at some point without deleting the subscription. This results in a subscription that will build up messages, as it is unable to forward them to a queue that no longer exists.
Why? Internally, a subscription maintains the ForwardTo as an object id, which after the queue is deleted points to an object that doesn't exist – resulting in messages building up in the subscription.
If you have messages in the subscription, you may need to go into the portal and update that subscription to point to the new queue (even though it has the same name), at which point the messages should flow through to the queue.
If there aren't any messages in the subscription (or if they aren't important), you can just delete the subscription and it will be recreated by MassTransit when you restart the bus.
I have Windows service written in C#. Earlier we were using Event hubs with multiple partitions for message queuing. We recently moved to Kafka. For implementing Event hubs in c# , we have IEventProcessor.ProcessEventsAsync , which keeps listening to event hub notifications and is triggered whenever a message is posted to event hub , which runs asynchronously in the background
I did not find any equivalent method in Kafka.
My requirement here is to subscribe to a Kafka topic and continuously consume messages. When a message is consumed, some other operations are also supposed to executed for that message. For each message say the execution time takes around 15 mins, I want the Kafka consumer to consume all messages and keep it in queue as when it receives and writes it into a file. Other process should read the file, pick the message and do other operations. I want all of them to run simultaneously/parallelly.
PS : I have written a console application which can produce and consume one message.What I'm looking for is queuing and parallelism.
For paralellism Kafka implements what's known as consumer groups. Kafka stores the "offsets" (read: key of record across a topic) and also stores the offsets of where a given consumer group is also at in processing the records. This should allow you to create new consumer instances on the fly using the same program, and by changing the group allow two programs to consume the same data in paralell for different tasks.
I found this link helpful when I was creating my first consumer as well, in case you found a way to create it without a groupId: http://cloudurable.com/blog/kafka-tutorial-kafka-consumer/index.html
Hope this helps!
Have look at Silverback: https://silverback-messaging.net. It abstracts many of those concerns and the basic usage is as simple as this:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddSilverback()
.WithConnectionToMessageBroker(options => options.AddKafka())
.AddKafkaEndpoints(
endpoints => endpoints
.Configure(
config =>
{
config.BootstrapServers = "localhost:9092";
})
.AddInbound(
endpoint => endpoint
.ConsumeFrom("my-topic")
.DeserializeJson(serializer => serializer.UseFixedType<SomeMessage>())
.Configure(
config =>
{
config.GroupId = "test-consumer-group";
config.AutoOffsetReset = AutoOffsetReset.Earliest;
})))
.AddSingletonSubscriber<MySubscriber>();
}
}
public class MySubscriber
{
public Task OnMessageReceived(SomeMessage message)
{
// TODO: process message
}
}
We are currently using self-hosted NServiceBus to handle queuable messages in our system. Right now there are instances where a queued message might fail on the first try and work on the automatic retries.
Right now we are logging on all failures, but we really don't care (at least for alerts) if a message failed the first time but worked on a re-try. What we do want to get alerted to is if all retries failed and a message goes into the error queue.
Is there any way native to NServiceBus to have code run when it's moving a message to the error queue?
If you are using the rest of the Service Platform (and you should!) that means that your error queue will have ServiceControl sitting on top of it, reading messages out of error and audit and persisting the details to its database so that it can serve up that information via its REST API to ServicePulse (for monitoring system health and uptime) and ServiceInsight (for exploration and debugging.)
Assuming you are using ServiceControl, it's pretty easy to have an endpoint subscribe to MessageFailed events that are published by ServiceControl. I explained how to do it in my blog post Failed Message Notification with ServiceControl.
This way, each endpoint doesn't have to be responsible for this task, and it is accomplished asynchronously by a centralized error monitoring endpoint.
It appears the correct way to do this is to create a custom implementation of IManageMessageFailures and registering the custom fault manager curing configuration time.
An example of this is:
public class CustomFaultManager : IManageMessageFailures
{
private readonly IManageMessageFailures faultManager;
static CustomFaultManager()
{
Configure.Instance.MessageForwardingInCaseOfFault();
}
public CustomFaultManager()
{
faultManager = new FaultManager();
((FaultManager)faultManager).ErrorQueue = ConfigureFaultsForwarder.ErrorQueue;
}
void IManageMessageFailures.SerializationFailedForMessage(TransportMessage message, Exception e)
{
faultManager.SerializationFailedForMessage(message, e);
}
void IManageMessageFailures.ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
{
faultManager.ProcessingAlwaysFailsForMessage(message, e);
//Custom code goes here
}
void IManageMessageFailures.Init(Address address)
{
faultManager.Init(address);
}
}
from https://github.com/Particular/NServiceBus/issues/463
I am having some trouble implementing the right patterns for a work project and I don't want to precede until I am satisfied with the right design strategy.
The project is based around Genesys Computer Telephony Integration (CTI) Platform. Essentially, utilizing a SDK provided by Genesys, a single client subscribes to a number of Genesys services (or TServers) running remotely. The client then registers a whole heap of Directory Numbers (DN's) associated to a particular TServer and waits for call events. When an event occurs, it is captured by the client and stored in a database. A number of other operations are executed, which is irrelevant at this stage. A lot of the communication work is handled by the Genesys ProtocolManager object, so a single event handler captures event data across all clients, which in turn is handled by a EventBrokerService. Here is a simple code to illustrate the connection process, registration of a single DN and the event function:
EventBrokerService eventBrokerService;
using (var client = new TServerProtocol(
new Endpoint(
new Uri("tcp://tserver01:11234"))))
{
client.Open();
eventBrokerService = BrokerServiceFactory.CreateEventBroker(client);
eventBrokerService.Activate();
eventBrokerService.Register(this.OnEvent);
RequestRegisterAddress requestRegisterAddress =
RequestRegisterAddress.Create("977845873",
RegisterMode.ModeMonitor,
ControlMode.RegisterDefault,
AddressType.DN);
IMessage response = client.Request(requestRegisterAddress);
}
and then we listen for events (there are many different events):
private void OnEvent(IMessage response)
{
switch (response.Id)
{
case EventACK.MessageId:
//do something
break;
case EventLinkConnected.MessageId:
var ev = response as EventLinkConnected;
//Insert event into DB and perform some other operations...
break;
}
}
The Genesys Platform, comes with another component called a Genesys Configuration server. The config server holds all of the TServer details, including the DN information and a whole bunch of other "objects". It is really just a fancy DBMS. The difference is, you can also subscribe to the config server and register for CRUD events (i.e. CreateEvent, UpdateEvent etc...). Without illustrating the code, the concept is similar to the one above. (i.e. You can register to a number of different Configuration Servers and listen for CRUD events).
For the most part, I have covered the above well and I am satisfied with the implementation so far. What I am trying to achieve is as follows:
I am attempting to implement a distributed system. In a nutshell, the system will consist of 2 components. Monitoring Services and Dispatcher Service components (they will all be Windows Services)
Monitoring Service Component
The "Monitoring Service(s)" connect to 1 or many T Servers to monitor for call events
The monitoring service will ALSO subscribe to a dispatcher service
Dispatcher Service Component
The "Dispatcher Service" connects to 1 or more Configuration Servers and waits for CRUD events.
Once an event occurs (i.e. a new DN was added on the config server), the dispatcher captures the creation event, and notifies all monitoring service subscribers. Subsequently, the dispatcher will also update a local database, so the DN information is preserved for redundancy (in case dispatcher can not connect to a Configuration Server).
The monitoring subscriber, to whom the newly created DN belongs (distinguished by a unique DBID and TServerID identifiers) will accept the DN, and register it for listening events (similarly illustrated in the first code snippet). The monitoring subscriber who does not possess the required TServer connection will drop the received request, naturally.
The Dispatcher can also receive newly added TServers, but this time around, it will make the decision which monitoring service it want's to utilize in order for that monitoring service to make ANOTHER connection. This will be determined by factors such as the number of current sessions running on a monitoring service or the how much memory a single service is chewing up at the time.
I have come up with some basic concepts and here is some of the code to illustrate what I have done thus far:
The communication method I have chosen is WCF with NetTcpBinding, so for the simple part, I have exposed an interface:
[ServiceContract(Namespace = "urn:Netwatch",
SessionMode = SessionMode.Required,
CallbackContract = typeof(IDisMonServiceCallback))]
public interface IDisMonService
{
[OperationContract]
bool Subscribe(string uid);
[OperationContract(IsOneWay = true)]
void Unsubscribe(string uid);
}
[ServiceContract(Namespace="urn:Netwatch")]
public interface IDisMonServiceCallback
{
[OperationContract]
bool DNRegistered(int tServerId, string dnEntry);
}
and on the dispatcher, I have implemented it:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class DisMonService : IDisMonService
{
private ConcurrentDictionary<string, IDisMonServiceCallback> subscribers = new ConcurrentDictionary<string, IDisMonServiceCallback>();
public IDisMonServiceCallback this[string uid]
{
get
{
IDisMonServiceCallback callback;
if (!subscribers.TryGetValue(uid, out callback))
return null;
return callback;
}
}
public List<IDisMonServiceCallback> GetAllServiceCallbacks()
{
return new List<IDisMonServiceCallback>(subscribers.Values);
}
public bool Subscribe(string uid)
{
IDisMonServiceCallback callback = GlobalHelper.Callback<IDisMonServiceCallback>();
if (!subscribers.ContainsKey(uid))
if (!subscribers.TryAdd(uid, callback))
return false;
return true;
}
public void Unsubscribe(string uid)
{
IDisMonServiceCallback callback;
if (subscribers.ContainsKey(uid))
if (!subscribers.TryRemove(uid, out callback))
return;
return;
}
}
From the code above, it is obvious that each subscribing monitoring service has a unique identifier, that way the right service callback context is retrieved (in case I decide to do some other funky operations).
This is where my dilemma essentially begins. To cut the long story short, my question(s) are as follow:
How do I deal with DisMonService class when attempting to pass on messages to all subscribers from within the Dispatcher service. i.e. new DN has been added, let us call the DisMonService class and notify all subscribers.
What would be the most optimal pattern to implement in dealing with updates to all subscribers from within DisMonServie
At the moment my dummy client connects to the dispatcher, and it registers itself. Moving forward, what is the best way to access the DisMonService class.
I hope I am not confusing anybody at what I am trying to ask. I guess what I am really trying to find is best way to implement the above system, any suggestions and such. Some code samples and snippets would really be helpful.
This is my first post here so I apologise to anybody if I haven't explained myself to the forum's standards.
I am writing a complex distributed application by taking advantage of WCF services.
Requirements
My requirements are the following:
There are many stations (PCs) having the same software running on them (the application I need to develop).
Every station will send messages to other stations (every station has a neighbourhood). The stations will route messages in order to reach the final destination for each message (it is a P2P context where local routing is necessary).
When a message is delivered by a station, that station has to be sure that message reaches the destination (another station somewhere in the world). For performance reasons I cannot create services that route my message using synchronous approaches (a service call would last too much time, polling has never been a good idea). For this reason a feedback messaging is considered: once the message reaches its destination, the destination will send a I-Received-The-Message message back to the sender.
With this approach, I need my stations to implement services in order to route feedback messages. Basically, everytime a message is delivered, a task table is filled with one record indicating that a message delivery needs to be confirmed. If no feedback message for that message reaches the sender station, the sender station will try to send the original message again.
What I cannot do
I know that for P2P scenarios there is a well provided service type, but I cannot use it for some reasons (I will not bother you with these reasons).
Please, accept the requirements I listed above.
My solution
I adopted this solution:
Two service contracts define calls for sending (routing) normal messages and reply/delivery-confirm messages:
/* Routing routines */
[ServiceContract]
public interface IMessageRouting {
/* When a client receives the message, in the MyMessage type
there are some fields that helps the current station to
decide which neighbour station the received packet will
be routed to */
[OperationContract(IsOneWay = true)]
void RouteMessage(MyMessage msg);
}
/* Delivery-Confirm messaging */
[ServiceContract]
public interface IDeliveryConfirmMessageRouting {
/* When the final destination (THE FINAL DESTINATION
ONLY, not an intermediate hop station) obtains a
message, it will route back to the sender a reply message */
[OperationContract(IsOneWay = true)]
void RouteDeliveryConfirmMessage(MyDeliveryConfirmMessage dcmsg);
}
Here are the services implementations:
/* This service will be self-hosted by my application in order
to provide routing functionality to other stations */
[ServiceBehaviour(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Single)]
public class StationMessagingService : IMessageRouting {
/* Constructing the service */
public StationMessagingService() { ... }
// Implementation of serive operations
public void RouteMessage(MyMessage msg) {
...
}
}
And the delivery confirm service...
/* This service will be self-hosted by my application in order
to provide delivery confirm message routing functionality
to other stations */
[ServiceBehaviour(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Single)]
public class StationDeliveryConfirmService : IDeliveryConfirmMessageRouting {
/* This service is particular, I will discuss the following lines
before the constructors in the next paragraph after first
typing all the code */
public delegate void DeliveryMessageReceivedEventHandler(
object sender, String DeliveryMessageReceivedEventArgs);
public event DeliveryMessageReceivedEventHandler DeliveryMessageReceived;
/* Constructing the service */
public StationDeliveryConfirmService() { ... }
// Implementation of serive operations
public void RouteDeliveryConfirmMessage(MyDeliveryConfirmMessage dcmsg) {
...
/* In the end fire the event only if I am the destination
of this message, otherwise I must route this message */
if (...) { /* Omitting condition for clarity */
this.DeliveryMessageReceived(this,
"A delivery confirm message has arrived with this info: " +
dcmsg.Info()); /* Info contains string info */
}
}
}
At this point I am ready to host my services:
/* My program */
public class Program {
// Program's entry point
static void Main(string[] args) {
// Defining the delivery check table (I have a special type/class for this)
DeliveryCheckTable DCT = new DeliveryCheckTable(...);
// Creating services
StationMessagingService SMS = new StationMessagingService();
StationDeliveryConfirmService SDCS = new StationDeliveryConfirmService();
// Event handlers registration (expalinations in the next paragraph)
SDCS.DeliveryMessageReceived += Program.DeliveryMessageReceivedHandler;
// Hosting
Uri MyBaseAddress = new Uri("http://services.myapplication.com/Services/");
using (ServiceHost hostMessagingSvc = new ServiceHost(SMS, MyBaseAddress),
ServiceHost hostDeliveryConfirmSvc = new ServiceHost(SDCS,
MyBaseAddress)) {
// Info on endpoints in config file
// Running services
hostMessagingSvc.Open();
hostDeliveryConfirmSvc.Open();
// ...
// Application's other operations
// For clarity and simplicity, just consider that the code
// here is some kind of infinite loop with actions in it
// where the GUI can commununicate with the user, somewhere
// in the application's code, there is a List where all
// sent messages are inserted and, when a delivery
// confirm arrives, the corresponding item in the list is cleared.
// The list is rendered as a table by the GUI.
// ...
/*** Arriving here somehow when my application needs to be shut down. ***/
// Closing services
hostMessagingSvc.Close();
hostDeliveryConfirmSvc.Close();
}
}
/* Event handlers for the delivery confirm messages
service (please be patient, these lines of code
will be discussed in short) */
static void DeliveryMessageReceivedHandler(object sender,
string DeliveryMessageReceivedEventArgs) {
/* Here I will perform actions on the List
deleting the row containing the ID of the
message sent whose confirm has arrived */
}
} /* Program class */
Some explainations
As you can see by the code (a code that runs and works correctly), I managed to let my hosted service communicate with the hosting application via callbacks.
So the typic flow is the following:
A neighbour of mine calls my application's void RouteMessage(... msg) service routine in order to send me a message.
In the service routine, I will check the message header and look for destination, if the destination is not me, I will route it to another neighbour of mine (closer to the destination), otherwise I will consume the message.
If I consume the message, then I'll have to send back the confirm.
I will call a neighbour of mine's void RouteDeliveryConfirmMessage(... msg) service routine in order to let it route that delivery confirm message.
Every station routes messages and, if a station finds out to be the destination, it consumes the message. but when the message is a confirm, and a station is the destination, that station will consume the confirm and will fire the DeliveryMessageReceived event causing the handler routine to start and deleting the corresponding table entry (so that the sender will have the ack knowing it is no more necessary to resend the message cause it was correctly received).
Application context
As you can see, I did not provide many details about my application, just the necessary in order to understand the code... This happens mainly for these reasons:
I do not want to bother you with my application design issues and targets.
There is much to say about why I chose some approaches, but that would be very context specific, and I would probably goig too deep in an unrelated topic.
Some may ask: "Why do you need to make a station route a message instead of providing direct messaging from the sender to the destination?", "What's the purpose of routing? Do not services let you call directly the destination station's service endpoint?". Well, I need to manage Peers in a network where peers have just a little knowledge of the entire network. New peers joins the existing one and they only have links to some station's endpoints. A peer does not need to have full knowledge of the network, it has a neighbourhood and it uses that. However, consider this as part of my requirements.
The question
OK, time for questioning. Just one question.
What I described here is a solution I managed to develop in order to let a service communicate with its hosting application. This is a problem for which I did not find a correct pattern. So I found this way of coding it...
Is it good?
Is it a best practice?
Is it a bad practice?
Should that be bad practice, what's the correct pattern/way of doing this? How to solve communication issues betwen the service and its hosting application?
Thankyou
Just one question. What I described here is a solution I managed to develop in order to let a service communicate with its hosting application.
What you described here is an approach to delivering messages from one endpoint to another on a network, without getting into any specific details of how you're planning to configure and identify the client endpoints between nodes, or why you wouldn't just send the message directly to the intended recipient. Nowhere did you attempt to discuss the very complicated matter of how your WCF service actually interacts in any way with your GUI application in a thread-safe manner. THAT would be your service communicating with its hosting application.
Although I don't have a full understanding of your application, I think what you're actually trying to accomplish is "plumbing" that is already available as a feature of WCF. I would recommend looking into WCF Discovery:
WCF Discovery
Windows Communication Foundation (WCF) provides support to enable services to be discoverable at runtime in an interoperable way using the WS-Discovery protocol. WCF services can announce their availability to the network using a multicast message or to a discovery proxy server. Client applications can search the network or a discovery proxy server to find services that meet a set of criteria. The topics in this section provide an overview and describe the programming model for this feature in detail.