[英]IErrorHandler.HandleError(Exception error) method of WCF is getting unexpected TimoutException
我的目的是檢測WCF服務內部未處理的錯誤,記錄它們並關閉應用程序。
為此,我使用WCF的IErrorHandler
。 在方法HandleError(Exception error)
我被通知發生了異常。 一切正常。 在問題的結尾,您將找到完整的清單。 這是輸出:
00000: Starting service ...
00041: Client call ThrowUnexpected
00056: Service is throwing [InvalidOperationException]
00063: Client chatched [FaultException]
10070: ErrorHandler got [TimeoutException]
10070: ErrorHandler got [InvalidOperationException]
我有兩點不滿意:
而不是預期的InvalidOperationException
我先得到TimeoutException
,然后再拋出。 如果我在第一個日志之后登錄並關閉,則日志中將包含錯誤信息。
僅在大約10秒鍾后,回調不會立即到達。 這些似乎正是net.tcp默認的那些超時秒。 對我來說太晚了,因為在發生意外情況后,我不會立即終止該過程。
問題1:僅在第二名得到我的例外是錯誤還是正常? 我可以假定對於任何WCF配置我都會得到這對異常嗎? 有什么方法可以只獲取方法內部拋出的異常嗎?
問題2:有什么方法可以立即調用而不是在超時后調用?
清單:
internal class Program
{
private static void Main(string[] args)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
Console.WriteLine("{0:00000}: Starting service ...", stopwatch.ElapsedMilliseconds);
var instance = new SomeService(stopwatch);
var uri = new UriBuilder(Uri.UriSchemeNetTcp, IPAddress.Loopback.ToString(), 8085, "SomeService").Uri;
using (var host = new ServiceHost(instance))
{
host.AddServiceEndpoint(typeof (ISomeService), new NetTcpBinding(), uri);
host.Description.Behaviors.Add(new ErrorHandlerBehavior(new ErrorHandler(stopwatch)));
host.Open();
// DO NOT DISPOSE Channel is broken
var proxy = new SomeServiceProxy(uri);
{
try
{
Console.WriteLine("{0:00000}: Client call ThrowUnexpected", stopwatch.ElapsedMilliseconds);
proxy.ThrowUnexpected();
}
catch (FaultException ex)
{
Console.WriteLine("{0:00000}: Client chatched [{1}]", stopwatch.ElapsedMilliseconds,
ex.GetType().Name);
}
}
}
}
}
}
[ServiceContract]
public interface ISomeService
{
[OperationContract]
void ThrowUnexpected();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class SomeService : ISomeService
{
private readonly Stopwatch _stopwatch;
public SomeService(Stopwatch stopwatch)
{
_stopwatch = stopwatch;
}
public void ThrowUnexpected()
{
var exception = new InvalidOperationException();
Console.WriteLine("{0:00000}: Service is throwing [{1}]", _stopwatch.ElapsedMilliseconds,
exception.GetType().Name);
throw exception;
}
}
public class ErrorHandler : IErrorHandler
{
private readonly Stopwatch _stopwatch;
public ErrorHandler(Stopwatch stopwatch)
{
_stopwatch = stopwatch;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
}
public bool HandleError(Exception error)
{
Console.WriteLine("{0:00000}: ErrorHandler got [{1}]", _stopwatch.ElapsedMilliseconds, error.GetType().Name);
return false;
}
}
public class SomeServiceProxy : ClientBase<ISomeService>, ISomeService
{
public SomeServiceProxy(Uri uri)
: base(new NetTcpBinding(), new EndpointAddress(uri))
{
}
public void ThrowUnexpected()
{
Channel.ThrowUnexpected();
}
}
public class ErrorHandlerBehavior : IServiceBehavior
{
private readonly IErrorHandler m_Handler;
public ErrorHandlerBehavior(IErrorHandler errorHandler)
{
m_Handler = errorHandler;
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
var dispatcher = (ChannelDispatcher) channelDispatcherBase;
dispatcher.ErrorHandlers.Add(m_Handler);
}
}
}
我認為您對IErrorHandler的工作方式有些誤解。 我指的是MSDN。 首先是ProvideFault方法
在發送響應消息之前,將首先調用所有ProvideFault實施。 當所有ProvideFault實現均已調用並返回時,並且如果fault非空,則根據操作合同將其發送回客戶端。 如果在調用所有實現之后fault為null,則響應消息由ServiceBehaviorAttribute.IncludeExceptionDetailInFaults屬性值控制。
然后是HandleError方法
因為可以從許多不同的地方調用HandleError方法,所以不能保證調用該方法的線程。 不要依賴在操作線程上被調用的HandleError方法。
您看到的TimeoutException來自ServiceHost的關閉(using-Block的結尾)。 您可以通過在ServiceHost上設置CloseTimeout來控制它。
host.CloseTimeout = TimeSpan.FromSeconds(2);
為什么超時發生了? 這是因為,即使代理處於故障狀態,從代理到服務的連接仍然存在並且沒有關閉。 要解決此問題,您需要在FaultedException的catch塊中調用Abort。
catch (FaultException ex)
{
proxy.Abort();
Console.WriteLine("{0:00000}: Client chatched [{1}]", stopwatch.ElapsedMilliseconds,
ex.GetType().Name);
}
這將導致以下輸出
00000: Starting service ...
00005: Client call ThrowUnexpected
00010: Service is throwing [InvalidOperationException]
00014: Client chatched [FaultException]
00026: ErrorHandler got [CommunicationException]
00029: ErrorHandler got [InvalidOperationException]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.