Skip to content
This repository was archived by the owner on Nov 7, 2018. It is now read-only.

Add Initialize<TOptions> #187

Closed
wants to merge 4 commits into from
Closed

Add Initialize<TOptions> #187

wants to merge 4 commits into from

Conversation

HaoK
Copy link
Member

@HaoK HaoK commented Apr 26, 2017

#185

Needed to replace double locking/options fixup in auth as we discussed last week.

@ajcvickers @Tratcher @Eilon @davidfowl

@MaKCbIMKo
Copy link

For me it looks like the same as Configure step (does the same). But another step right after the configuration one. Is the main goal of that is make sure that it will be called right after all configurations?

What if something will require step number 3 (PostConfigure or something else)?

Maybe need to create more complex solution? I know that's too much, but more long-term solution.


/// <summary>
/// Initializes a new instance with the specified options configurations.
/// </summary>
/// <param name="setups">The configuration actions to run.</param>
public OptionsFactory(IEnumerable<IConfigureOptions<TOptions>> setups)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep the old ctor for compat, and have it chain to the new ctor? DI would only call the new ctor anyway, but it would avoid a breaking change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We added this type in 2.0 so no breaking change thankfully

@@ -69,5 +69,43 @@ public static IServiceCollection Configure<TOptions>(this IServiceCollection ser

public static IServiceCollection ConfigureAll<TOptions>(this IServiceCollection services, Action<TOptions> configureOptions) where TOptions : class
=> services.Configure(name: null, configureOptions: configureOptions);

/// <summary>
/// Registers an action used to Initialize a particular type of options.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to capitalize the I of Initialize (it's just a word here, not a method name).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Applies to other doc comments in this PR.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'll fix, global find/replace fail, I just cloned the ConfigureOptions files and replaced

/// <param name="name">The name of the options instance.</param>
/// <param name="InitializeOptions">The action used to Initialize the options.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection Initialize<TOptions>(this IServiceCollection services, string name, Action<TOptions> InitializeOptions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename InitializeOptions param to start with lowercase letter.

public class InitializeOptions<TOptions> : IInitializeOptions<TOptions> where TOptions : class
{
/// <summary>
/// Constructor.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creates a new instance of...

/// <param name="action">The action to register.</param>
public InitializeOptions(string name, Action<TOptions> action)
{
Name = name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these params need any checks? Can they be empty? Null? Anything?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null name signify's applying to all names.
string.empty is used to target the 'default' name, i.e. the overloads that don't specify name

Passing in a null action is equivalent to passing in a no-op o => { }, so I don't think its something we explicitly need to block (we didn't for the existing https://github.com/aspnet/Options/blob/dev/src/Microsoft.Extensions.Options/ConfigureOptions.cs, so we need to be consistent) Note: we do require non null actions on the sugar Configure/Initialize apis since it doesn't make sense to add no-op/null actions there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.

namespace Microsoft.Extensions.Options
{
/// <summary>
/// Implementation of IInitializeNamedOptions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can use a typeref for the type in this doc.

services.Configure<FakeOptions>(o => o.Message += "0");
services.Configure<FakeOptions>("1", o => o.Message += "1");
services.InitializeAll<FakeOptions>(o => o.Message += "Initialize");
services.Initialize<FakeOptions>(o => o.Message += "2");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm just confused, but doesn't this Initialize initialize all FakeOptions, because no name was specified??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah its a bit confusing,

All overloads that don't take a name target the Options.DefaultName = string.Empty; This was done to make all of the existing options.Configures behave the same in Options 2.0 since we added names, and wanted to preserve the existing semantics and behaviors.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should define some non-empty string to have this meaning. Like "Default", or something more specific if we think avoiding collisions is important. The empty-string is very un-documenting.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah let's get that figured out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the actual value for the default name doesn't matter too much, we use Options.DefaultName everywhere, its currently set to string.empty since that seemed like a good default to me, in general the constant should be used everywhere but if we want to change it, its just changing this line: https://github.com/aspnet/Options/blob/dev/src/Microsoft.Extensions.Options/Options.cs#L11

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, whatever value we pick, its just used as the default for the overloads that don't specify a name, so it doesn't really have any documention value other than if you were debugging a custom IConfigure/InitializeOptions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its pretty clear today if you look at the usage in the overloads with the constant:

https://github.com/aspnet/Options/blob/dev/src/Microsoft.Extensions.Options/OptionsServiceCollectionExtensions.cs#L43

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion on the exact name, I just feel strongly about "let's get that figured out" 😄 @ajcvickers ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel strongly, so I'll let @HaoK make the call. I would be a little confused if I was attempting to debug code that was using this, or if I passed empty string and go back something, but I guess most people won't do those things.

Copy link
Member Author

@HaoK HaoK Apr 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay lets keep it as empty string for now, since this isn't new for Initialize.

empty string is pretty weird name to pick, and you wouldn't actually see any issues with using it as your name, unless you configured using both methods.

services.Configure(o => o.Foo = "bar");
services.Configure("", o => o.Foo = "what??");

@HaoK
Copy link
Member Author

HaoK commented May 8, 2017

Updated to fix casing, also added references in the doc comments for Configure/Initialize to each other and whether they run before/after each other.

Also added a test/fix for a minor issue with old IConfigureOptions being run for all named instances instead of only the default instance

@HaoK
Copy link
Member Author

HaoK commented May 15, 2017

Merged 52ab5f1

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants