1

I have an extension method which is used to read a particular claim from the current ClaimsPrincipal. But I also need to check this value against a list of items which I have in the appsettings.json. I had this working by using a ConfigurationBuilder() to read the appsettings directly in much the same way as the startup does, although instead of using

.SetBasePath(Directory.GetCurrentDirectory())

as I do in the startup, I was using

.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))

Which although isn't pretty, works fine. However, when the Unit tests are run none of the following get me to where the appsettings are

Directory.GetCurrentDirectory()
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)

and I cannot see a way of getting the IHostingEnvironment or something similar into the extension method to read out the appsettings, or indeed to ditch the ConfigurationBuilder() and get at IOptions in the extension method, in such a way that the unit test and the running code will work correctly.

I assume there must be a way of doing this? Although I expect that I should simply not be trying at all and lift the check against the list of items into another class entirely...

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
nat
  • 2,185
  • 5
  • 32
  • 64
  • 1
    Seems like you are fighting against DI with your extension methods. Is there any reason you can't pass the configuration as a parameter to your extension method? – SpruceMoose Feb 20 '18 at 11:47
  • not really if I'm honest, I think that may be the simplest option – nat Feb 20 '18 at 12:37

1 Answers1

3

Putting business logic that may ever require dependencies into static methods is not recommended. This makes it difficult to inject dependencies into them. Options are few:

  1. Redesign the static method into a service so dependencies can be injected through the constructor. (Recommended)

public class Foo : IFoo
{
    private readonly IOptions<FooOptions> optionsAccessor;
    public Foo(IOptions<FooOptions> optionsAccessor)
    {
        this.optionsAccessor = optionsAccessor ??
            throw new ArgumentNullException(nameof(optionsAccessor));
    }

    public void DoSomething()
    {
         var x = this.optionsAccessor;

         // Same implementation as your static method
    }
}
  1. Inject the dependencies as parameters of the extension method.

public static void DoSomething(this object o, IOptions<FooOptions> optionsAccessor)
{
    // Implementation
}
  1. Redesign the static method to be a facade over an abstract factory like this example.
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • thanks, I was hoping not to have to redo this as its only a particular implementation for our load balancing environment, but I guess there is no escape. thanks for your help – nat Feb 20 '18 at 12:51