Closed tugberkugurlu closed 5 years ago
Thanks for contacting us, @tugberkugurlu. @rynowak, can you please help out @tugberkugurlu here? Thanks!
Hi @tugberkugurlu - you should instead register an additional implementation if IActionDescriptorProvider
- make the order value a bigger number than the build in implementations.
These are a pipeline so when yours is called you'll see the results of the other providers in context.Results
and you can do your filtering by removing items you want to turn off.
I think you'll find this more straightforward than what you're currently doing.
Lovely ✨ That's a much better way to approach the problem, thanks @rynowak! Will give that a go, I am hoping that NSwag will also honor that as it's honoring the custom IActionDescriptorCollectionProvider
but seems like all is connected together and at the end produce a coherent set of actions.
Is this a Bug or Feature request?:
I would say neither, I am looking for a migration guidance.
Description of the problem:
At v2.1 or below,
ActionDescriptorCollectionProvider
wasn't an abstract class and I was able to hold a reference to within my own implementation for anIActionDescriptorCollectionProvider
. Including it below for reference but it won't compile as it's missing related components:FeatureFlagAwareActionDescriptorCollectionProvider.cs
``` public class FeatureFlagAwareActionDescriptorCollectionProvider : IActionDescriptorCollectionProvider { private bool _initialized; private object _initializationLock = new object(); private object _initializationTarget; private readonly IServiceProvider _serviceProvider; private readonly ActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; private IReadOnlyList _filteredActionDescriptors;
public FeatureFlagAwareActionDescriptorCollectionProvider(IEnumerable actionDescriptorProviders,
IEnumerable actionDescriptorChangeProviders, IServiceProvider serviceProvider)
{
if (actionDescriptorProviders == null) throw new ArgumentNullException(nameof(actionDescriptorProviders));
if (actionDescriptorChangeProviders == null) throw new ArgumentNullException(nameof(actionDescriptorChangeProviders));
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
_actionDescriptorCollectionProvider = new ActionDescriptorCollectionProvider(actionDescriptorProviders, actionDescriptorChangeProviders);
}
///
public ActionDescriptorCollection ActionDescriptors
{
get
{
EnsureInitialized();
return new ActionDescriptorCollection(_filteredActionDescriptors, _actionDescriptorCollectionProvider.ActionDescriptors.Version);
}
}
private bool IsFeatureFlagged(ControllerActionDescriptor descriptor)
{
var ffAttributeData = descriptor.MethodInfo.CustomAttributes.FirstOrDefault(attribute =>
attribute.AttributeType == typeof(FeatureFlaggedAttribute));
if (ffAttributeData != null)
{
var ffAttribute = (FeatureFlaggedAttribute) descriptor.MethodInfo.GetCustomAttribute(typeof(FeatureFlaggedAttribute));
var optionsType = typeof(IOptions<>).MakeGenericType(ffAttribute.FeatureFlagType);
var featureFlagOption = _serviceProvider.GetService(optionsType);
// ReSharper disable once PossibleNullReferenceException - we know that GetProperty will not going to be null.
var featureFlag = optionsType.GetProperty(nameof(IOptions.Value)).GetValue(featureFlagOption) as IFeatureFlag;
// ReSharper disable once PossibleNullReferenceException - we rely on the fact that this will be auto-registered by the DI system.
return !featureFlag.IsEnabled;
}
return false;
}
private void EnsureInitialized()
{
LazyInitializer.EnsureInitialized(ref _initializationTarget, ref _initialized, ref _initializationLock, () =>
{
_filteredActionDescriptors = _actionDescriptorCollectionProvider.ActionDescriptors
.Items
.Where(descriptor =>
{
if (descriptor is ControllerActionDescriptor controllerActionDescriptor)
{
return !IsFeatureFlagged(controllerActionDescriptor);
}
return true;
})
.ToList();
return null;
});
}
private class MarkerFeatureFlag : IFeatureFlag
{
public bool IsEnabled { get; set; }
}
}
```
With 2.2.0,
ActionDescriptorCollectionProvider
seems to be an abstract class now and actual implementation is done inside the internalDefaultActionDescriptorCollectionProvider
class.With 2.2.0, would you please advice what my options are to implement the action selection filtering logic as above?
Version of
Microsoft.AspNetCore.Mvc
orMicrosoft.AspNetCore.App
orMicrosoft.AspNetCore.All
:2.2.0