有没有办法让我添加日志记录,以便以某种方式自动记录进入和退出方法以及参数以进行跟踪?我该怎么做?
我正在使用 Log4Net。
实现这种事情的最好方法是使用拦截,有几种方法可以做到这一点,尽管它们都倾向于有点侵入性。一种是从 ContextBoundObject 派生所有对象。 这是使用这种方法的示例。另一种方法是使用现有的 AOP 库之一来实现这一点。Castle Project中的DynamicProxy 之类的东西是其中许多的核心。这里有几个链接: Spring.Net PostSharp Cecil
可能还有其他几个,我知道Castle Windsor和Ninject都在 IoC 功能之上提供 AOP 功能。
一旦 AOP 到位,您只需编写一个拦截器类,它将有关方法调用的信息写入 log4net。
如果其中一个 AOP 框架能够为您提供开箱即用的那种功能,我实际上不会感到惊讶。
我不确定您的实际需求是什么,但这里有一个低租金的选择。它不完全是“自动的”,但您可以使用 StackTrace 以不需要传递参数的方式剥离您正在寻找的信息 - 类似于 ckramer 关于拦截的建议:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace TracingSample
{
class Program
{
static void Main(string[] args)
{
DoSomething();
}
static void DoSomething()
{
LogEnter();
Console.WriteLine("Executing DoSomething");
LogExit();
}
static void LogEnter()
{
StackTrace trace = new StackTrace();
if (trace.FrameCount > 1)
{
string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace;
string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name;
Console.WriteLine("Entering {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name);
}
}
static void LogExit()
{
StackTrace trace = new StackTrace();
if (trace.FrameCount > 1)
{
string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace;
string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name;
Console.WriteLine("Exiting {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name);
}
}
}
}
您可以将上述示例与继承相结合,使用基类型中的非虚拟公共成员来表示操作方法,然后调用虚拟成员来实际完成工作:
public abstract class BaseType
{
public void SomeFunction()
{
LogEnter();
DoSomeFunction();
LogExit();
}
public abstract void DoSomeFunction();
}
public class SubType : BaseType
{
public override void DoSomeFunction()
{
// Implementation of SomeFunction logic here...
}
}
再一次 - 关于这一点并没有太多“自动”,但如果您不需要对每个方法调用进行检测,它将在有限的基础上工作。
希望这可以帮助。
您可以使用Postsharp之类的后编译器。该网站的示例讨论了设置用于进入/退出方法的跟踪器,这与您想要的非常相似。
您可以在具有 LogInjector 的 CodePlex 上使用开源框架CInject来标记方法调用的进入和退出。
或者,您可以按照本文中提到的使用 IL 拦截方法调用的步骤操作,并使用 C# 中的 Reflection.Emit 类创建自己的拦截器。
要扩展 Jared 的答案,避免代码重复并包括参数选项:
private static void LogEnterExit(bool isEnter = true, params object[] args)
{
StackTrace trace = new StackTrace(true); // need `true` for getting file and line info
if (trace.FrameCount > 2)
{
string ns = trace.GetFrame(2).GetMethod().DeclaringType.Namespace;
string typeName = trace.GetFrame(2).GetMethod().DeclaringType.Name;
string args_string = args.Length == 0 ? "" : "\narguments: [" + args.Aggregate((current, next) => string.Format("{0},{1};", current, next))+"]";
Console.WriteLine("{0} {1}.{2}.{3}{4}", isEnter ? "Entering" : "Exiting", ns, typeName, trace.GetFrame(2).GetMethod().Name, args_string );
}
}
static void LogEnter(params object[] args)
{
LogEnterExit(true, args);
}
static void LogExit(params object[] args)
{
LogEnterExit(false, args);
}
static void DoSomething(string arg1)
{
LogEnter(arg1);
Console.WriteLine("Executing DoSomething");
LogExit();
}
DoSomething
在控制台中,如果使用“blah”运行,这将是输出arg1
Entering Program.DoSomething
arguments: [blah]
Executing DoSomething
Exiting Program.DoSomething
这不适用于所有 C# 应用程序,但我在 Asp.Net Core 应用程序中执行以下操作,通过实现以下接口将日志记录添加到控制器方法调用:
IActionFilter,IAsyncActionFilter。
public void OnActionExecuting(ActionExecutingContext context)
public void OnActionExecuted(ActionExecutedContext context)
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)