Skip to main content

Overview

Environment filters allow you to control handler execution based on the runtime environment of your application. These filters are useful for enabling debug features, testing functionality, or creating environment-specific behavior.

Build Configuration

IsDebugEnvironment

Filters updates to only execute when the application is running in debug mode. Example:
[IsDebugEnvironment]
public async Task HandleDebugMessage()
{
    // Only executes when compiled in Debug configuration
    await Bot.SendTextMessageAsync("Debug mode is active");
}

[CommandHandler("test")]
[IsDebugEnvironment]
public async Task HandleTestCommand()
{
    // Test commands only available in debug builds
    await RunDiagnostics();
}

[TextStartsWith("debug")]
[IsDebugEnvironment]
public async Task HandleDebugCommands()
{
    // Debug-specific message handling
    await ProcessDebugMessage();
}

IsReleaseEnvironment

Filters updates to only execute when the application is running in release mode. Example:
[IsReleaseEnvironment]
public async Task HandleProductionMessage()
{
    // Only executes when compiled in Release configuration
    await ProcessProductionMessage();
}

[CommandHandler("deploy")]
[IsReleaseEnvironment]
public async Task HandleDeploy()
{
    // Deployment commands only in production
    await PerformDeployment();
}

[IsReleaseEnvironment]
[ChatId(-1001234567890)]
public async Task HandleProductionChat()
{
    // Production chat handling
}

Environment Variables

EnvironmentVariable

Filters updates based on environment variable values. This powerful filter allows you to control behavior based on configuration without recompiling.
variable
string
required
The name of the environment variable.
value
string
The expected value of the environment variable (optional).
comparison
StringComparison
default:"InvariantCulture"
The string comparison method.
Check if Variable Exists:
[EnvironmentVariable("FEATURE_ENABLED")]
public async Task HandleFeature()
{
    // Executes if FEATURE_ENABLED environment variable exists (any value)
    await RunFeature();
}
Check Variable Value:
[EnvironmentVariable("ENVIRONMENT", "production")]
public async Task HandleProduction()
{
    // Only executes if ENVIRONMENT=production
    await HandleProductionUpdate();
}

[EnvironmentVariable("ENVIRONMENT", "development")]
public async Task HandleDevelopment()
{
    // Only executes if ENVIRONMENT=development
    await HandleDevUpdate();
}
Case-Insensitive Matching:
[EnvironmentVariable("LOG_LEVEL", "debug", StringComparison.OrdinalIgnoreCase)]
public async Task HandleDebugLogging()
{
    // Matches DEBUG, debug, Debug, etc.
    await EnableVerboseLogging();
}
Multiple Environment Checks:
[EnvironmentVariable("FEATURE_FLAGS", "advanced")]
[EnvironmentVariable("USER_TIER", "premium")]
public async Task HandleAdvancedFeature()
{
    // Both environment variables must match
    await ActivateAdvancedFeature();
}

Practical Examples

Feature Flags

[CommandHandler("ai")]
[EnvironmentVariable("FEATURE_AI", "enabled")]
public async Task HandleAIFeature()
{
    // AI feature only when enabled via environment variable
    await ProcessWithAI();
}

[CommandHandler("beta")]
[EnvironmentVariable("BETA_FEATURES", "true")]
public async Task HandleBetaFeature()
{
    // Beta features controlled by environment
    await RunBetaFeature();
}

Environment-Specific Logging

[EnvironmentVariable("LOG_LEVEL", "verbose")]
public async Task LogVerbose()
{
    // Detailed logging when LOG_LEVEL=verbose
    await LogDetailedInformation();
}

[IsDebugEnvironment]
public async Task LogDebugInfo()
{
    // Debug logging in debug builds
    Console.WriteLine($"Update received: {Update.Type}");
}

Multi-Environment Bot

[CommandHandler("status")]
[EnvironmentVariable("ENVIRONMENT", "production")]
public async Task HandleProductionStatus()
{
    await Bot.SendTextMessageAsync("Production Status: ✓ Online");
}

[CommandHandler("status")]
[EnvironmentVariable("ENVIRONMENT", "staging")]
public async Task HandleStagingStatus()
{
    await Bot.SendTextMessageAsync("Staging Status: ⚠ Testing");
}

[CommandHandler("status")]
[EnvironmentVariable("ENVIRONMENT", "development")]
public async Task HandleDevStatus()
{
    await Bot.SendTextMessageAsync("Development Status: 🔧 Dev Mode");
}

Testing and QA

[IsDebugEnvironment]
[CommandHandler("simulate")]
public async Task HandleSimulate()
{
    // Simulation commands only in debug
    await SimulateScenario();
}

[EnvironmentVariable("QA_MODE", "enabled")]
public async Task HandleQAMode()
{
    // Special handling for QA testing
    await EnableQAFeatures();
}

[EnvironmentVariable("TEST_DATA", "mock")]
public async Task UseMockData()
{
    // Use mock data instead of real API calls
    await LoadMockData();
}

Region-Specific Features

[CommandHandler("payments")]
[EnvironmentVariable("REGION", "US")]
public async Task HandleUSPayments()
{
    // US-specific payment handling
    await ProcessUSPayment();
}

