Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting a logger with constructor dependencies

I'm trying to refactor some code to use .NET Core dependency injection via mapping services in startup.cs. I would like to inject an IRequestDatabaseLogger here instead of newing it up. However it requires the context in the constructor. How can I achieve this? Is it even possible without an DI framework or even then?

    public class ActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            var requestDatabaseLogger = new RequestDatabaseLogger(context);
            long logId = requestDatabaseLogger.Log();

            context.HttpContext.AddCurrentLogId(logId);

            base.OnActionExecuting(context);
        }
   }
like image 920
Lars Thorén Avatar asked Feb 06 '17 07:02

Lars Thorén


2 Answers

However it requires the context in the constructor.

Letting the construction of application components depend on runtime data is an anti-pattern, as described here. That article describes how to solve these problems in general.

In your case this probably means that your component should depend on ASP.NET Core's IHttpContextAccessor abstraction instead, which is a pattern described in the referenced article.

Alternatively, as described in the article, you can pass through the required runtime data to the logger using it's Log method.

like image 99
Steven Avatar answered Oct 28 '22 01:10

Steven


You should use the TypeFilter to achieve this, and wrap the filter that has the dependency (in this case on a logger or a context) inside of the filter. I show a detailed example of this in my MSDN Article on ASP.NET Core Filters. The related source code is here (look at the ValidateAuthorExists filter).

Here's what it might look like in your scenario:

public class MyFilterAttribute : TypeFilterAttribute
{
    public MyFilterAttribute():base(typeof(MyFilterImpl))
    {
    }

    private class MyFilterImpl : IAsyncActionFilter
    {
        public MyFilterImpl( *inject dependencies here*)
        {}
    }
}

This is how you can use attributes in .NET Core while still injecting dependencies into the underlying action filter. I also cover this in my upcoming ASP.NET Core Quickstart course on DevIQ.com (look for it end of this month).

like image 24
ssmith Avatar answered Oct 28 '22 00:10

ssmith