Async WCF self hosted service

后端 未结 1 926
一个人的身影
一个人的身影 2021-02-04 15:45

My objective is to implement an asynchronous self hosted WCF service which will run all requests in a single thread and make full use of the new C# 5 async features.

My

相关标签:
1条回答
  • 2021-02-04 16:29

    You need to apply ConcurrencyMode.Multiple.

    This is where the terminology gets a bit confusing, because in this case it doesn't actually mean "multi-threaded" as the MSDN docs state. It means concurrent. By default (single concurrency), WCF will delay other requests until the original operation has completed, so you need to specify multiple concurrency to permit overlapping (concurrent) requests. Your SynchronizationContext will still guarantee only a single thread will process all the requests, so it's not actually multi-threading. It's single-threaded concurrency.

    On a side note, you might want to consider a different SynchronizationContext that has cleaner shutdown semantics. The SingleThreadSynchronizationContext you are currently using will "clamp shut" if you call Complete; any async methods that are in an await are just never resumed.

    I have an AsyncContext type that has better support for clean shutdowns. If you install the Nito.AsyncEx NuGet package, you can use server code like this:

    static SynchronizationContext syncCtx;
    static ServiceHost serviceHost;
    
    static void Main(string[] args)
    {
        AsyncContext.Run(() =>
        {
            syncCtx = SynchronizationContext.Current;
            syncCtx.OperationStarted();
            serviceHost = new ServiceHost(typeof(MessageService));
            Console.CancelKeyPress += Console_CancelKeyPress;
    
            var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
            serviceHost.AddServiceEndpoint(typeof(IMessageService), binding, address);
            serviceHost.Open();
        });
    }
    
    static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
    {
        if (serviceHost != null)
        {
            serviceHost.BeginClose(_ => syncCtx.OperationCompleted(), null);
            serviceHost = null;
        }
    
        if (e.SpecialKey == ConsoleSpecialKey.ControlC)
            e.Cancel = true;
    }
    

    This will translate Ctrl-C into a "soft" exit, meaning the application will continue running as long as there are client connections (or until the "close" times out). During the close, existing client connections can make new requests, but new client connections will be rejected.

    Ctrl-Break is still a "hard" exit; there's nothing you can do to change that in a Console host.

    0 讨论(0)
提交回复
热议问题