开发者

WCF Wait for operations to finish when closing ServiceHost

开发者 https://www.devze.com 2023-03-06 17:15 出处:网络
I create a WCF SOAP server with an operation that takes some time to perform: [ServiceContract] public interface IMyService

I create a WCF SOAP server with an operation that takes some time to perform:

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    string LongRunningOperation();
}

[ServiceBehavior(
    ConcurrencyMode开发者_开发问答 = ConcurrencyMode.Multiple,
    UseSynchronizationContext = false,
    InstanceContextMode = InstanceContextMode.Single)]
class MyService : IMyService
{
    public string LongRunningOperation()
    {
        Thread.Sleep(20000);
        return "Hey!";
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyService instance = new MyService();
        ServiceHost serviceHost = new ServiceHost(instance);
        BasicHttpBinding binding = new BasicHttpBinding();
        serviceHost.AddServiceEndpoint(typeof(IMyService), binding, "http://localhost:9080/MyService");
        serviceHost.Open();
        Console.WriteLine("Service running");
        Thread.Sleep(10000);
        serviceHost.Close();
        Console.WriteLine("Service closed");
        Thread.Sleep(30000);
        Console.WriteLine("Exiting");
    }
}

The ServiceHost is opened, and after 10 seconds I close it.

When calling serviceHost.Close(), all clients currently connected, waiting for LongRunningOperation to finish, are inmediately disconnected.

Is there a wait of closing the ServiceHost in a cleaner way? That is, I want to disable the service listeners, but also wait for all currently connected clients to finish (or specify a maximum timeout).


Im surprised calling ServiceHost.Close is not letting LongRunningOperation complete.

The whole architecture is setup to allow things time to gracefully shut down (e.g. the difference between Close and Abort transitions.). According to MSDN docs:

This method causes a CommunicationObject to gracefully transition from any state, other than the Closed state, into the Closed state. The Close method allows any unfinished work to be completed before returning.

Also there is a CloseTimeout on the ServiceHost for precisely this. Have you tried setting the CloseTimeout to be greater than 20 seconds? (According to Reflector the default CloseTimeout for ServiceHost is 10 seconds...)


In principle, I think something like the following should be possible, though I haven't implemented it to confirm all the details:

  • Implement a custom IOperationInvoker wrapping the Dispatcher's normal OperationInvoker (you'll want an IServiceBehavior to install the wrapped invoker when the service dispatcher runtime is built)
  • the custom invoker would mostly delegate to the real one, but would also provide "gate-keeper" functionality to turn away new requests (e.g. raise a some kind of exception) when the service host is about to be shut down.
  • it would also keep track of operation invocations still in progress and set an event when the last operation invocation finishes or times out.
  • the main hosting thread would then wait on the invoker's "all finished" event before calling serviceHost.Close().


What you are doing seems all wrong to me. The ServiceHost should never close abruptly. It is a service and should remain available. There is no real way to close gracefully without some participation from the client. When I say close gracefully, this also subjective from a clients perspective.

So I dont think I understand your requirements at all, however one way would be to implement a publish/subscribe pattern and when the host is ready to close, notify all subscribers of this event so that all connections could be closed by each respective client. You can read more about this here http://msdn.microsoft.com/en-us/magazine/cc163537.aspx

Again, this approach to hosting a service is not standard and thats why you are finding it hard to find a solution to this particular problem of yours. If you could elaborate on your use case/usage scenario, it would probably help to find a real solution.


You are describing client side functionality. Sounds like you should wrap the servicehost object and then have your proxy rejecting new requests when it "is closing". You don't close the real servicehost until all calls have been serviced.

You should also take a look at the asynch CTP. To put this kind of logic inside a consumer side "Task" object will be much easier with the upcoming TaskCompletionSource class.

Check this video from dnrtv out. It's not about wcf, but rather about the upcoming language and class support for asynchrony.

0

精彩评论

暂无评论...
验证码 换一张
取 消