c# - 用于管理需要与其托管应用程序进行对话的WCF状态服务的回调方法的正确性

标签 c# .net wcf service

我正在利用WCF服务编写一个复杂的分布式应用程序。

要求

我的要求如下:


许多工作站(PC)上运行着相同的软件(我需要开发的应用程序)。
每个站点都将向其他站点发送消息(每个站点都有一个邻居)。站点将路由消息以到达每个消息的最终目的地(这是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 */


一些说明

从代码(运行和正常工作的代码)可以看出,我设法使托管服务通过回调与托管应用程序通信。
因此,典型流程如下:


我的一个邻居调用了我的应用程序的void RouteMessage(... msg)服务例程,以便向我发送消息。
在服务例程中,我将检查消息头并查找目标,如果目标不是我,则将其路由到我的另一个邻居(更接近目标),否则将使用该消息。
如果我使用了该消息,则必须发回确认。
我将呼叫我的void RouteDeliveryConfirmMessage(... msg)服务例程的邻居,以使其路由该传递确认消息。
每个站点都路由消息,如果发现站点是目的地,它将使用该消息。但是,当消息是确认消息,而工作站是目的地时,该工作站将使用确认并触发DeliveryMessageReceived事件,从而导致处理程序例程启动并删除相应的表条目(这样,发送方将获得确认知道不再需要重新发送该消息(因为已正确接收该消息)。


应用环境

如您所见,我没有提供有关我的应用程序的许多细节,只是为了理解代码所必需的...发生这种情况的主要原因是:


我不想打扰我的应用程序设计问题和目标。
关于为什么选择某些方法,还有很多要说的话,但是那将是非常特定于上下文的,并且我可能会在一个无关的主题上过分深入。
有人可能会问:“为什么要使站点路由消息而不是提供从发件人到目的地的直接消息传递?”,“路由的目的是什么?服务不能让您直接呼叫目标站点的服务端点吗? ”。好吧,我需要在一个网络中管理对等网络,对等网络对整个网络只有一点点了解。新的对等方加入现有的对等方,并且它们仅具有指向某些站点端点的链接。对等点不需要完全了解网络,它可以使用邻居。但是,将此视为我的要求的一部分。


问题

好的,该提问了。只是一个问题。
我在这里描述的是我设法开发的一种解决方案,以使服务与其托管应用程序进行通信。这是我没有找到正确模式的问题。所以我发现了这种编码方式...
好吗?
这是最佳做法吗?
这是不好的做法吗?
那应该是不好的做法吗,正确的做法/方式是什么?如何解决服务及其托管应用之间的通信问题?

谢谢

最佳答案

只是一个问题。我在这里描述的是我设法开发的一种解决方案,以使服务与其托管应用程序进行通信。


您在此处描述的是一种将消息从一个端点传递到网络上的另一个端点的方法,而无需深入了解计划如何配置和标识节点之间的客户端端点的特定细节,或者为什么不只是发送邮件。邮件直接发送给目标收件人。您从未尝试过讨论WCF服务实际上如何以线程安全的方式与GUI应用程序进行任何交互的非常复杂的问题。那将是您的服务与其托管应用程序进行通信。

尽管我对您的应用程序不完全了解,但我认为您实际上要完成的工作是“管道”,它已作为WCF的功能提供。我建议研究WCF发现:


  WCF Discovery
  
  Windows Communication Foundation(WCF)支持使用WS-Discovery协议以互操作方式在运行时发现服务。 WCF服务可以使用多播消息或发现代理服务器向网络声明其可用性。客户端应用程序可以搜索网络或发现代理服务器以查找符合一组条件的服务。本节中的主题提供了概述,并详细描述了此功能的编程模型。

关于c# - 用于管理需要与其托管应用程序进行对话的WCF状态服务的回调方法的正确性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6077105/

相关文章:

c# - 在 List<> 购物篮中显示重复项 C#

c# - 当您通过 .NET Remoting 从远程对象返回 Stream 时到底发生了什么

c# - 如何在 Asp.Net Web API 上实现 Https/SSL 连接?

.net - c#编码转换?

WCF 4 - TransportWithMessageCredential 使用 X.509 证书进行传输和消息安全

c# - WPF 中的 OpenGL 控件 - 如何?

c# - 使用 ASP.NET WebAPI 返回 bool 值以供 Ajax GET 请求使用

.net - .NET/Oracle 架构的数据处理逻辑的最佳位置

javascript - 如何从 javascript 客户端将参数传递到 WCF Rest 服务的方法?

wcf - 是否可以在自托管 WCF 服务中使用 ASP.NET MembershipProvider/RoleProvider?