2

I have registered the implementation of my logger in ServiceCollection in the start up:

services.AddTransient(typeof(ILogger<>), typeof(GenericLogger<>));

Usually, I do this to inject using Constructor:

class DynamoEventProcessor
{
    private readonly IRepository _repository;
    private readonly IDogStatsd _dogStatsd;
    private readonly ILogger<DynamoEventProcessor> _logger;

    public DynamoEventProcessor(IRepository repository, IDogStatsd dogStatsd, ILogger<DynamoEventProcessor> logger)
    {
        _repository = repository;
        _dogStatsd = dogStatsd;
        _logger = logger;
    }
}

But I have a class where there is no constructor:

public class ProfileContent
{
    public MemoryStream Content { get; set; }
    public string ContentAlgorithm { get; set; }
    public List<Dictionary<string, AttributeValue>> DataKeys { get; set; }
    public long ExpiresUtc { get; set; }
    public long Version { get; set; }
    public long Deleted { get; set; }

    public static Dictionary<string, EncryptedDataAndKeys> GetEncryptedDataAndKeys(Dictionary<string, Dictionary<string, AttributeValue>> profileContentAttributes)
    {
        _logger.LogInformation("Available Keys: " + KeysAsString(keyList));
        _logger.LogInformation("AccountId missing Coporate Data: " + _converter.GetValueFromAttributeValue(attributes["AccountId"]).ToString());
        var encryptedDataAndKeys = new Dictionary<string, EncryptedDataAndKeys>();

        foreach (var item in profileContentAttributes)
        {
            encryptedDataAndKeys.Add(item.Key, GetEncryptedDataAndKey(item.Value));
        }

        return encryptedDataAndKeys;
    }
}

My _logger failed here due to null. I understand the problem, that I didn't inject it properly. How can I inject it when I use it in static method without instantiating an object?

SimonG
  • 312
  • 7
  • 20
Muthaiah PL
  • 1,048
  • 3
  • 15
  • 26
  • 1
    I would make the static method a service (probably singelton) and register it in the container. An other solution would be, pass the needed service as parameter. If you realy want to go the route you current do, you need an [service locator](https://dotnetcoretutorials.com/2018/05/06/servicelocator-shim-for-net-core/), which is **not recommended**. – Christian Gollhardt May 27 '19 at 23:47
  • Possible duplicate of [How to use DI inside a static Method in Asp.net Core rc1](https://stackoverflow.com/questions/36027206/how-to-use-di-inside-a-static-method-in-asp-net-core-rc1) – Christian Gollhardt May 27 '19 at 23:56

2 Answers2

11

You can't inject into a static constructor. You have a couple of options:

1.) Pass ILogger into the method, hopefully the calling code has it injected.

2.) Have a static property for ILogger on ProfileContent and then in your Startup file, in the Configure method, initialize it i.e.

ProfileContent.Logger = app.ApplicationServices.GetService<ILogger<ProfileContent>>();

then use Logger in your static method. Personally, I would go for option 1.

JohanP
  • 5,252
  • 2
  • 24
  • 34
  • 3
    The only thing I could add to this is: 3) Get rid of the statics, with Singleton registrations in the DI, do this class really need to be static? – Robert Perry May 28 '19 at 11:38
  • 1
    You preferred option 1. Option 2. was hugely less code for me. What's the reason for preferring option 1.? – Bob Koury Jul 06 '21 at 20:25
  • 3
    Option 2 is the service locator anti pattern. It also blackboxes the creation and assignment of Logger and as a general rule, I'm not a fan of static properties. – JohanP Jul 06 '21 at 23:39
1

Sorry a bit late but for interest for other folks who face this problem .. for static methods you can go with method injection. You cannot use constructor injection in a static class because the constructor of a static class cannot accept any parameters. Also, .net core doesn't allows property injection. So, the only option that is available to us for static class is method injection. Consider the example below in which I am injecting Serilog.ILogger in the HandleModelBindingExceptions method.

        public static IMvcBuilder HandleModelBindingExceptions(this IMvcBuilder builder, ILogger logger)
    {
        var errorInfo = string.Empty;
        string methodName = "HandleModelBindingExceptions";

        builder.ConfigureApiBehaviorOptions(option =>
          {
              //Lambda, Func delegate
              option.InvalidModelStateResponseFactory = 
              context =>
              {
                  try
                  {
                  //Code to parse the errorResponse object 
                  
                  return new ObjectResult(errorResponse) { StatusCode = 400 };
              };
          });

        return builder;

    }