Reputation: 8432
I'm having trouble manually constructing a IServiceProvider
that will allow my unit tests to use it to pull in shared test configuration using GetService<IOptions<MyOptions>>
I created some unit tests to illustrate my problems, also the repo for this can be found here if it's useful in answering the question.
The JSON
{
"Test": {
"ItemOne": "yes"
}
}
The Options Class
public class TestOptions
{
public string ItemOne { get; set; }
}
The Tests
Out of these tests ConfigureWithBindMethod
and ConfigureWithBindMethod
both fail, where SectionIsAvailable
passes. So the section is being consumed as expected from the JSON file as far as I can tell.
[TestClass]
public class UnitTest1
{
[TestMethod]
public void ConfigureWithoutBindMethod()
{
var collection = new ServiceCollection();
var config = new ConfigurationBuilder()
.AddJsonFile("test.json", optional: false)
.Build();
collection.Configure<TestOptions>(config.GetSection("Test"));
var services = collection.BuildServiceProvider();
var options = services.GetService<IOptions<TestOptions>>();
Assert.IsNotNull(options);
}
[TestMethod]
public void ConfigureWithBindMethod()
{
var collection = new ServiceCollection();
var config = new ConfigurationBuilder()
.AddJsonFile("test.json", optional: false)
.Build();
collection.Configure<TestOptions>(o => config.GetSection("Test").Bind(o));
var services = collection.BuildServiceProvider();
var options = services.GetService<IOptions<TestOptions>>();
Assert.IsNotNull(options);
}
[TestMethod]
public void SectionIsAvailable()
{
var collection = new ServiceCollection();
var config = new ConfigurationBuilder()
.AddJsonFile("test.json", optional: false)
.Build();
var section = config.GetSection("Test");
Assert.IsNotNull(section);
Assert.AreEqual("yes", section["ItemOne"]);
}
}
Possibly useful to point out
When calling config.GetSection("Test")
in the immediate window, I get this value
{Microsoft.Extensions.Configuration.ConfigurationSection}
Key: "Test"
Path: "Test"
Value: null
At face value I'd have assumed Value should not be null, which is leading me to think I may be missing something obvious here, so if anyone can spot what I'm doing wrong that'd be genius.
Upvotes: 18
Views: 14314
Reputation: 27894
First off, upvote kloarubeek's answer. I was stuck before I got through it.
I have a different twist.
This did not work (emphasis on 'AddSingleton')
MyCustomConfigurationPoco concreteMyCustomConfigurationPoco =
new MyCustomConfigurationPoco();
configuration.GetSection("MyJsonName")
.Bind(concreteMyCustomConfigurationPoco);
servColl.AddSingleton<MyCustomConfigurationPoco>(concreteMyCustomConfigurationPoco);
But changing to this did work:
MyCustomConfigurationPoco concreteMyCustomConfigurationPoco =
new MyCustomConfigurationPoco();
configuration.GetSection("MyJsonName")
.Bind(concreteMyCustomConfigurationPoco);
/* my caveat here */
servColl.Configure<MyCustomConfigurationPoco>(option =>
{
option.SomeScalarPropertyOne = concreteMyCustomConfigurationPoco.SomeScalarPropertyOne;
option.SomeScalarPropertyTwo = concreteMyCustomConfigurationPoco.SomeScalarPropertyTwo;
});
You might be asking "How is this different from the other answer?"
I actually had to set a value from somewhere besides .json before injecting it into the IoC.
So where I have above.
/* my caveat here */
imagine code like this
option.SomeScalarPropertyTwo = AnotherThing.GetSomeScalarPropertyTwo();
So I had to manipulate the MyCustomConfigurationPoco (instantiation) before injecting it into the IoC.
But now my "getter" code works as seen below:
IOptions<MyCustomConfigurationPoco> concreteMyCustomConfigurationPocoOptions =
servProv.GetService<IOptions<MyCustomConfigurationPoco>>();
if (null == concreteMyCustomConfigurationPocoOptions)
{
throw new ArgumentNullException(nameof(concreteMyCustomConfigurationPocoOptions));
}
MyCustomConfigurationPoco concreteMyCustomConfigurationPoco =
concreteMyCustomConfigurationPocoOptions.Value;
if (null == concreteMyCustomConfigurationPoco)
{
throw new ArgumentNullException(nameof(concreteMyCustomConfigurationPoco));
}
Upvotes: 1
Reputation: 2854
To use options in your service collection, you need to add the service required for using options collection.AddOptions();
This should do the trick:
[TestMethod]
public void ConfigureWithoutBindMethod()
{
var collection = new ServiceCollection();
collection.AddOptions();
var config = new ConfigurationBuilder()
.AddJsonFile("test.json", optional: false)
.Build();
collection.Configure<TestOptions>(config.GetSection("Test"));
var services = collection.BuildServiceProvider();
var options = services.GetService<IOptions<TestOptions>>();
Assert.IsNotNull(options);
}
Upvotes: 31