Andry
Andry

Reputation: 16875

Correctness of a callback approach for managing WCF stateful services needing to dialogue with their hosting application

I am writing a complex distributed application by taking advantage of WCF services.

Requirements

My requirements are the following:

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:

  1. A neighbour of mine calls my application's void RouteMessage(... msg) service routine in order to send me a message.
  2. 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.
  3. If I consume the message, then I'll have to send back the confirm.
  4. I will call a neighbour of mine's void RouteDeliveryConfirmMessage(... msg) service routine in order to let it route that delivery confirm message.
  5. 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:

  1. I do not want to bother you with my application design issues and targets.
  2. 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.
  3. 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

Upvotes: 2

Views: 276

Answers (1)

Joel C
Joel C

Reputation: 5567

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.

Upvotes: 1

Related Questions