Universal.Slack.Client
1.0.2
dotnet add package Universal.Slack.Client --version 1.0.2
NuGet\Install-Package Universal.Slack.Client -Version 1.0.2
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Universal.Slack.Client" Version="1.0.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Universal.Slack.Client" Version="1.0.2" />
<PackageReference Include="Universal.Slack.Client" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Universal.Slack.Client --version 1.0.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Universal.Slack.Client, 1.0.2"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Universal.Slack.Client@1.0.2
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Universal.Slack.Client&version=1.0.2
#tool nuget:?package=Universal.Slack.Client&version=1.0.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Universal.Slack.Client
Basic client to interact with Slack's APIs.
Usage
using (SlackClient slackClient = new SlackClient()
{
AccessToken = "<your-bot-token>"
})
{
await slackClient.ConversationsListAsync();
}
API Methods
Authentication
// OAuth 2.0 token exchange
var tokenResponse = await slackClient.OAuthV2AccessAsync(new OAuthV2AccessRequest()
{
ClientId = "your-client-id",
ClientSecret = "your-client-secret",
Code = "authorization-code"
});
Conversations
// List all conversations
var conversations = await slackClient.ConversationsListAsync();
// Get conversation details
var channelInfo = await slackClient.ConversationsInfoAsync("C1234567890");
// Get message history
var messages = await slackClient.ConversationsHistoryAsync("C1234567890", limit: 50);
// Get all messages (handles pagination automatically)
var allMessages = await slackClient.ConversationsHistoryAllAsync("C1234567890");
// Get thread replies
var threadReplies = await slackClient.ConversationsRepliesAsync("C1234567890", "1234567890.123456");
// Get all thread replies
var allReplies = await slackClient.ConversationsRepliesAllAsync("C1234567890", "1234567890.123456");
// Get channel members
var members = await slackClient.ConversationsMembersAsync("C1234567890");
// Get all channel members
var allMembers = await slackClient.ConversationsMembersAllAsync("C1234567890");
Users
// List users
var users = await slackClient.UsersListAsync(limit: 100);
// Get all users (handles pagination automatically)
var allUsers = await slackClient.UsersListAllAsync();
// Get user details
var userInfo = await slackClient.UsersInfoAsync("U1234567890");
Messaging
// Post a simple message
await slackClient.ChatPostMessageAsync(new ChatPostMessageRequest()
{
Channel = "C1234567890",
Text = "Hello, World!"
});
// Post a message with blocks
await slackClient.ChatPostMessageAsync(new ChatPostMessageRequest()
{
Channel = "C1234567890",
Text = "Fallback text",
Blocks = new Block[]
{
new SectionBlock
{
Type = BlockTypes.Section,
Text = new TextObject
{
Type = "mrkdwn",
Text = "*Bold text* and _italic text_"
}
}
}
});
// Reply in a thread
await slackClient.ChatPostMessageAsync(new ChatPostMessageRequest()
{
Channel = "C1234567890",
Text = "This is a threaded reply",
ThreadTimestamp = "1234567890.123456"
});
// Reply with broadcast (shows in thread and main channel)
await slackClient.ChatPostMessageAsync(new ChatPostMessageRequest()
{
Channel = "C1234567890",
Text = "Important update for everyone",
ThreadTimestamp = "1234567890.123456",
ReplyBroadcast = true
});
File Upload
// Get upload URL (Step 1 of 3-step process)
var uploadUrl = await slackClient.FilesGetUploadURLExternalAsync("report.pdf", fileSize);
// Upload file using the new 3-step process (convenience method)
var uploadResponse = await slackClient.FilesUploadAsync(
filename: "report.pdf",
fileContent: pdfBytes,
channelId: "C1234567890",
initialComment: "Here's the monthly report",
title: "Monthly Report"
);
// Upload to a thread
var threadUpload = await slackClient.FilesUploadAsync(
filename: "analysis.txt",
fileContent: textBytes,
channelId: "C1234567890",
threadTimestamp: "1234567890.123456",
initialComment: "Analysis results"
);
// Complete upload manually (Step 3 of 3-step process)
await slackClient.FilesCompleteUploadExternalAsync(
files: new FilesCompleteUploadExternalRequest.File[]
{
new FilesCompleteUploadExternalRequest.File { Id = fileId, Title = "My File" }
},
channelId: "C1234567890"
);
Common Patterns
File Upload for Generated Content
// Bot generates and uploads analysis reports
public async Task ShareAnalysisAsync(string channelId, string threadTs, object analysisData)
{
// Generate report content
var reportContent = GenerateMarkdownReport(analysisData);
var reportBytes = Encoding.UTF8.GetBytes(reportContent);
// Upload as file with context
await slackClient.FilesUploadAsync(
filename: $"analysis-{DateTime.Now:yyyy-MM-dd}.md",
fileContent: reportBytes,
channelId: channelId,
threadTimestamp: threadTs,
initialComment: "Here's the detailed analysis you requested",
title: "Data Analysis Report"
);
}
// Upload generated code snippets
public async Task ShareCodeSolutionAsync(string channelId, string code, string language)
{
var codeBytes = Encoding.UTF8.GetBytes(code);
await slackClient.FilesUploadAsync(
filename: $"solution.{GetFileExtension(language)}",
fileContent: codeBytes,
channelId: channelId,
initialComment: $"Here's the {language} solution:",
altText: $"{language} code solution",
title: "Generated Code Solution"
);
}
Processing Messages with Files
var messages = await slackClient.ConversationsHistoryAsync(channelId, limit: 100);
foreach (var message in messages.Messages)
{
if (message.Files?.Length > 0)
{
foreach (var file in message.Files)
{
Console.WriteLine($"File: {file.Name} ({file.FileType})");
Console.WriteLine($"Size: {file.Size} bytes");
Console.WriteLine($"Shared in: {string.Join(", ", file.Channels ?? new string[0])}");
// Bot could analyze file content based on type
if (IsAnalyzableFileType(file.FileType))
{
await AnalyzeAndRespondToFile(file, message.Channel, message.Timestamp);
}
}
}
}
Thread Conversation Analysis
var messages = await slackClient.ConversationsHistoryAsync(channelId, limit: 50);
foreach (var message in messages.Messages.Where(m => m.ReplyCount > 0))
{
var threadReplies = await slackClient.ConversationsRepliesAllAsync(channelId, message.Timestamp);
Console.WriteLine($"Thread with {threadReplies.Length} total messages:");
foreach (var reply in threadReplies)
{
var user = await slackClient.UsersInfoAsync(reply.User);
Console.WriteLine($" {user.User.Profile.DisplayName}: {reply.Text}");
}
}
User Profile Analysis
var members = await slackClient.ConversationsMembersAllAsync(channelId);
foreach (var memberId in members)
{
var userInfo = await slackClient.UsersInfoAsync(memberId);
var user = userInfo.User;
Console.WriteLine($"User: {user.Profile?.DisplayName ?? user.Name}");
Console.WriteLine($" Status: {user.Profile?.StatusText}");
Console.WriteLine($" Timezone: {user.TimezoneLabel}");
Console.WriteLine($" Is Bot: {user.IsBot}");
}
Pagination
Many methods support automatic pagination through *AllAsync
variants:
// Manual pagination
var response = await slackClient.UsersListAsync(limit: 200);
string cursor = response.ResponseMetadata?.NextCursor;
while (!string.IsNullOrEmpty(cursor))
{
var nextPage = await slackClient.UsersListAsync(cursor: cursor, limit: 200);
// Process nextPage.Members
cursor = nextPage.ResponseMetadata?.NextCursor;
}
// Automatic pagination
var allUsers = await slackClient.UsersListAllAsync(); // Handles pagination internally
Error Handling
try
{
await slackClient.ChatPostMessageAsync(request);
}
catch (SlackException ex)
{
Console.WriteLine($"Slack API Error: {ex.Error}");
// Handle specific errors like "channel_not_found", "not_in_channel", etc.
}
catch (SlackRateLimitException ex)
{
Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter} seconds");
await Task.Delay(TimeSpan.FromSeconds(ex.RetryAfter ?? 60));
// Retry the request
}
Response Models
All API responses include rich object models:
- Message: Full message data with attachments, reactions, thread info, files
- Channel: Complete channel information with topic, purpose, member count
- User: Detailed user profiles with status, timezone, permissions, avatar images
- File: Complete file metadata with download URLs, thumbnails, sharing info, dimensions
- FilesCompleteUploadExternalResponse: Response from file upload with uploaded file details
- ConversationsHistoryResponse: Message history with pagination metadata
- Block: Block Kit support for rich message formatting (simplified implementation)
File Upload Process
The modern Slack file upload uses a 3-step process (required for apps created after May 2024):
- Get Upload URL:
FilesGetUploadURLExternalAsync()
- Returns upload URL and file ID - Upload File: POST file data to the returned URL (handled internally by convenience methods)
- Complete Upload:
FilesCompleteUploadExternalAsync()
- Finalize and optionally share to channels
The FilesUploadAsync()
convenience method handles all three steps automatically.
Requirements
- Scopes needed:
files:write
,chat:write
,channels:read
,users:read
- .NET compatibility: Targets frameworks supporting HttpClient and async/await
- Slack app: Must be created with proper OAuth scopes and bot token
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Universal.Common.Net.Http (>= 5.1.0)
- Universal.Slack (>= 1.2.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Updated dependencies.