在应用程序终止时,WCF 中 IsOneWay=true 的方法会发生什么情况

发布于 2024-07-10 02:05:55 字数 292 浏览 13 评论 0原文

我有一个客户端应用程序,它偶尔会通知其服务进度。 对服务的方法调用标记为 IsOneWay=true,因为通知不需要任何返回值,而且我不想延迟。

客户端可能会向服务发出错误通知,然后终止。

问题是:单向方法调用在发送消息后是否返回调用者代码? 或者它将消息排队,然后由另一个线程发送?

两个进程(客户端和服务)位于同一台机器上,我注意到有时(当机器过载时)服务不会收到错误通知。 我怀疑我提到的第二种选择会发生,但我不确定。

如果我是对的,我如何确保通知已发送并保留该方法?

I have a client application that once in while notifies about its progress a service.
The method call to the service is marked with IsOneWay=true, because the notification doesn't need any return value and I don't want to delay.

The client may notify about errors to the service, and afterward it terminates.

The question is: does a oneway method call returns to the caller code after it sent the message? or it queues the message and later on it is sent by another thread?

The two processes (the client and the service) are on the same machine, and I noticed that sometimes (when the machine is overloaded) the service doesn't get the error notification. I suspect that the second option I mentioned happens, but I am not sure.

If I am right, how can I make sure the notification is send and keep the method oneway?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

猫烠⑼条掵仅有一顆心 2024-07-17 02:05:57

我同意蒂莫西的观点。 我还想补充一点,WCF 服务为传入消息保留一个队列。 如果服务无法像消息传入一样快地处理消息,则该队列可能会变满。当传入队列变满时,WCF 将丢弃新消息。

我不确定如果单向消息被丢弃,客户端会发生什么。 我假设没有抛出异常/错误,但我不确定。

I agree with Timothy. I also want to add that the WCF service keeps a queue for incoming messages. That queue may become full if the service isn't able to process messages as fast as they are coming in. When the incoming queue becomes full, WCF will drop new messages.

I'm not sure what happens on the client side if one-way messages are dropped though. I assume that no exception/fault is thrown but I don't know that for sure.

柒夜笙歌凉 2024-07-17 02:05:56

我遇到了类似的问题(单向调用不执行任何操作或抛出异常)。 我发现负责将方法参数从 xml 转换回对象的反序列化器正在创建一个异常。 我的服务方法从未被访问,并且没有异常被返回,因为它是单向调用。 直到我暂时禁用“单向”,我才检测到它,因此我的异常被传播回客户端。

希望这可以帮助处于类似情况的其他人。

I had a similar problem (one-way call not doing anything or throwing an exception). I found that the deserilizer responsible for transforming the method argument from xml back into objects was creating an exception. My service method was never getting reached and not exception was getting returned because it was a one-way call. I didn't detect it until I temporarily disabled the 'one-way' so my exception got propagated back to the client.

Hope this helps someone else in similar situation.

青萝楚歌 2024-07-17 02:05:55

好问题。 在客户端应用程序调用方法之前,它会打开通道。 该通道用于所有数据通信。 有两种发送方式:1) 可靠会话 - 当您的数据包被可靠地传递并重新发送破解的数据包时,2) 排序 - 当服务上的请求按照从客户端传输的顺序计算时(而不是如何传递) 。 如果您有可靠的有序会话,并且服务主机在关闭应用程序后遇到数据问题,主机将尝试要求客户端重新发送数据,并且在没有响应后拒绝您的所有请求。 在其他情况下(不可靠),打开通道后您可以发送数据并破坏通信,oneway 方法将计算您的请求,如果不会出现异常。

为了测试服务问题的一些可能性(不完全是您的客户端问题,但很有帮助),我创建了一个解决方案:

1)带有一个文件“IService1.cs”的库项目“WcfContracts”:

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        void ThrowException();

        [OperationContract(IsOneWay=true)]
        void ThrowExceptionUseIsOneWay();
    }

2)控制台项目“WcfConsoleHoster”,其中引用了两个“ WcfContracts”,由三个文件组成:

a) Service1.cs,这是服务实现

public class Service1 : WcfContracts.IService1
{    
        public void ThrowException()
        {
            throw new Exception("Basic exception");
        }

        public void ThrowExceptionUseIsOneWay()
        {
            throw new Exception("Basic exception using IsOneWay=true");
        }
}

b) Program.cs,它具有默认入口点并仅启动服务

static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(Service1));
        host.Open();
        Console.WriteLine("host 1 opened");
        Console.ReadKey();
    }

c) 服务“App.config”

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="behavourHttpGet" name="WcfConsoleHoster.Service1">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/" />
          </baseAddresses>
        </host>
        <endpoint binding="wsHttpBinding" contract="WcfContracts.IService1" />        
        <endpoint address ="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="behavourHttpGet">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

3) 控制台项目“WcfConsoleClient” ”,它只是调用服务

a) 在“Program.cs”中

Console.WriteLine("Wcf client. Press any key to start");
Console.ReadKey();
ChannelFactory<IService1> factory = new ChannelFactory<IService1>("Service1_Endpoint");
IService1 channel = factory.CreateChannel();
//Call service method
channel.ThrowException();

Console.WriteLine("Operation executed");
Console.ReadKey();

b) 客户端“App.config”

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="Service1_Endpoint"
        address="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/"
        binding="wsHttpBinding"
        contract="WcfContracts.IService1">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

1. 抛出异常。首先,我们调用双向方法,在服务器主机中抛出异常。 然后这个异常返回到客户端并且通道在客户端引发它,应用程序被销毁。 当然,您可以使用 try()catch{} 块来处理这个问题。

让我们通过调用 channel.ThrowExceptionUseIsOneWay(); 来查看单向方法的相同情况。 服务主机中引发异常,但客户端没有异常,我们得到“操作已执行”。 重要的是要认识到该通道将无法用于下次使用。

所以 IsOneWay=true 按预期工作 - 它仅以一种方式发送消息。 您不能从方法返回任何对象(预计为 void),并且不能使用FaultContract,或在服务启动后获得InvalidOperationException。

2. Thread.Sleep()。下一个测试是使用 Thread.Sleep() 进行大规模操作。
IService1 被扩展为

  [OperationContract]
  int ThreadSleep();

  [OperationContract(IsOneWay=true)]

,Service1.cs 中的实现是等待 5 秒

public int ThreadSleep()
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
    return 1;
}

public void ThreadSleepUseIsOneWay()
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
}

现在对客户端进行一点修改,用于计算已用调用时间

System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
//call methode
channel.ThreadSleep();
stopwatch.Stop();
Console.WriteLine(string.Format("Operation executed in {0} seconds", stopwatch.Elapsed.Seconds));
Console.ReadKey();

调用两种方式方法< /em> ThreadSleep() 的结果是“操作在 7 秒内执行”(线程睡眠 5 秒 + 通道初始化 2 秒)。

调用 channel.ThreadSleepUseIsOneWay()单向方法 的结果为“0 秒”! 无需等待服务响应!

最好使用NetNamedPipeBinding,它可靠且可靠在同一台机器上快速连接。

Good question. Before client application calls a method it opens the channel. The channel is used for all data communication. There are two ways of sending: 1) reliable session - when your packets are deleveried reliably and cracked packets are resent, 2) ordering - when requests on the service are computed in the order they were transfered from client (not how they are delivered). If you have reliable ordered session and service host is getting some problems with data your after closing application, host will try to ask the client resent data and after no responce reject all you request. In other situation (unreliable) after opening channel you can send data and destroy communication, oneway method will compute you request, if there will not be exception.

To test some possibilities with service problem (not exactly your client paroblem however is helpful) I create a solution:

1) Library project "WcfContracts" with one file "IService1.cs":

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        void ThrowException();

        [OperationContract(IsOneWay=true)]
        void ThrowExceptionUseIsOneWay();
    }

2) Console project "WcfConsoleHoster" which has reference two "WcfContracts", and consists of the three files:

a) Service1.cs, which is service implementation

public class Service1 : WcfContracts.IService1
{    
        public void ThrowException()
        {
            throw new Exception("Basic exception");
        }

        public void ThrowExceptionUseIsOneWay()
        {
            throw new Exception("Basic exception using IsOneWay=true");
        }
}

b) Program.cs, which has default entry point and just starts the service

static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(Service1));
        host.Open();
        Console.WriteLine("host 1 opened");
        Console.ReadKey();
    }

