【问题标题】:About logging every calling of a method in AOP way关于以 AOP 方式记录每个方法的调用
【发布时间】:2018-08-09 04:55:41
【问题描述】:

我想为我的项目创建一个日志系统。我希望它以 AOP 方式进行。需要使用参数和返回值记录每个执行的方法。我怎么理解,它可以通过拦截器来实现。我为它创建了一个宠物项目。它几乎可以工作。我遇到的问题是如何从日志中了解在一个请求期间执行了什么以及在另一个请求期间执行了什么? F.e.我有 asp.net 应用程序。用户来到应用程序。我记录一切。但我不明白一位具体用户做了什么。我只是在日志中看到执行了一个方法,然后执行了另一个方法,依此类推。但是如何定义所有属于具体请求的执行方法呢?

更新: 我知道 ASP.Net 中的过滤器。我将它用于控制器。但我也想记录服务和数据访问层。

另一个更新: nvoigt 的回答有效。非常感谢 nvoigt!

protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        var builder = new ContainerBuilder();
        var config = GlobalConfiguration.Configuration;
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
        builder.RegisterType<ItemService>().As<IItemService>().EnableInterfaceInterceptors().InterceptedBy(typeof(CallLogger)).InstancePerRequest();
        builder.RegisterType<ItemRepository>().As<IItemRepository>().EnableInterfaceInterceptors().InterceptedBy(typeof(CallLogger)).InstancePerRequest();
        builder.RegisterType<CallLogger>().AsSelf().InstancePerRequest();
        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    }

如您所见,CallLoger 具有每个请求的生命周期。我已将 Guid scopeId 属性添加到 CallLogger

public class CallLogger : IInterceptor
{
    private readonly string _path = @"D:\1.txt";
    private readonly Guid _scopeId;
    public CallLogger()
    {
        _scopeId = Guid.NewGuid();
    }

    public void Intercept(IInvocation invocation)
    {
        string message = String.Format("{0}: {1} - Calling method {2} with parameters {3}... ",
            _scopeId,
            invocation.TargetType.FullName, invocation.Method.Name,
            string.Join(", ", invocation.Arguments.Select(a => a)));

        string[] m1 = { message };

        File.AppendAllLines(_path, m1);

        invocation.Proceed();

        List<string> m2 = new List<string>();

        if (invocation.ReturnValue is IEnumerable)
        {
            m2.Add(String.Format($"{_scopeId}: Done {invocation.TargetType.FullName} - {invocation.Method.Name}: result was"));
            foreach (var rv in (IEnumerable)invocation.ReturnValue)
            {
                m2.Add(rv.ToString());
            }
        }
        else
        {
            m2.Add(String.Format($"{_scopeId}: Done {invocation.TargetType.FullName} - {invocation.Method.Name}: result was {invocation.ReturnValue}"));
        }

        File.AppendAllLines(_path, m2);
    }
}

现在我的日志带有 scopeId:

fd35e0f3-a162-48f9-9d69-b39c601513a2: Core.ItemService - Calling method Get with parameters 1... 
fd35e0f3-a162-48f9-9d69-b39c601513a2: Core.Repositories.ItemRepository - Calling method Get with parameters 1... 
fd35e0f3-a162-48f9-9d69-b39c601513a2: Done Core.Repositories.ItemRepository - Get: result was Id is 1, SomeProperty is Property1, AnotherProperty is Another1
fd35e0f3-a162-48f9-9d69-b39c601513a2: Done Core.ItemService - Get: result was Id is 1, SomeProperty is Property1, AnotherProperty is Another1
1ed6bfd7-f786-4397-905e-6ba7027bdd55: Core.ItemService - Calling method Get with parameters 5... 
1ed6bfd7-f786-4397-905e-6ba7027bdd55: Core.Repositories.ItemRepository - Calling method Get with parameters 5... 
1ed6bfd7-f786-4397-905e-6ba7027bdd55: Done Core.Repositories.ItemRepository - Get: result was Id is 5, SomeProperty is Property5, AnotherProperty is Another5
1ed6bfd7-f786-4397-905e-6ba7027bdd55: Done Core.ItemService - Get: result was Id is 5, SomeProperty is Property5, AnotherProperty is Another5

【问题讨论】:

标签: c# asp.net .net aop


【解决方案1】:

你对你实际做了什么非常含糊,所以这个答案对于你需要做的事情有点含糊:

每个日志条目都必须包含一个标识符,因此您可以按标识符对日志条目进行分组,并且基本上为每次调用控制器获取一组日志(控制器日志、服务层的日志、存储库都按他们的初始条目)。

你已经有一个实例来保存每次调用的数据,它是你的依赖注入容器,每次调用都有一个作用域。您需要在其中有一个类来保存您的范围特定数据(例如,每个范围只有一个Guid.NewGuid()),并且您的记录器必须通过您的依赖注入框架访问该类。然后您的记录器可以将该标识符附加到您的日志中,您以后可以按它进行分组。

【讨论】:

  • 对 IoC 容器的好思考
  • 确实,这个问题很模糊。另一方面,如果我知道自己真正需要什么,我通常会使用谷歌。顺便说一句,你的想法很棒!我正在尝试。
猜你喜欢
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-03
相关资源
最近更新 更多