Правильность подхода обратного вызова для управления сервисами с отслеживанием состояния WCF, нуждающимися в диалоге с их хост-приложением - PullRequest
2 голосов
/ 21 мая 2011

Я пишу сложное распределенное приложение, пользуясь услугами WCF.

Требования

Мои требования следующие:

  • На многих станциях (ПК) работает одно и то же программное обеспечение (приложение, которое мне нужно разработать).
  • Каждая станция будет отправлять сообщения другим станциям (каждая станция имеет район). Станции будут маршрутизировать сообщения для достижения конечного пункта назначения для каждого сообщения (это контекст P2P, где необходима локальная маршрутизация).
  • Когда сообщение доставляется станцией, эта станция должна быть уверена, что сообщение достигает пункта назначения (другой станции где-то в мире). По соображениям производительности я не могу создавать службы, которые маршрутизируют мое сообщение с использованием синхронных подходов (вызов службы будет длиться слишком долго, опрос никогда не был хорошей идеей). По этой причине рассматривается сообщение с обратной связью: как только сообщение достигает пункта назначения, пункт назначения отправляет сообщение I-Received-The-Message обратно отправителю.
  • При таком подходе мне нужно, чтобы мои станции реализовывали сервисы для маршрутизации сообщений обратной связи. По сути, каждый раз, когда доставляется сообщение, таблица задач заполняется одной записью, указывающей, что доставка сообщения должна быть подтверждена. Если никакое сообщение обратной связи для этого сообщения не достигает станции отправителя, станция отправителя снова попытается отправить исходное сообщение.

Что я не могу сделать

Я знаю, что для сценариев P2P есть хорошо предоставленный тип сервиса, но я не могу использовать его по некоторым причинам (я не буду беспокоить вас по этим причинам). Пожалуйста, примите требования, которые я перечислил выше.

Мое решение

Я принял это решение:

Два сервисных контракта определяют вызовы для отправки (маршрутизации) обычных сообщений и сообщений ответа / подтверждения доставки:

/* 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);
}

Вот реализации служб:

/* 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) {
      ...
   }
}

И служба подтверждения доставки ...

/* 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 */
      }
   }
}

На данный момент я готов разместить свои услуги:

/* 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 */

Некоторые пояснения

Как вы можете видеть по коду (коду, который работает и работает правильно), мне удалось разрешить моей размещенной службе взаимодействовать с приложением хостинга через обратные вызовы. Таким образом, типичный поток выглядит следующим образом:

  1. Моя соседка вызывает сервисную программу void RouteMessage(... msg) моего приложения, чтобы отправить мне сообщение.
  2. В процедуре обслуживания я проверю заголовок сообщения и поищу пункт назначения. Если пункт назначения не я, я направлю его к другому моему соседу (ближе к пункту назначения), в противном случае я буду использовать сообщение.
  3. Если я получу сообщение, мне придется отправить подтверждение.
  4. Я позвоню в соседнюю сервисную подпрограмму void RouteDeliveryConfirmMessage(... msg) моего соседа, чтобы позволить ей направить это сообщение о подтверждении доставки.
  5. Каждая станция направляет сообщения и, если станция обнаруживает, что является пунктом назначения, она потребляет сообщение. но когда сообщение является подтверждением, а станция является пунктом назначения, эта станция будет использовать подтверждение и сгенерирует событие DeliveryMessageReceived, вызывающее запуск процедуры обработчика и удаляющее соответствующую запись таблицы (так что отправитель получит подтверждение зная, что больше нет необходимости повторно отправлять сообщение, потому что оно было правильно получено).

Контекст приложения

Как видите, я не предоставил много подробностей о моем приложении, просто необходимых для понимания кода ... Это происходит в основном по следующим причинам:

  1. Я не хочу беспокоить вас своими проблемами и целями разработки приложений.
  2. Многое можно сказать о том, почему я выбрал некоторые подходы, но это будет зависеть от конкретного контекста, и я, вероятно, слишком углублюсь в несвязанную тему.
  3. Некоторые могут спросить: «Почему вам нужно заставить станцию ​​маршрутизировать сообщение, а не предоставлять прямой обмен сообщениями от отправителя к получателю?», «Какова цель маршрутизации? Разве службы не позволяют вам напрямую вызывать станцию ​​назначения конечная точка обслуживания? Что ж, мне нужно управлять одноранговыми узлами в сети, где одноранговые узлы немного знают всю сеть. Новые одноранговые узлы присоединяются к существующему, и у них есть только ссылки на конечные точки некоторых станций. Узлу не нужно иметь полное знание сети, у него есть соседство, и он использует это. Однако рассмотрите это как часть моих требований.

Вопрос

ОК, время для допроса. Всего один вопрос. То, что я описал здесь, - это решение, которое мне удалось разработать, чтобы позволить службе взаимодействовать с приложением хостинга. Это проблема, для которой я не нашел правильный шаблон. Так что я нашел этот способ его кодирования ... Это хорошо? Это лучшая практика? Это плохая практика? Если это плохая практика, каков правильный способ / способ сделать это? Как решить коммуникационные проблемы между сервисом и его хостингом?

Thankyou

1 Ответ

1 голос
/ 21 мая 2011

Всего один вопрос. То, что я описал здесь, - это решение, которое мне удалось разработать, чтобы служба могла взаимодействовать с приложением хостинга.

То, что вы описали здесь, - это подход к доставке сообщений от одной конечной точки к другой в сети, не вдаваясь в какие-либо конкретные детали того, как вы планируете настраивать и идентифицировать клиентские конечные точки между узлами, или почему вы этого не сделаете просто отправьте сообщение напрямую предполагаемому получателю. Нигде вы не пытались обсудить очень сложный вопрос о том, каким образом ваша служба WCF каким-либо образом взаимодействует с приложением с графическим интерфейсом в поточно-ориентированном режиме. ЭТО будет вашим сервисом для связи с приложением хостинга.

Несмотря на то, что у меня нет полного понимания вашего приложения, я думаю, что вы на самом деле пытаетесь выполнить «подключение», которое уже доступно в качестве функции WCF. Я бы порекомендовал посмотреть в WCF Discovery:

WCF Discovery

Windows Communication Foundation (WCF) обеспечивает поддержку, позволяющую обнаруживать службы во время выполнения совместимым образом с использованием протокола WS-Discovery. Службы WCF могут сообщать о своей доступности сети с помощью многоадресного сообщения или прокси-серверу обнаружения. Клиентские приложения могут выполнять поиск в сети или на прокси-сервере обнаружения, чтобы найти службы, которые соответствуют набору критериев. Темы в этом разделе предоставляют обзор и подробно описывают модель программирования для этой функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...