Skip to content

When making an Autocomplete provider for an enum it never gets run at all. #341

@AraHaan

Description

@AraHaan

Description

I have a unique situation where I have an enum parameter, but the options I want to display to the user is specific to the "bot profile roles" the user has set themselves in the bot which affects which enum options must be displayed to the user on the Discord side.

The issue here is that for some reason the autocomplete provider never executes at all as I have also ran the code in Debug configuration and set breakpoints in every line inside of the Autocomplete provider where those breakpoints never gets hit at all. Even after refreshing discord. I suspect the problem might be somewhere in NetCord.

Note: The names of the values in the 2 enums are different than the ones here in the issue, but the general logic is the same.

Steps to Reproduce

The problem command in the module:

/// <summary>
/// Module for profile-related commands.
/// </summary>
[SlashCommand("profile", "Profile-related commands.", Contexts = [InteractionContextType.Guild])]
public class ProfileModule : ApplicationCommandModule<ApplicationCommandContext>
{
    private readonly HttpClient httpClient;
    private readonly IDbContextFactory<BotDbContext> botDbContextFactory;

    /// <summary>
    /// Initializes a new instance of the <see cref="ProfileModule" /> class.
    /// </summary>
    /// <param name="httpClient"></param>
    /// <param name="botDbContextFactory"></param>
    public ProfileModule(HttpClient httpClient, IDbContextFactory<BotDbContext> botDbContextFactory)
    {
        this.httpClient = httpClient;
        this.botDbContextFactory = botDbContextFactory;
    }

    // snip other commands without issues.

    /// <summary>
    /// Sets the image for the current user profile state.
    /// </summary>
    /// <param name="profileState">The profile state to set the image for.</param>
    /// <param name="imageUrl">The url to the image to set this state to.</param>
    /// <returns>The <see cref="InteractionMessageProperties" /> containing the resulting response message.</returns>
    [SubSlashCommand("setimage", "Sets the image for the current user profile state.")]
    public ValueTask<InteractionMessageProperties> SetImageAsync(
        [SlashCommandParameter(Name = "state", Description = "The profile state to set the image for.", AutocompleteProviderType = typeof(UserProfileStateAutocompleteProvider))]
        UserProfileState profileState,
        [SlashCommandParameter(Name = "image", Description = "The url to the image to set this state to.")]
        string imageUrl)
    {
        // The real implementation here is not related to this issue.
        // The problem: None of the options in "UserProfileState" based on the user's profile in the
        // bot's database itself is never display in discord, and because of that the command cannot
        // be used at all.
        return "This is a placeholder for the real implementation which is not the problem here.";
    }

    // snip other commands without issues.
}

The Autocomplete provider that never gets executed at all:

internal class UserProfileStateAutocompleteProvider : IAutocompleteProvider<AutocompleteInteractionContext>
{
    private readonly IDbContextFactory<BotDbContext> botDbContextFactory;
    public UserProfileStateAutocompleteProvider(IDbContextFactory<BotDbContext> botDbContextFactory)
        => this.botDbContextFactory = botDbContextFactory;

    public async ValueTask<IEnumerable<ApplicationCommandOptionChoiceProperties>?> GetChoicesAsync(ApplicationCommandInteractionDataOption option, AutocompleteInteractionContext context)
    {
        // geting the DbContext here should not be the problem here,
        // so is getting the user profile from the UserId onbtained from the context parameter.
        using var dbContext = await this.botDbContextFactory.CreateDbContextAsync().ConfigureAwait(false);
        var profile = await dbContext.GetCurrentUserProfileAsync(context.User.Id).ConfigureAwait(false);
        return (profile != null, profile!.Role.HasFlag(UserProfileRole.Role3), profile.Role.HasFlag(UserProfileRole.Role1), profile.Role.HasFlag(UserProfileRole.Role2)) switch
        {
            (true, false, true, false) => [
                // Role 1 "states".
                UserProfileState.State1.ToOptionChoice()!,
                UserProfileState.State2.ToOptionChoice()!,
                UserProfileState.State3.ToOptionChoice()!,
                UserProfileState.State4.ToOptionChoice()!],
            (true, false, false, true) => [
                // Role 2 "states".
                UserProfileState.State1.ToOptionChoice()!,
                UserProfileState.State5.ToOptionChoice()!,
                UserProfileState.State6.ToOptionChoice()!,
                UserProfileState.State7.ToOptionChoice()!],
            (true, true, true, true) => [
                // Role 3 "states", essentially this includes all of them so far.
                UserProfileState.State1.ToOptionChoice()!,
                UserProfileState.State2.ToOptionChoice()!,
                UserProfileState.State3.ToOptionChoice()!,
                UserProfileState.State4.ToOptionChoice()!,
                UserProfileState.State5.ToOptionChoice()!,
                UserProfileState.State6.ToOptionChoice()!,
                UserProfileState.State7.ToOptionChoice()!],
            // When profile == null/all role checks returning false (possibly invalid profile role).
            _ => [],
        };
    }
}

The enums:

[Flags]
public enum UserProfileRole
{
    None = 0,
    Role1 = 1,
    Role2 = 2,
    Role3 = Role1 | Role2,
}

public enum UserProfileState
{
    None,
    State1,
    State2,
    State3,
    State4,
    State5,
    State6,
    State7,
}

Note: ToOptionChoice on the states essentially returns new(Enum.GetName(value), (int)value) to construct the ApplicationCommandOptionChoiceProperties type.

Version

v1.0.0-alpha.487, but also happens in v1.0.0-alpha.486, v1.0.0-alpha.485, and older.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions