I am using EF Core 3.1 and have several custom services provided via dependency injection, e.g., an ILogger
. How can these services be resolved from within a model, such as when I want to log something from the model?
Adding the dependency to the constructor (like in other classes) means that an empty constructor would not work... which is what is used in all the EF Core examples I can find:
new Author{ FirstName = "William", LastName = "Shakespeare" };
... which suggests DI in a model constructor would be an anti-pattern.
But since models do not inherit, I'm not sure how to get my hands on the other services at runtime (other than a hack like saving a static reference to IServiceProvider
from the Startup
class).
One might argue that models should not contain business logic, and therefore do not need access to services. However, the problem remains — there are times I need to do things with a model that are not triggered by a web request / controller (and therefore, I have no access to the DI services).
Edit: the scenario is actually more complex than a simple logger.
A simplified example of where else I need services looks like this (assuming a I18n
service):
public string Name => GetService<I18n>().Localize(this.translationKey);
The model in this case might be rendered into JSON for the client.
Trying to put this localization code in the Controller or other service seems like a road to copy-pasta spaghetti code. The Name
property is required in many different cases, not just a single controller path. For example, it might be concatenated into another localized string elsewhere. Being forced to do the name localization explicitly from outside the model would be extremely repetitive and burdensome, especially once this example was scaled out to the scope of my app.
I could come up with many more such examples unrelated to logging or I18n.
Another example: how would I know the DbContext
from which the Model was loaded? An app with two databases like mine can easily lose track of this lineage. It seems right now the controller which created the model needs to track this explicitly, whereas if models supported DI they would be able to capture the DbContext
in the constructor.