我最近阅读了由Juval Lowy撰写的编程WCF服务,第三版。我利用下面显示的ParameterTracerInvoker : GenericInvoker
来使用NLOG跟踪日志。它的效果很好,除了我认为可能无法实现的一件事,即获取被调用的MethodName
。正如您在PreInvoke
方法中看到的,我正在记录输入,但不记录方法名称。任何人都知道如何检索方法名称?
public abstract class GenericInvoker : IOperationInvoker
{
internal readonly IOperationInvoker _oldInvoker;
public GenericInvoker(IOperationInvoker oldInvoker)
{
Debug.Assert(oldInvoker != null);
_oldInvoker = oldInvoker;
}
public virtual object[] AllocateInputs()
{
return _oldInvoker.AllocateInputs();
}
/// <summary>
/// Exceptions here will abort the call
/// </summary>
/// <returns></returns>
protected virtual void PreInvoke(object instance, object[] inputs)
{ }
/// <summary>
/// Always called, even if operation had an exception
/// </summary>
/// <returns></returns>
protected virtual void PostInvoke(object instance, object returnedValue, object[] outputs, Exception exception)
{ }
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
PreInvoke(instance, inputs);
object returnedValue = null;
object[] outputParams = new object[] { };
Exception exception = null;
try
{
returnedValue = _oldInvoker.Invoke(instance, inputs, out outputParams);
outputs = outputParams;
return returnedValue;
}
catch (Exception operationException)
{
exception = operationException;
throw;
}
finally
{
PostInvoke(instance, returnedValue, outputParams, exception);
}
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
PreInvoke(instance, inputs);
return _oldInvoker.InvokeBegin(instance, inputs, callback, state);
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
object returnedValue = null;
object[] outputParams = { };
Exception exception = null;
try
{
returnedValue = _oldInvoker.InvokeEnd(instance, out outputs, result);
outputs = outputParams;
return returnedValue;
}
catch (Exception operationException)
{
exception = operationException;
throw;
}
finally
{
PostInvoke(instance, returnedValue, outputParams, exception);
}
}
public bool IsSynchronous
{
get
{
return _oldInvoker.IsSynchronous;
}
}
}
public class ParameterTracerInvoker : GenericInvoker
{
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
public ParameterTracerInvoker(IOperationInvoker oldInvoker)
: base(oldInvoker)
{
}
protected override void PreInvoke(object instance, object[] inputs)
{
//_logger.Trace(((SyncMethodInvoker)_oldInvoker).MethodName);
_logger.Trace("Input Parameters:");
foreach (object argument in inputs)
{
if (argument != null)
{
_logger.Trace(argument.ToString());
}
else
{
_logger.Trace("null");
}
}
}
protected override void PostInvoke(object instance, object returnedValue, object[] outputs, Exception exception)
{
foreach (object output in outputs)
{
_logger.Trace("Output Parameters:");
_logger.Trace(output.ToString());
}
returnedValue = "aaaaaaaaaaaa";
_logger.Trace("Returned: " + returnedValue ?? String.Empty);
}
}
答案 0 :(得分:4)
IOperationInvoker
本身不会为您提供操作名称,但为了使用自定义调用程序,您通常会使用操作行为。该行为可以访问操作名称,并且可以传递给您的自定义调用者:
public class ParameterTracerOperationBehavior : IOperationBehavior
{
// ...
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
var originalInvoker = dispatchOperation.Invoker;
var operationName = operationDescription.Name;
var newInvoker = new ParameterTracerInvoker(originalInvoker, operationName);
dispatchOperation.Invoker = newInvoker;
}
}
public class ParameterTracerInvoker
{
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly string operationName;
public ParameterTracerInvoker(IOperationInvoker oldInvoker, string operationName)
: base(oldInvoker)
{
this.operationName = operationName;
}
// ...
}
答案 1 :(得分:2)
我的完整示例
public class WcfTracingOperationBehavior : IOperationBehavior
{
#region Implementation of IOperationBehavior
public void Validate(OperationDescription operationDescription)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.Invoker = new WcfTracingOperationInvoker(dispatchOperation.Invoker, operationDescription);
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
#endregion
}
和
public class WcfTracingOperationInvoker : IOperationInvoker
{
private readonly IOperationInvoker _originalInvoker;
private string ServiceFullName { get; set; }
private string ServiceName { get; set; }
private string MethodName { get; set; }
public WcfTracingOperationInvoker(IOperationInvoker originalInvoker, OperationDescription operationDescription)
{
_originalInvoker = originalInvoker;
var declaringType = operationDescription.SyncMethod.DeclaringType;
if (declaringType != null)
{
ServiceFullName = declaringType.FullName;
ServiceName = declaringType.Name;
}
MethodName = operationDescription.SyncMethod.Name;
}
#region Implementation of IOperationInvoker
public object[] AllocateInputs()
{
SetMethodInfo();
return _originalInvoker.AllocateInputs();
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
var result = _originalInvoker.Invoke(instance, inputs, out outputs);
return result;
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return _originalInvoker.InvokeBegin(instance, inputs, callback, state);
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
return _originalInvoker.InvokeEnd(instance, out outputs, result);
}
public bool IsSynchronous
{
get { return _originalInvoker.IsSynchronous; }
}
#endregion
private void SetMethodInfo()
{
// The WcfContext is some my stuff.
var wcfTraceActivity = WcfContext<WcfTraceActivity>.Current;
wcfTraceActivity.ServiceName = ServiceName;
wcfTraceActivity.ServiceFullName = ServiceFullName;
wcfTraceActivity.MethodName = MethodName;
}
}