0

I have a simple web-service with a one-way operation which I expected would not block the client when invoked.

With the BasicHttpBinding this is fine.

With the default WsHttpBinding the IsOneWay attribute is not taken into account (same time as a not one-way operation I've created to test).

I've found two interesting facts:

  • when I set SecurityMode to None it works as expected

  • when I set SessionMode to NotAllowed it works too

I've read that if sessions are activated messages are treated in order so that would explain the behavior.

But why setting SecurityMode to None does the trick too?

What are the relationships between these three properties and how to explain these behaviors?

Here is my "benchmark":

[ServiceContract(/*SessionMode = SessionMode.NotAllowed*/)]
interface ILogService
{
    [OperationContract]
    void Log(string message);

    [OperationContract(IsOneWay = true)]
    void LogOneWay(string message);
}

class LogService : ILogService
{
    public void Log(string message)
    {
        Thread.Sleep(100);
    }

    public void LogOneWay(string message)
    {
        Thread.Sleep(100);
    }
}

public void Run()
{
    ServiceHost host = new ServiceHost(typeof(LogService));
    host.AddServiceEndpoint(typeof(ILogService), new WSHttpBinding(/*SecurityMode.None*/), "http://localhost:12345/log");
    host.Open();

    ILogService proxy = ChannelFactory<ILogService>.CreateChannel(new WSHttpBinding(/*SecurityMode.None*/), new EndpointAddress("http://localhost:12345/log"));
    proxy.Log("");

    const int n = 100;

    Stopwatch stopwatch = Stopwatch.StartNew();
    for (int i = 0; i < n; ++i)
    {
        proxy.LogOneWay("");
        Console.WriteLine(i);
    }
    stopwatch.Stop();

    TimeSpan datagramTime = stopwatch.Elapsed;

    stopwatch.Restart();
    for (int i = 0; i < n; ++i)
    {
        proxy.Log("");
        Console.WriteLine(i);
    }
    stopwatch.Stop();

    TimeSpan halfDuplexTime = stopwatch.Elapsed;

    host.Close();

    Console.WriteLine("Half-duplex: {0}", halfDuplexTime);
    Console.WriteLine("Datagram: {0}", datagramTime);
}
Pragmateek
  • 13,174
  • 9
  • 74
  • 108
  • 1
    See http://bloggingabout.net/blogs/gerben/archive/2010/02/01/wcf-best-practice-5-one-way-is-not-always-really-one-way.aspx and the article it references http://msdn.microsoft.com/en-us/magazine/cc163537.aspx "One-way calls do not equate to asynchronous calls. When one-way calls reach the service, they may not be dispatched all at once and may be queued up on the service side to be dispatched one at a time, all according to the service configured concurrency mode behavior and session mode. " – Preston Guillot Nov 02 '13 at 00:26
  • @PrestonGuillot: thanks for looking at the issue. The first article is about the *Close* behavior but I guess the behavior is the same for any operation. Like me it points the relation with security settings but does not explain why. The second article you quote does not explain the behavior either: it says that messages are queued on the service side, so the client should not have to wait, unless the queue is full, but as the measures of my "benchmark" show it behaves as if the queue has no slot! +1 anyway because they add grist to my mill. :) – Pragmateek Nov 02 '13 at 16:50

0 Answers0