8

Using Asp.Net Core we can make use of Dependency Injection in controllers/repositories.

However, I wish do do some logging in my Entity Class.

class Person
{
    private ILogger<Person> _logger;
    private List<Pets> pets;

    public Person(ILogger<Person> logger)
    {
        _logger = logger;
    }

    public bool HasCat()
    {
        _logger.LogTrace("Checking to see if person has a cat.");
        // logic to determine cat ownership
        hasCat = true;
        return hasCat;
    }
}

When the Person class is instantiated by EntityFramework it does not attempt to inject any dependencies.

Can I force this? Am i going about it in completely the wrong way?

Ultimatley I just want to be able to use logging consistently throughout the application.

Thanks,

JNB
  • 418
  • 1
  • 4
  • 11
  • 6
    Why do you want to use logging inside your domain classes? Use logging inside the classes which are using your domain classes (Controller / Repositories). – user743414 Jun 28 '18 at 12:26
  • 1
    In this case HasCat() does some things that make more sense on an instance than in a controller. I could simply do the logging where HasCat() is called, but I'd prefer to do it within the method so I'm not duplicating and I can't "forget". – JNB Jun 28 '18 at 12:34
  • Have you tried adding `[FromServices]` to the constructor parameter? – Simply Ged Jun 28 '18 at 12:37
  • I've no clue if it's possible to inject the logger, we've no logic inside our domain classes. So one workaroud could be to pass the logger to the method. Should only happen on rare cases. – user743414 Jun 28 '18 at 12:43
  • 1
    `Can I force this?` Probably, but you shouldn't. `Am i going about it in completely the wrong way?` **Yes**.You are making poor design choices by mixing concerns. Entities should not have implementation concerns. They are no longer entities if they do. Logging is a cross-cutting concern. – Nkosi Jun 28 '18 at 13:04
  • 1
    Related: https://stackoverflow.com/questions/4835046/why-not-use-an-ioc-container-to-resolve-dependencies-for-entities-business-objec – Steven Jun 28 '18 at 14:55
  • 1
    Related: https://stackoverflow.com/a/9915056/264697 – Steven Jun 28 '18 at 14:56
  • 1
    I disagree that this is an anti-pattern. Using a DDD-style approach as per Microsoft's recommendations, it very much makes sense to put domain logic inside entity classes (as shown here: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/net-core-microservice-domain-model). And if you're going to be performing business logic in your entity classes (again, as Microsoft recommends), then it very much makes sense to be able to perform logging in there as well. – Tagc Oct 11 '20 at 21:39

1 Answers1

6

It is possible but I don't recommend it because I agree with commenters that logging belongs in your services and controllers.

EF Core 2.1 allows injecting the DbContext into a private constructor that EF will invoke. See the official docs.

First you need to expose a LoggerFactory property in your DbContext class.

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options, ILoggerFactory loggerFactory = null)
    {
        LoggerFactory = loggerFactory;
    }

    public ILoggerFactory LoggerFactory { get; }
}

Then you can inject the DbContext into a private constructor in your entity class.

public class Person
{
    private readonly ILogger _logger;

    public Person() { } // normal public constructor

    private Person(MyDbContext db) // private constructor that EF will invoke
    {
        _logger = db.LoggerFactory?.CreateLogger<Person>();
    }

    public bool HasCat()
    {
        _logger?.LogTrace("Check has cat");
        return true;
    }
}
Brad
  • 4,493
  • 2
  • 17
  • 24
  • I really wish EF core 2.1 injecting anything into the constructor from your service container (not just those you manually make available in your DbContext). – Jeremy Armstrong Sep 10 '18 at 20:29
  • 4
    This really is not a good answer as it clearly recommends an anemic domain model without any further explanation. related: https://stackoverflow.com/questions/4835046/why-not-use-an-ioc-container-to-resolve-dependencies-for-entities-business-objec – Iso J Aug 19 '19 at 07:25
  • 2
    @IsoJ The very first line where I state _I don't recommend it_ is that not clear enough? – Brad Aug 24 '19 at 05:34
  • 11
    @Brad you clearly recommend putting logging only to services and controllers which basically means that there's no business logic in Entity Classes. This is pretty much a definition of anemic domain model. And to add a personal opinion for the way logging is configured throughout dotnet core applications. I really hate the way loggers are injected through a constructor. Logging is not a dependency as such. It's a cross cutting concern for the whole application. E.g. I prefer the Java way very much over this. – Iso J Aug 27 '19 at 17:22
  • 1
    @IsoJ if a class needs another class in order to perform functionality (logging) then it is a dependency on that class. Logging is no different of a service or functionality or dependency than e.g. injecting some user data transformer or whatever. – James Nov 06 '22 at 18:32
  • @James this is actually a design decision made by dotnet developers. And I have to say I dislike this. Take for example Java where logging is a separate concern outside the scope of dependency injection. Don't want to go to a language war here, but I've not seen any benefit on injecting loggers. It's just extra work. You could eventually start unit testing also logging through some spies, but I have not yet run into that kind of need. – Iso J Apr 28 '23 at 06:59