/// <summary> /// Performs a targeting evaluation using the provided <see cref="TargetingContext"/> to determine if a feature should be enabled. /// </summary> /// <param name="context">The feature evaluation context.</param> /// <param name="targetingContext">The targeting context to use during targeting evaluation.</param> /// <exception cref="ArgumentNullException">Thrown if either <paramref name="context"/> or <paramref name="targetingContext"/> is null.</exception> /// <returns>True if the feature is enabled, false otherwise.</returns> public Task <bool> EvaluateAsync(FeatureFilterEvaluationContext context, ITargetingContext targetingContext) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (targetingContext == null) { throw new ArgumentNullException(nameof(targetingContext)); } TargetingFilterSettings settings = context.Parameters.Get <TargetingFilterSettings>() ?? new TargetingFilterSettings(); if (!TryValidateSettings(settings, out string paramName, out string message)) { throw new ArgumentException(message, paramName); } // // Check if the user is being targeted directly if (targetingContext.UserId != null && settings.Audience.Users != null && settings.Audience.Users.Any(user => targetingContext.UserId.Equals(user, ComparisonType))) { return(Task.FromResult(true)); } // // Check if the user is in a group that is being targeted if (targetingContext.Groups != null && settings.Audience.Groups != null) { foreach (string group in targetingContext.Groups) { GroupRollout groupRollout = settings.Audience.Groups.FirstOrDefault(g => g.Name.Equals(group, ComparisonType)); if (groupRollout != null) { string audienceContextId = $"{targetingContext.UserId}\n{context.FeatureName}\n{group}"; if (IsTargeted(audienceContextId, groupRollout.RolloutPercentage)) { return(Task.FromResult(true)); } } } } // // Check if the user is being targeted by a default rollout percentage string defaultContextId = $"{targetingContext.UserId}\n{context.FeatureName}"; return(Task.FromResult(IsTargeted(defaultContextId, settings.Audience.DefaultRolloutPercentage))); }
/// <summary> /// Performs validation of targeting settings. /// </summary> /// <param name="settings">The settings to validate.</param> /// <param name="paramName">The name of the invalid setting, if any.</param> /// <param name="reason">The reason that the setting is invalid.</param> /// <returns>True if the provided settings are valid. False if the provided settings are invalid.</returns> private bool TryValidateSettings(TargetingFilterSettings settings, out string paramName, out string reason) { const string OutOfRange = "The value is out of the accepted range."; const string RequiredParameter = "Value cannot be null."; paramName = null; reason = null; if (settings.Audience == null) { paramName = nameof(settings.Audience); reason = RequiredParameter; return(false); } if (settings.Audience.DefaultRolloutPercentage < 0 || settings.Audience.DefaultRolloutPercentage > 100) { paramName = $"{settings.Audience}.{settings.Audience.DefaultRolloutPercentage}"; reason = OutOfRange; return(false); } if (settings.Audience.Groups != null) { int index = 0; foreach (GroupRollout groupRollout in settings.Audience.Groups) { index++; if (groupRollout.RolloutPercentage < 0 || groupRollout.RolloutPercentage > 100) { // // Audience.Groups[1].RolloutPercentage paramName = $"{settings.Audience}.{settings.Audience.Groups}[{index}].{groupRollout.RolloutPercentage}"; reason = OutOfRange; return(false); } } } return(true); }