WCF 关闭 ServiceHost 时等待操作完成

发布于 2024-11-08 00:28:21 字数 1253 浏览 0 评论 0原文

我创建了一个 WCF SOAP 服务器,其操作需要一些时间才能执行:

[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");
    }
}

ServiceHost 打开,10 秒后将其关闭。

当调用 serviceHost.Close() 时,当前连接的所有等待 LongRunningOperation 完成的客户端都会立即断开连接。

是否需要等待以更​​干净的方式关闭 ServiceHost?也就是说,我想禁用服务侦听器,但还要等待所有当前连接的客户端完成(或指定最大超时)。

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).

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

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

发布评论

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

评论(4

浮生未歇 2024-11-15 00:28:21

我很惊讶调用 ServiceHost.Close 并没有让 LongRunningOperation 完成。

整个架构的设置是为了让事情有时间正常关闭(例如关闭和中止转换之间的差异)。根据 MSDN 文档:

此方法会导致
优雅地通讯对象
从任何状态的转换,除了
Closed状态,进入Closed
状态。 Close 方法允许任何
之前未完成的工作必须完成
返回。

ServiceHost 上还有一个 CloseTimeout 正是用于此目的。您是否尝试过将 CloseTimeout 设置为大于 20 秒? (根据 Reflector,ServiceHost 的默认 CloseTimeout 为 10 秒...)

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...)

鸠魁 2024-11-15 00:28:21

原则上,我认为类似以下的事情应该是可能的,尽管我还没有实现它来确认所有细节:

  • 实现自定义 IOperationInvoker
    包装调度程序的正常
    OperationInvoker(在构建服务调度程序运行时时,您需要一个 IServiceBehavior 来安装包装的调用程序)
  • 自定义调用程序主要会委托给真实的调用程序,但也会提供
    “看门人”功能拒绝
    当服务主机即将到来时新请求(例如引发某种异常)
    被关闭。
  • 它还会跟踪仍在中的操作调用
    进度并在最后一次操作调用完成或超时时设置事件。
  • 然后,主托管线程将在调用 serviceHost.Close() 之前等待调用者的“全部完成”事件。

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().
彼岸花ソ最美的依靠 2024-11-15 00:28:21

你所做的事在我看来都是错误的。 ServiceHost 永远不应该突然关闭。它是一项服务,应该保持可用。如果没有客户的参与,就没有真正的方法可以优雅地结束。当我说“优雅地关闭”时,从客户的角度来看,这也是主观的。

所以我认为我根本不理解您的要求,但是一种方法是实现发布/订阅模式,当主机准备关闭时,通知所有订阅者此事件,以便每个客户端都可以关闭所有连接。您可以在此处阅读有关此内容的更多信息 http://msdn.microsoft.com/en- us/magazine/cc163537.aspx

同样,这种托管服务的方法不是标准的,这就是为什么您发现很难找到针对您的这个特定问题的解决方案。如果您可以详细说明您的用例/使用场景,可能会有助于找到真正的解决方案。

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.

三生池水覆流年 2024-11-15 00:28:21

您正在描述客户端功能。听起来您应该包装 servicehost 对象,然后让您的代理在“关闭”时拒绝新请求。在所有调用都得到服务之前,您不会关闭真正的服务主机。

您还应该看看异步 CTP。使用即将推出的 TaskCompletionSource 类,将这种逻辑放入消费者端“Task”对象中将会容易得多。

从 dnrtv 中查看此视频。这与 wcf 无关,而是与即将推出的异步语言和类支持有关。

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.

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