It will findout all the interfaces on the target type, and if they are one of these interfaces:
- IConfigureOptions<>
- IPostConfigureOptions<>
- IValidateOptions<>
It will register it by calling:
services.AddTransient(item, configureType);
In which, item is the matched interface, configureType is the type of the options.
For example, if ConfigureMyOptions
implements IConfigureOptions<MyOptions>
and IPostConfigureOptions<MyOptinos>
, calling:
services.ConfigureOptions<ConfigureMyOptions>();
That is equivalent to:
serivces.AddTransient<IConfigure<MyOptions>, ConfigureMyOptions>();
services.AddTransient<IPostConfigureOptions<MyOptions>, ConfigureMyOptions>();
By decompile, here's the code of ConfgiureOptions:
public static IServiceCollection ConfigureOptions(this IServiceCollection services, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type configureType)
{
services.AddOptions();
bool flag = false;
foreach (Type item in FindConfigurationServices(configureType))
{
services.AddTransient(item, configureType);
flag = true;
}
if (!flag)
{
ThrowNoConfigServices(configureType);
}
return services;
}
Notice how are the interface discovered by reflection:
private static IEnumerable<Type> FindConfigurationServices(Type type)
{
Type[] array = GetInterfacesOnType(type);
foreach (Type type2 in array)
{
if (type2.IsGenericType)
{
Type genericTypeDefinition = type2.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(IConfigureOptions<>) || genericTypeDefinition == typeof(IPostConfigureOptions<>) || genericTypeDefinition == typeof(IValidateOptions<>))
{
yield return type2;
}
}
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "This method only looks for interfaces referenced in its code. The trimmer will keep the interface and thus all of its implementations in that case. The call to GetInterfaces may return less results in trimmed apps, but it will include the interfaces this method looks for if they should be there.")]
static Type[] GetInterfacesOnType(Type t)
{
return t.GetInterfaces();
}
}
And that's how the magic got pulled.