[英]How do I get accurate Exception stack in WCF Task-based Operation
我正在使用WCF IErrorHandler接口來捕獲和記錄WCF服務的服務器端的錯誤。 但是,傳遞給HandleError和ProvideFault的異常的StackTrace搞砸了:
at System.ServiceModel.Dispatcher.TaskMethodInvoker.InvokeEnd(Object instance,Object []&outputs,IAsyncResult result)at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeEnd(MessageRpc&rpc)at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage7(MessageRpc&rpc) )......還有更多
我在堆棧跟蹤中看到隨機的Dispatcher方法並不奇怪,但我想我會在堆棧頂部看到自己的方法。
我已經確定這只會發生在看起來像的操作上
[OperationContract]
public Task<int> MyOperation()
{
throw new ApplicationException("test");
}
看起來像這樣的服務有一個適當的堆棧跟蹤供我記錄:
[OperationContract]
public int MySyncOperation()
{
throw new ApplicationException("test");
}
作為一個FYI,這是錯誤處理程序方法的樣子:
public class MyErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
//variable 'error' has wrong stack trace if exception sourced from Task<int> operation
return false;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
//variable 'error' has wrong stack trace if exception sourced from Task<int> operation
}
}
請注意,異常類型和消息是正確的,所以就好像他們錯誤地在某處使用'throw ex'而不僅僅是'throw'重新拋出我的異常;
有沒有辦法從IErrorHandler方法之一獲取正確的異常堆棧跟蹤?
我最終使用以下自定義操作調用程序解決了這個問題。 我唯一的目標是使用正確的堆棧跟蹤記錄錯誤,因此最終被拋出的錯誤會保留較差的堆棧跟蹤。
public class ErrorLoggingOperationInvokerFacade : IOperationInvoker
{
private readonly IOperationInvoker _invoker;
private readonly ILog _log;
public ErrorLoggingOperationInvokerFacade(IOperationInvoker invoker, ILog log)
{
_invoker = invoker;
_log = log;
}
public object[] AllocateInputs()
{
return _invoker.AllocateInputs();
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
return _invoker.Invoke(instance, inputs, out outputs);
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return _invoker.InvokeBegin(instance, inputs, callback, state);
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
var task = result as Task;
if (task != null && task.IsFaulted && task.Exception != null)
{
foreach (var error in task.Exception.InnerExceptions)
{
_log.Log(error);
}
}
return _invoker.InvokeEnd(instance, out outputs, result);
}
public bool IsSynchronous { get { return _invoker.IsSynchronous; } }
}
它可以附加您的服務類或方法的屬性:
public class LogErrorsAttribute : Attribute, IServiceBehavior, IOperationBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var operation in serviceHostBase.Description.Endpoints.SelectMany(endpoint => endpoint.Contract.Operations))
{
if (!operation.Behaviors.Any(b => b is LogErrorsAttribute))
operation.Behaviors.Add(this);
}
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.Invoker = new ErrorLoggingOperationInvokerFacade(dispatchOperation.Invoker, WcfDependencyManager.ResolveLogger());
}
public void Validate(OperationDescription operationDescription) { }
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { }
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }
}
以前我在IErrorHandler
接口的實現中記錄了錯誤,但此時堆棧跟蹤已經搞砸了。 我試圖修改操作調用程序以使用正確的堆棧跟蹤拋出異常,但我從來沒有讓它正常工作。 出於某種原因,我的自定義故障異常變成了通用故障異常,因此我放棄了這種方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.