[CommandHandler("payments")]
[EnvironmentVariable("REGION", "EU")]
public async Task HandleEUPayments()
{
    // EU-specific payment handling with GDPR compliance
    await ProcessEUPayment();
}

Maintenance Mode

[EnvironmentVariable("MAINTENANCE_MODE", "true")]
public async Task HandleMaintenanceMode()
{
    // Respond to all messages during maintenance
    await Bot.SendTextMessageAsync(
        "🔧 Bot is currently under maintenance. Please try again later."
    );
}

[EnvironmentVariable("MAINTENANCE_MODE", "false")]
[CommandHandler("help")]
public async Task HandleHelp()
{
    // Normal operation when not in maintenance
    await ShowHelpMenu();
}

Admin Features

[CommandHandler("admin")]
[EnvironmentVariable("ADMIN_ENABLED", "true")]
[FromUserId(123456789)]
public async Task HandleAdminCommands()
{
    // Admin commands only when enabled and from admin user
    await ProcessAdminCommand();
}

[IsDebugEnvironment]
[CommandHandler("dump")]
public async Task DumpState()
{
    // Dump internal state for debugging
    await SendStateInformation();
}

A/B Testing

[CommandHandler("start")]
[EnvironmentVariable("AB_TEST_GROUP", "A")]
public async Task HandleStartGroupA()
{
    await Bot.SendTextMessageAsync("Welcome! (Version A)");
}

[CommandHandler("start")]
[EnvironmentVariable("AB_TEST_GROUP", "B")]
public async Task HandleStartGroupB()
{
    await Bot.SendTextMessageAsync("Hello! (Version B)");
}

External Service Integration

[EnvironmentVariable("USE_EXTERNAL_API", "true")]
public async Task UseExternalAPI()
{
    // Use external API when configured
    await CallExternalService();
}

[EnvironmentVariable("USE_EXTERNAL_API", "false")]
public async Task UseLocalProcessing()
{
    // Fallback to local processing
    await ProcessLocally();
}

Setting Environment Variables

In Your Application

// Program.cs or Startup.cs
Environment.SetEnvironmentVariable("ENVIRONMENT", "production");
Environment.SetEnvironmentVariable("FEATURE_AI", "enabled");
Environment.SetEnvironmentVariable("LOG_LEVEL", "info");

In launchSettings.json (Development)

{
  "profiles": {
    "Development": {
      "commandName": "Project",
      "environmentVariables": {
        "ENVIRONMENT": "development",
        "FEATURE_AI": "enabled",
        "LOG_LEVEL": "debug"
      }
    },
    "Production": {
      "commandName": "Project",
      "environmentVariables": {
        "ENVIRONMENT": "production",
        "LOG_LEVEL": "info"
      }
    }
  }
}

In Docker

ENV ENVIRONMENT=production
ENV FEATURE_AI=enabled
ENV LOG_LEVEL=info

In docker-compose.yml

services:
  bot:
    image: mybot:latest
    environment:
      - ENVIRONMENT=production
      - FEATURE_AI=enabled
      - LOG_LEVEL=info

In Shell/Terminal

# Linux/macOS
export ENVIRONMENT=production
export FEATURE_AI=enabled

# Windows (Command Prompt)
set ENVIRONMENT=production
set FEATURE_AI=enabled

# Windows (PowerShell)
$env:ENVIRONMENT="production"
$env:FEATURE_AI="enabled"

Best Practices

  1. Use environment variables for configuration: Prefer environment variables over hardcoded values for flexibility:
// Good
[EnvironmentVariable("FEATURE_ENABLED", "true")]

// Less flexible
[IsDebugEnvironment]  // Only works in debug builds
  1. Document required variables: Keep a list of environment variables your bot uses:
// Required environment variables:
// - ENVIRONMENT: "production", "staging", or "development"
// - FEATURE_AI: "enabled" or "disabled"
// - LOG_LEVEL: "debug", "info", "warning", or "error"
  1. Provide defaults: Handle missing environment variables gracefully:
var logLevel = Environment.GetEnvironmentVariable("LOG_LEVEL") ?? "info";
  1. Use DEBUG/RELEASE for build-time decisions: Use IsDebugEnvironment and IsReleaseEnvironment for features that should be compiled in or out:
[IsDebugEnvironment]
[CommandHandler("test")]
public async Task DebugTest() { }  // Not available in release builds
  1. Combine environment and permission filters: Create secure, environment-aware handlers:
[EnvironmentVariable("ENVIRONMENT", "production")]
[FromUserId(123456789)]  // Only admin in production
public async Task HandleProductionAdmin() { }
  1. Use consistent naming: Establish a naming convention for environment variables:
// Good: Consistent prefixes
FEATURE_AI
FEATURE_PAYMENTS
FEATURE_ANALYTICS

// Less organized
AI_ENABLED
PAYMENTS
ENABLE_ANALYTICS
  1. Validate environment variables at startup: Check critical environment variables when your bot starts:
public static void Main()
{
    var requiredVars = new[] { "BOT_TOKEN", "ENVIRONMENT" };
    
    foreach (var varName in requiredVars)
    {
        if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(varName)))
        {
            throw new Exception($"Required environment variable {varName} is not set");
        }
    }
    
    // Start bot...
}

Build docs developers (and LLMs) love