gpt4 book ai didi

c# - WCF 的 IErrorHandler.HandleError(Exception error) 方法出现意外的 TimoutException

转载 作者:行者123 更新时间:2023-11-30 21:55:16 24 4
gpt4 key购买 nike

我的目的是检测 WCF 服务内未处理的错误,记录它们并关闭应用程序。

为此,我使用了 WCF 的 IErrorHandler。在方法 HandleError(Exception error) 中,我被告知发生了异常。一切正常。在问题的末尾,您会找到完整的 list 。这是输出:

00000: Starting service ...
00041: Client call ThrowUnexpected
00056: Service is throwing [InvalidOperationException]
00063: Client chatched [FaultException]
10070: ErrorHandler got [TimeoutException]
10070: ErrorHandler got [InvalidOperationException]

有两点我不满意:

  1. 而不是预期的 InvalidOperationException 我首先得到 TimeoutException 然后是我抛出的那个。如果我在第一个之后登录并关闭,我的日志中就会有错误的信息。

  2. 回调不会立即到达,大约 10 秒后才会到达。这些似乎正是 net.tcp 可能默认的超时秒数。对我来说已经太晚了,因为我不会在发生意外情况后立即终止进程。

问题 1: 仅在第二名出现异常是错误还是正常?我可以假设对于任何 WCF 配置我都会得到这对异常吗?有没有办法只获取方法内部抛出的异常?

问题2:有什么方法可以立即调用而不是超时后调用?

list :

    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 方法

All ProvideFault implementations are called first, prior to sending a response message. When all ProvideFault implementations have been called and return, and if fault is non-null, it is sent back to the client according to the operation contract. If fault is null after all implementations have been called, the response message is controlled by the ServiceBehaviorAttribute.IncludeExceptionDetailInFaults property value.

然后是HandleError方法

Because the HandleError method can be called from many different places there are no guarantees made about which thread the method is called on. Do not depend on HandleError method being called on the operation thread.

您看到的 TimeoutException 来自 ServiceHost 的关闭(using-Block 的末尾)。您可以通过在 ServiceHost 上设置 CloseTimeout 来控制它。

host.CloseTimeout = TimeSpan.FromSeconds(2);

为什么超时会发生?这是因为,即使代理处于故障状态,从代理到服务的连接仍然存在并且没有关闭。要解决此问题,您需要在 FaultedException 的 catch block 中调用 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]

关于c# - WCF 的 IErrorHandler.HandleError(Exception error) 方法出现意外的 TimoutException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32402243/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com