我的意图是检测WCF服务内部未处理的错误,记录它们并关闭应用程序。WCF的IErrorHandler.HandleError(异常错误)方法出现意外TimoutException
为此,我使用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:是一个bug还是正常的,我让我的例外,只在第二位?我能否假设对于任何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);
}
}
}