c# - 关于以AOP方式记录方法的每次调用

标签 c# asp.net .net aop

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

更新: 我了解 ASP.Net 中的过滤器。我用它作为 Controller 。但我也想记录服务和数据访问层。

另一个更新: 恩沃伊特的答案有效。非常感谢 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 rangeId 属性添加到 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

最佳答案

你对你实际做了什么非常模糊,所以这个答案对于你需要做什么也很模糊:

每个日志条目都必须包含一个标识符,以便您可以按标识符对日志条目进行分组,并且基本上为每次调用 Controller 获取一组日志( Controller 日志、服务层日志、存储库均按以下方式分组在一起)他们的初始条目)。

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

关于c# - 关于以AOP方式记录方法的每次调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51740353/

相关文章:

c# - 包括一个集合,然后是下一级的集合

c# - 在 asp.net webservices (asmx) 中,是从代码调用时应用的 CacheDuration

c# - 应用程序目录中所有用户的可写 .config 文件?

c# - 关于mssql和mysql中的select查询以及表名的保留关键字问题

asp.net - 尝试访问谷歌分析时指定的提供商类型无效

.net - Horizo​​ntalAlignment 设置为 Stretch 和 Left 的 TextBox

c# - 在 Linq select 子句中重用表达式(查询格式)

c# - 设置 DatePicker 值

c# - 为什么返回 Task<int> 而不是 int? (异步和等待)

c# - 为 MVVM 选择的多个列表框/集合项