c) Service "App.config"

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="behavourHttpGet" name="WcfConsoleHoster.Service1">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/" />
          </baseAddresses>
        </host>
        <endpoint binding="wsHttpBinding" contract="WcfContracts.IService1" />        
        <endpoint address ="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="behavourHttpGet">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

3) Console project "WcfConsoleClient", which simply calls the service

a) In "Program.cs"

Console.WriteLine("Wcf client. Press any key to start");
Console.ReadKey();
ChannelFactory<IService1> factory = new ChannelFactory<IService1>("Service1_Endpoint");
IService1 channel = factory.CreateChannel();
//Call service method
channel.ThrowException();

Console.WriteLine("Operation executed");
Console.ReadKey();

b) Client "App.config"

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="Service1_Endpoint"
        address="http://localhost:8732/Design_Time_Addresses/WcfConsoleHoster/Service1/"
        binding="wsHttpBinding"
        contract="WcfContracts.IService1">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

1. Throwing exception. First, we call two way method wich throws exception in the server host. Then this exception goes back to the client and channel raises it on the client side, application is destroyed. Of course you can handle this with try()catch{} block.

Let's look the same with one way method by calling channel.ThrowExceptionUseIsOneWay();. Exception is raised in the service host, but there is no exception on the client side and we get "Operation executed". It is important to realize that channel will be unavailable for the next use.

So IsOneWay=true works as expected - it sends message only in one way. You cannot return any object from method(void is expected) and you cannot use FaultContract, or get InvalidOperationException after the service start up.

2. Thread.Sleep(). Next test is on massive operation with Thread.Sleep().
IService1 is extended to

  [OperationContract]
  int ThreadSleep();

  [OperationContract(IsOneWay=true)]

and the realization in Service1.cs is waiting for 5 seconds

public int ThreadSleep()
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
    return 1;
}

public void ThreadSleepUseIsOneWay()
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
}

Now a bit modification for the client for counting elapsed calling time

System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
//call methode
channel.ThreadSleep();
stopwatch.Stop();
Console.WriteLine(string.Format("Operation executed in {0} seconds", stopwatch.Elapsed.Seconds));
Console.ReadKey();

Calling two way method ThreadSleep() has the result "Operation executed in 7 seconds" (5 sec for thread sleep + 2 sec for channel initialization).

One way method with calling channel.ThreadSleepUseIsOneWay() has the result "0 seconds"! There is no waiting for the service response!

It is best to use NetNamedPipeBinding, which is reliable and fast connection on the same machine.

北音执念 2024-07-17 02:05:55

您不能“确保发送通知”......并“保持方法单向”。 这有点违背了“OneWay”的含义:)

如果您想确保消息已发送,那么可以使用 TwoWay。 您很可能不会注意到轻微的性能影响。 如果服务器和客户端位于您提到的同一台计算机上......那么您根本不会注意到性能受到影响。

You can't "make sure the notification is sent" ... and "keep the method oneway". That kinda goes against what "OneWay" means :)

If you want to ensure that the message is sent, it's ok to do TwoWay. You most likely won't notice the slight performance hit. And if the server and client are on the same machine as you mentioned... then you will not notice the performance hit at all.

秋心╮凉 2024-07-17 02:05:55

查看这篇文章以获取一些详细信息:
http://kennyw.com/?p=130

另外,我相信如果你有可靠的消息传递使请求将被验证为已成功发送,但正如上面的帖子所述,该服务将在该点之后结束连接。

Check out this post for some detailed info:
http://kennyw.com/?p=130

Also, I believe that if you have reliable messaging enabled that the request would be verified as sent successfully, but as the above post notes, the service will end the connection after that point.

昔日梦未散 2024-07-17 02:05:55

这可能是使用 netMsmqBinding 的好地方。 所有 MSMQ 消息本质上都是 OneWay,因为队列本质上是断开连接的。 一旦客户端将消息与 netMsmq 客户端一起排队,它就可以安全地关闭,并且服务器稍后可以拾取该消息并处理它。

This might be a good place to use a netMsmqBinding. All MSMQ messages are inherently OneWay because queues are inherently disconnected. Once the client queues the message with a netMsmq client, it can safely shutdown, and the server can later pickup the message and process it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文