Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dispatch_failled, can't manage to use commands #179

Closed
Dabendorf opened this issue Nov 6, 2023 · 11 comments
Closed

Dispatch_failled, can't manage to use commands #179

Dabendorf opened this issue Nov 6, 2023 · 11 comments

Comments

@Dabendorf
Copy link

I might not be the first asking this, but I am just entirely failing to use slack commands, while the rest of this amazing framework works.

I set up a slack command /echo routing to https://mywebsite.net/Slack/echo/slack/command

The code is the following:

[HttpPost]
        [Route("[Controller]/echo/slack/command")]
        [Produces("application/json")]
        public async Task<SlashCommandResponse> Handle(SlashCommand command) {
            Console.WriteLine($"{command.UserName} used the /echo slash command in the {command.ChannelName} channel");
        
            return new SlashCommandResponse {
                Message = new Message
                {
                    Text = command.Text
                }
            };
        }

I literally tried everything. Changing the route, changing the body, having other arguments, literally everything I do gets me to "/echo failed with the error dispatch_failed".
I used this as manual: https://github.com/soxtoby/SlackNet/tree/master/Examples/SlackNetDemo

Anything obvious I did wrong here? I tested the URL, it is in fact existing

@Dabendorf
Copy link
Author

Edit:
I also tried it with socket mode instead:

using SlackNet.Interaction;
using SlackNet.WebApi;

namespace SlackAPI.Controllers; 

class SlashCommands : ISlashCommandHandler {
	public const string SlashCommand = "/echo";
    
	public async Task<SlashCommandResponse> Handle(SlashCommand command) {
		Console.WriteLine($"{command.UserName} used the {SlashCommand} slash command in the {command.ChannelName} channel");
        
		return new SlashCommandResponse {
			Message = new Message
			{
				Text = command.Text
			}
		};
	}
}
builder.Services.AddSlackNet(c => c
		.UseApiToken(slackConfig.SlackAccessToken)
		.UseAppLevelToken(
			slackConfig.AppLevelToken)
		.RegisterEventHandler<MessageEvent, PingHandler>()
	.RegisterSlashCommandHandler<SlashCommands>(SlashCommands.SlashCommand));

But same error

@soxtoby
Copy link
Owner

soxtoby commented Nov 8, 2023

