2010-11-06 52 views
1

调用ServiceHost.Close()允许主机实例通过允许正在进行的呼叫完成而正常退出,同时拒绝将来的客户端调用。假设ServiceHost.CloseTimeout设置为10秒,然后ServiceHost实例将阻塞10秒,等待Close()返回ServiceHost.Close不返回...

a)如果Close()没有在10秒内恢复,会发生什么? ServiceHost实例是否会强行关闭而不抛出任何异常?

b)Close()在规定的时间内没有返回的常见情况是什么?也许在进行中的客户调用仍在处理中?

谢谢

答复:

我很困惑。在您的例子服务宿主,并等待操作完成,但在我的例子不是这样,因为Console.WriteLine("GetDog completed");(内GetDog()称呼)没有得到执行:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ServiceModel; 
using System.ServiceModel.Description; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    [ServiceContract] 
    public interface IDogs 
    { 
     [OperationContract] 
     string GetDog(); 
    } 

    public class Animals : IDogs 
    { 
     public string GetDog() 
     { 
      Thread.Sleep(30000); 
      Console.WriteLine("GetDog completed"); // this doesn't get executed 
      return "dalmatian"; 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 

      ServiceHost host1 = 
       new ServiceHost(typeof(Animals),new Uri("http://localhost:8000")); 
      host1.AddServiceEndpoint(typeof(IDogs), new BasicHttpBinding(), "Dogs"); 

      ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); 
      behavior.HttpGetEnabled = true; 
      host1.Description.Behaviors.Add(behavior); 

      host1.AddServiceEndpoint(
       typeof(IMetadataExchange), 
       MetadataExchangeBindings.CreateMexHttpBinding(), 
       "mex"); 

      host1.Open(); 
      Thread.Sleep(6000); 
      host1.Close(); 
     } 
    } 

顺便说一句 - 为什么不例外中抛出主线程(调用host.Close())?相反,它是从执行Service.doFoo()?的线程抛出的!

+0

你肯定呼叫到达GetDog()方法?将Write调用添加到方法的开头。 – 2010-11-07 19:21:23

回答

1

a)它会抛出一个TimeoutException。

b)如果您忽略了一些耗时的内容,可能会超时OnClosingOnClose(TimeSpan)OnClosed。而且,根据这个list of errors,它将等待该操作被派遣。请参阅SfxCloseTimedOutWaitingForDispatchToComplete。需要测试它。

更新。好吧,显然,这是真的。虽然客户端连接将立即中止,但服务主机将在更改主机状态之前等待操作完成。下面是我用来测试这个代码:

class Program 
{ 
    static void Main(string[] args) 
    { 
     //Server 
     string baseUri = "http://localhost:8080/test/"; 
     ServiceHost host = new ServiceHost(new Service(), new Uri(baseUri)); 
     BasicHttpBinding binding = new BasicHttpBinding(); 
     var endpoint = host.AddServiceEndpoint(typeof(IService), binding, baseUri); 
     host.Closed += ((sender, arguments) => Console.WriteLine("Closed")); 
     host.Open(); 

     //Client 
     ChannelFactory<IService> factory = new ChannelFactory<IService>(endpoint); 
     new Action(() => 
     { 
      try 
      { 
       factory.CreateChannel().DoFoo(); 
      } 
      catch(Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 
     }).BeginInvoke(null, null); 

     //Making sure request has reached the server 
     Thread.Sleep(1000); 

     host.Close(); 
    } 
} 

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
public class Service : IService 
{ 
    public void DoFoo() 
    { 
     Console.WriteLine("DoFoo started"); 
     Thread.Sleep(10000); 
     Console.WriteLine("DoFoo finished"); 
    } 
} 

[ServiceContract] 
interface IService 
{ 
    [OperationContract] 
    void DoFoo(); 
} 

输出:

 
     DoFoo started 
    An error occurred while receiving the HTTP response to http://localhost:8080/tes 
    t/. This could be due to the service endpoint binding not using the HTTP protoco 
    l. This could also be due to an HTTP request context being aborted by the server 
    (possibly due to the service shutting down). See server logs for more details. 
    DoFoo finished 
    Closed 
+0

A - 因此设置ServiceHost.CloseTimeout属性与为ServiceHost.Close(TimeSpan超时)设置超时参数具有相同的效果? B - “是的,根据这个错误列表,它将等待该操作被发送。请参阅SfxCloseTimedOutWaitingForDispatchToComplete“您是否暗示如果客户端调用在超时发生时仍在处理中,那么Close()将等待客户端调用处理完成(可能需要很长时间),并将结果发送回客户端那么它会抛出一个错误? – user437291 2010-11-07 01:04:54

+1

a)是的,我认为是。当你调用无参数'Close()'过载时,它会被使用。 b)查看我的答案更新。 – 2010-11-07 07:54:57

+0

你能看到我的编辑吗? – user437291 2010-11-07 18:22:40