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

时间:2018-08-08 06:58:31

标签: c# asp.net .net aop

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

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

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

// New ListContainer.js

// Same imports

// Extracted component
const ListElement = props => {
  const { del } = props;
  const { _id } = props.item;
  const { name } = props.item;
  return (
    <CSSTransition key={_id} timeout={500} classNames="fade">
      <ListGroupItem>
        <Button
          className="remove-btn"
          color="danger"
          size="sm"
          onClick={() => del(_id)}>
          &times;
        </Button>
        {name} {_id}
      </ListGroupItem>
    </CSSTransition>
  );
}

// Refactored parent component
class ListContainer extends Component {

  componentDidMount() {
    this.props.getItems();
  }

  del = (id) => {
    this.props.deleteItem(id);
  }

  render() {
    const { items } = this.props.item;

    return(
      <Container>
        <ListGroup>
          <TransitionGroup className="shopping-list">
            {
              items.map((item, i) => (
                <ListElement key={i} item={item} del={ id => this.del(id) } />
              ))
            }
          </TransitionGroup>
        </ListGroup>
      </Container>
    );
  }
}

// Same redux connector

您看到的是,CallLoger具有每个请求生存期。并且我已将 Guid scopeId 属性添加到CallLogger

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);
    }

现在,我的日志具有scopeId:

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);
    }
}

1 个答案:

答案 0 :(得分:2)

您对自己实际所做的事情非常含糊,因此此答案也与您需要做的事情一样含糊:

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

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