Interceptor with Microsoft.Extensions.DependencyInjection and asp.net web api 2 for cross cutting concerns like logging

7.5k Views Asked by At

We are using Microsoft.Extensions.DependencyInjection in our asp.net web api2 for dependency injection.

For cross cutting concerns like logging, we are of thought that aspect oriented programming should be considered and unable to find any support in the above di.

Other DI like castle, Unity and ninject are opted out post looking at their benchmarks. Is there any way to use injectors of other di frameworks like castle dynamic proxy and use it with Microsoft.Extensions.DependencyInjection?

Any suggestions related to IL-weaving frameworks are also welcomed. Consideration of PostSharp is ruled out as it isn't free.

3

There are 3 best solutions below

5
Peter Bons On

I am not convinced you need a tool like PostSharp or any other AOP tool for this when developing web api's. There are numerous extension points where you can plug in your logging/auditing/whatever actions. A good overview would be this poster

You could create an Action Filter. You can register this globally across all controllers (if needed) or a MessageHandler for example.

Now, adressing your comment:

[..] What about logging in classes of business layer/data access layer like any exceptions/ custom messages without making direct calls to logger. [..]

I am not sure what you want to achieve by this. If you have proper exception handling you have to deal with the exception or let it bubble up. When writing the exception handling, why not write one extra line that logs whatever you need? It gives you the opportunity to add meaningful context as well to your log message, something that is hard to do using an automated AOP tool!

Lastly, let me address this comment:

Consideration of PostSharp is ruled out as it isn't free.

Tools like PostSharp are very, very much worth their money if it can address the issue at hand. Sure you can spend day researching free alternatives or write your own implementation but it will probably much more limited, needs refactoring of your existing codebase, difficult to maintain for the team as a whole and it will swallow lots of time. The alternative might be more expensive than the tool.

0
Dan Rayson On

I'd argue you don't need any AOP frameworks, .NET provides just enough tooling to be able to do the majority of the aspect oriented stuff yourself.

The short version is this:

  1. Inherit from MarshalByRefObject on your business class.

  2. Create an "Aspect" for your desired functionality. As in, create a class that inherits from RealProxy. e.g. public class LoggingAspect<T> : RealProxy.

  3. override the Invoke method, and implement your aspect code. Make sure to pass-though the method call to the original instance.

  4. Create a builder/factory class that will create instances of the desired classes, e.g. Entity e = EntityBuilder.WithLogging();

  5. Replace all instance of new Entity(...) with EntityBuilder.Get(...).

The long version is much better explained by Microsoft employees themselves:

Aspect-Oriented Programming : Aspect-Oriented Programming with the RealProxy Class

1
Laurynas Lazauskas On

Decor.NET is a wrapper around Castle.Core dynamic proxy, which aims to simplify method decoration.

It is DI container agnostic, but has an integration with Microsoft's DI, which is available in Decor.Extensions.Microsoft.DependencyInjection NuGet package.

  1. You create a decorator:

    public class YourDecorator : IDecorator
    {    
        public SomeDependency SomeDependency { get; }    
    
        public YourDecorator(SomeDependency someDependency) // Supports DI.
        {
            SomeDependency = someDependency;
        }
    
        public async Task OnInvoke(Call call)
        {
            ...
            await call.Next();
            ...
        }
    }
    
  2. Decorate your methods:

    [Decorate(typeof(YourDecorator))]
    virtual void SomeMethod()  // << has to be overridable (can come from an interface)
    {
        ...
    }
    
  3. Register everything in Microsofts' DI:

    services.AddDecor()
        .AddTransient<YourDecorator>()
        .AddScoped<YourService>().Decorated();
    

You can play around in this .Net Fiddle.


Disclosure: I'm the author of this package.