最近我正在研究WCF服务的异常日志记录模块。遗憾的是,该服务还没有引入单元测试,因此出现了许多意外的异常。到目前为止,我已经完成了通过实现IErrorHandler
接口并使用IServiceBehaviour
将其绑定到服务接口来获取拦截器aproach的异常。我非常喜欢这个功能。但它让我进入下一步,希望获得异常细节。就像发生异常的那条线一样?
我可以通过两种方式满足这种愿望:
但这两种方法对我来说都很糟糕。我想知道是否有一个已知的设计模式或实现这一目标的工具?
答案 0 :(得分:0)
在我看来,您可能会尝试使用日志记录,例如log4net。然后你可以找出发生的地点和发生的事情。异常对象并不总是包含堆栈信息,因为在优化等过程中会出现“内联”。
答案 1 :(得分:0)
包含您服务的PDB文件,行号将包含在exception.ToString()
答案 2 :(得分:0)
我们解决这个问题的方式有两个:
例如:
public FooServiceModel GetFoo(int fooId)
{
return new ILogged<GetFooCommand>().Target.Execute(fooId);
}
这会将命令的执行委托给ILogged
,其中:
它还使用自定义消息头将客户端请求与服务器调用链接起来,以便可以从客户端到服务器完全调试并返回调用。这非常有用,可以让我们在现场诊断出复杂的问题。
我们使用Castle.Core
动态代理来实现ILogged
一个看起来像这样的拦截器(ILog
是一个log4net记录器):
public class LoggingInterceptor : IInterceptor
{
public LoggingInterceptor([NotNull] object target, [NotNull] ILog logger)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (logger == null)
{
throw new ArgumentNullException("logger");
}
this.Target = target;
this.Logger = logger;
}
public object Target { get; set; }
public ILog Logger { get; set; }
public void Intercept(IInvocation invocation)
{
try
{
this.Logger.Debug(invocation);
invocation.ReturnValue = invocation.Method.Invoke(
this.Target, invocation.Arguments);
this.Logger.Debug("Invocation return value:");
this.Logger.Debug(invocation.ReturnValue);
}
catch (TargetInvocationException ex)
{
this.Logger.Error("Unable to execute invocation", ex);
if (ex.InnerException != null)
{
throw ex.InnerException;
}
throw;
}
}
}
调用本身由自定义log4net对象渲染器呈现:
public class InvocationRenderer : IObjectRenderer
{
public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
{
var invocation = (IInvocation)obj;
var builder = new StringBuilder();
builder.AppendFormat(
"Invoking Method: {0} --> '{1}' with parameters (",
invocation.Method.DeclaringType != null
? invocation.Method.DeclaringType.FullName : "{Unknown Type}",
invocation.Method);
var parameters = invocation.Method
.GetParameters()
.Zip(invocation.Arguments, (p, a) => new { Parameter = p, Argument = a })
.ToArray();
var index = 0;
foreach (var parameter in parameters)
{
builder.AppendFormat(
"{0}: {1}",
parameter.Parameter.Name,
rendererMap.FindAndRender(parameter.Argument));
if (++index < parameters.Length)
{
builder.Append(", ");
}
}
builder.Append(")");
writer.Write(builder.ToString());
}
}
希望这会给你一些关于如何解决这个问题的想法。