Thanks for the question, @Dabendorf. The best bet here is to let SlackNet handle the slash command request for you, rather than setting up your own route. SlackNet sets up its own endpoints, so you can tell Slack to send all slash command requests to /slack/command (without the preceding /Slack/echo that you've got in your first example) and register a slash command handler like you have in your socket mode example.

If you go down the socket mode route, then make sure you enable socket mode on your Slack app, which will remove the need to specify any URLs for handling slash commands etc.

Hope that helps.

@Dabendorf
Copy link
Author

Hi,
Thank you for your answer. Yeah I trashed the original routing functionality and just run your version with sockets.
I am now not getting any errors any longer, but nothing happens.
Maybe I just misunderstand the concept.

My class looks like this:

public class SlashCommands : ISlashCommandHandler {
	public const string SlashCommand = "/echo";
	private readonly ISlackApiClient _slack;
	private readonly IConfiguration _configuration;


	public SlashCommands(ISlackApiClient slack, IConfiguration configuration) {
		_slack = slack;
		_configuration = configuration;
	}

	public async Task<SlashCommandResponse> Handle(SlashCommand command) {
		Console.WriteLine("TEST TEST");
		Console.WriteLine($"{command.UserName} used the {SlashCommand} slash command in the {command.ChannelName} channel");
		await _slack.Chat.PostMessage(new Message() { Text = "Test Test Hello", Channel = _configuration.GetValue<string>("Slack:ChannelToSend")}, null);
		Console.WriteLine(command.UserName);
		
		return new SlashCommandResponse {
			Message = new Message {
				Text = command.Text
			}
		};
	}
}

Its not the final code, its just for testing purpose. I tried to do anything, sending /echo, /echo with text, any other command. It just doesn't happen anything. Also the printing does not happen and in debugging, I never get into the Handle method. So I think something is wrong there I guess.

My Program.cs looks like that:

Console.WriteLine("Configuring...");

var settings = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddUserSecrets<Program>()
    .Build();

var serviceCollection = new ServiceCollection();
serviceCollection.AddSlackNet(c => c
    // Configure the tokens used to authenticate with Slack
    .UseApiToken("removed") // This gets used by the API client
    .UseAppLevelToken("removed") // This gets used by the socket mode client

    // Echo demo - a slash command for telling you what you already know
    .RegisterSlashCommandHandler<SlashCommands>(SlashCommands.SlashCommand)

);

var client = new SlackServiceBuilder()
    .UseAppLevelToken("removed")
    .GetSocketModeClient();
await client.Connect();

Console.WriteLine("Connected. Press any key to exit...");
await Task.Run(Console.ReadKey);

I tested like literally every configuration (except the one who will work, haha).
Do you see anything obvious what is weird here?

@soxtoby
Copy link
Owner

soxtoby commented Nov 9, 2023

I think the problem here is that you've configured SlackNet with a ServiceCollection, but then resolved the socket mode client from a separate SlackServiceBuilder, so the client connects, but slash commands won't go anywhere because they were configured somewhere else.

I'd suggest resolving the socket mode client from the ServiceProvider like this:

var serviceProvider = serviceCollection.BuildServiceProvider();
var client = serviceProvider.SlackServices().GetSocketModeClient();

That way the socket mode client will get the configuration from the ServiceCollection.

@Dabendorf
Copy link
Author

Hey,
Thanks for your answer. I am not sure how to resolve that. I tried these two lines before, since they are also part of the manual, but I get a warning in line one and an error in line 2.
It marks SlackServices() red and says Cannot resolve symbol.
The warning in the first one is that BuildServiceProvider generates an additional copy of a singleton.
I am not sure why it cannot find any SlackServices.
Maybe its just missing an import, but I guess I used all you used and my IDE wont give me any recommendations

@soxtoby
Copy link
Owner

soxtoby commented Nov 9, 2023

Hmm odd. SlackServices() is in the same namespace as AddSlackNet(): SlackNet.Extensions.DependencyInjection. Make sure you're calling it on serviceProvider, not serviceCollection. Alternatively you could resolve the service directly with:

var client = serviceProvider.GetRequiredService<ISlackSocketModeClient>();

As for the "additional copy of singleton services" warning, it looks like that warning shows up when you use BuildServiceProvider() in an ASP.NET project, since they're expecting you to use an app builder instead of creating the ServiceProvider directly.

@soxtoby soxtoby closed this as completed Nov 9, 2023
@soxtoby soxtoby reopened this Nov 9, 2023
@soxtoby
Copy link
Owner

soxtoby commented Nov 9, 2023

Oops finger slipped. If you're not going to use ASP.NET, then change the top of your project file from:

<Project Sdk="Microsoft.NET.Sdk.Web">

to

<Project Sdk="Microsoft.NET.Sdk">

and the warning on BuildServiceProvider should disappear.

@Dabendorf
Copy link
Author

Thank you very much for you answering here, that helps a lot!
I am not sure if I maybe debug my problem wrong, but I don't know. The code is know free for errors in the IDE, but still, nothing is running.

using SlackAPI.Handlers;
using SlackNet;

using SlackNet.Extensions.DependencyInjection;

Console.WriteLine("Configuring...");

var settings = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddUserSecrets<Program>()
    .Build();

var serviceCollection = new ServiceCollection();
serviceCollection.AddSlackNet(c => c
    // Configure the tokens used to authenticate with Slack
    .UseApiToken("removed") // This gets used by the API client
    .UseAppLevelToken("removed") // This gets used by the socket mode client

    // Echo demo - a slash command for telling you what you already know
    .RegisterSlashCommandHandler<SlashCommands>(SlashCommands.SlashCommand)

);

var serviceProvider = serviceCollection.BuildServiceProvider();
var client = serviceProvider.GetRequiredService<ISlackSocketModeClient>();

await client.Connect();

Console.WriteLine("Connected. Press any key to exit...");
await Task.Run(Console.ReadKey);

When I use it locally, I do not have any output whatsover. The bot just don't react to anything. If I push it into production and run it there, then I get the old dispatch failed messages for literally every command I defined.

I personally always wondered how the SlashCommands class actually knows which command I use? Is the handler for all commands? Maybe that is my problem.

using SlackNet;
using SlackNet.Interaction;
using SlackNet.WebApi;

namespace SlackAPI.Handlers; 

public class SlashCommands : ISlashCommandHandler {
	public const string SlashCommand = "/echo";
	private readonly ISlackApiClient _slack;
	private readonly IConfiguration _configuration;


	public SlashCommands(ISlackApiClient slack, IConfiguration configuration) {
		_slack = slack;
		_configuration = configuration;
	}

	public async Task<SlashCommandResponse> Handle(SlashCommand command) {
		Console.WriteLine("TEST TEST");
		Console.WriteLine($"{command.UserName} used the {SlashCommand} slash command in the {command.ChannelName} channel");
		await _slack.Chat.PostMessage(new Message() { Text = "Test Test Hello", Channel = _configuration.GetValue<string>("Slack:ChannelToSend")}, null);
		Console.WriteLine(command.UserName);
		
		return new SlashCommandResponse {
			Message = new Message {
				Text = command.Text
			}
		};
	}
}

But I don't know. Its just weird that I cannot debug it properly

@Dabendorf
Copy link
Author

Interesting fact: your PingHandler demo works perfectly in my programme, its just the slash commands failing

@soxtoby
Copy link
Owner

soxtoby commented Nov 12, 2023

RegisterSlashCommandHandler takes in the command that the handler is mapped to, so the handler will end up handling every command you register it for (which in this case should just be /echo).

Running your code, I got an error constructing SlashCommands because there was no IConfiguration registered with the service provider. It was probably registered automatically when you were using ASP.NET, but now you'll need to register it manually with:

serviceCollection.AddSingleton<IConfiguration>(settings);

(make sure to include the generic argument, because settings will be IConfigurationRoot, not IConfiguration specifically)

Only other things I can think of would be to double-check that the slash command you've set up in your Slack app exactly matches what's being registered with SlackNet, and that it's the only app you have with that slash command.

Hope that helps.

@Dabendorf
Copy link
Author

Hey
Thank you for all your help. I have over the weekend just refactored the entire code and now use your asp.net example code instead. I have no idea what was wrong with my old code, but the new version works nice for me :) Thanks for all the help and the great project

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants