loggingblazoraopfody

How Blazor Server AOP logging?


I would like to implement and use an AOP logging in my Blazor Server .NET 5 (C# 9) application, for generic enter-exit-exception scenarios for the marked method(s).

I know how to do it with MethodBoundaryAspect.Fody NuGet package and a custom Attribute, but with Dependency Injection I cannot inject an ILogger into the custom Attribute (which lifecycle also not controlled by the build in service provider), so it seems this is not a viable solution anymore. I don't stick to Attribute as a solution, it just seems very practical.

My overall target is to get rid of the boilerplate code lines for general logging in product methods. With another attribute (or something else) elapsed time measuring would be a piece of cake with the desired solution.


Solution

  • It's true that you can't use dependency injection to inject services into the constructor of your attribute. Considering that they represent compile-time meta data this shouldn't be too surprising.

    However, if we take a step back, we can take advantage of interfaces in combination with information passed to your method interceptors. We'll focus on OnEntry, but the same will apply to OnExit and OnException.

    public virtual void OnEntry(MethodExecutionArgs arg)
    {
    }
    

    MethodExecutionArgs has a variety of useful properties but we'll just focus on one: the Instance property. Given that this property represents the instance of the class that contains the method being intercepted, you can choose to make some assumptions about what interfaces that class implements.

    If you define a new interface, say ILoggerProvider you can have the class that contains the methods you want to log implement this interface to give your aspect a handle to ILogger:

    public interface ILoggerProvider
    {
        ILogger Logger { get; }
    }
    

    Putting this all together, your class should resemble something like this:

    public class MyProduct : ILoggerProvider
    {
        public ILogger Logger { get; }
    
        public MyProduct(ILogger logger)
        {
            Logger = logger;
        }
    
        [Log]
        public void M()
        {
        }
    }
    

    And finally, your aspect should look something like:

    public class LogAttribute : OnMethodBoundaryAspect
    {
        private ILogger GetLogger(MethodExecutionArgs args) => ((ILoggerProvider)args.Instance).Logger;
    
        public override void OnEntry(MethodExecutionArgs args)
        {
            var logger = GetLogger(args);
            // Log whaat you will
        }
    
        public override void OnExit(MethodExecutionArgs args)
        {
            var logger = GetLogger(args);
            // Log whaat you will
        }
    
        public override void OnException(MethodExecutionArgs args)
        {
            var logger = GetLogger(args);
            // Log whaat you will
        }
    }
    

    Note: this assumes that the methods you want to intercept are not static methods, as they will obviously have a null Instance.