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
- RequireUserPermissionsAttribute<TContext> - ensures that the user invoking the command or interaction has the specified permissions.
- RequireBotPermissionsAttribute<TContext> - ensures that the bot has the specified permissions.
- RequireContextAttribute<TContext> - ensures that the command or interaction is invoked in the specified context like Guild, GroupDM or DM.
- RequireNsfwAttribute<TContext> - ensures that the command or interaction is invoked in a NSFW channel.
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);