Table of Contents

Preconditions

Preconditions determine whether a command or interaction can be invoked. They are represented by attributes. They can be applied on modules, commands, interactions and parameters.

Built-in Preconditions

Creating a Custom Precondition Attribute

using NetCord.Services;

namespace MyBot;

// We use generics to make our attribute usable for all types of commands and interactions at the same time
public class RequireAnimatedAvatarAttribute<TContext> : PreconditionAttribute<TContext> where TContext : IUserContext
{
    public override ValueTask<PreconditionResult> EnsureCanExecuteAsync(TContext context, IServiceProvider? serviceProvider)
    {
        // Return a fail result when the user has no avatar or it's not animated
        if (context.User.AvatarHash is not string hash || !hash.StartsWith("a_"))
            return new(PreconditionResult.Fail("You need an animated avatar to use this."));

        return new(PreconditionResult.Success);
    }
}

Example usage

On a module

[RequireAnimatedAvatar<ButtonInteractionContext>]
public class ButtonModule : ComponentInteractionModule<ButtonInteractionContext>
{
    // All interactions here will require animated avatars
}

On a command

public class AvatarModule : CommandModule<CommandContext>
{
    [RequireAnimatedAvatar<CommandContext>]
    [Command("avatar")]
    public string Avatar() => Context.User.GetAvatarUrl()!.ToString();
}

On a minimal API-style command

host.AddSlashCommand(
        name: "hi",
        description: "Hi!",
        [RequireAnimatedAvatar<ApplicationCommandContext>] () => "Hi! You can use this command because your avatar is animated!");

Creating a Custom Parameter Precondition Attribute

using NetCord.Services;

namespace MyBot;

// We use generics to make our attribute usable for all types of commands and interactions at the same time
public class MustContainAttribute<TContext>(string required) : ParameterPreconditionAttribute<TContext>
{
    public override ValueTask<PreconditionResult> EnsureCanExecuteAsync(object? value, TContext context, IServiceProvider? serviceProvider)
    {
        var text = (string)value!;

        // Return a fail result when the parameter value does not contain the required text
        if (!text.Contains(required, StringComparison.InvariantCultureIgnoreCase))
            return new(PreconditionResult.Fail($"The parameter must contain '{required}'."));

        return new(PreconditionResult.Success);
    }
}

Example usage

On a command

public class HelloModule : ApplicationCommandModule<ApplicationCommandContext>
{
    [SlashCommand("hello", "Say hello!")]
    public static string Hello([MustContain<ApplicationCommandContext>("hello")] string text) => text;
}

On a minimal API-style command

host.AddCommand(
        aliases: ["bye"],
        ([MustContain<CommandContext>("bye")] string text) => text);