netirc - NetIRC 1.1.2
Simple open-source Portable IRC Client Library written in C# targeting .NETStandard 2.0 and .NET Framework 4.6.1
PM> Install-Package NetIRC -Version 1.1.2 -Source https://www.myget.org/F/netirc/api/v3/index.json
> nuget.exe install NetIRC -Version 1.1.2 -Source https://www.myget.org/F/netirc/api/v3/index.json
> dotnet add package NetIRC --version 1.1.2 --source https://www.myget.org/F/netirc/api/v3/index.json
> choco install NetIRC --version 1.1.2 --source https://www.myget.org/F/netirc/api/v2
Import-Module PowerShellGet
Register-PSRepository -Name "netirc" -SourceLocation "https://www.myget.org/F/netirc/api/v2"
Install-Module -Name "NetIRC" -RequiredVersion "1.1.2" -Repository "netirc"
Copy to clipboard
Browse the sources in this package using Visual Studio or WinDbg by configuring the following symbol server URL: https://www.myget.org/F/netirc/api/v2/symbolpackage/
NetIRC
A simple, portable IRC client library for C# targeting .NET Standard 2.0 and .NET Framework 4.6.1.
NetIRC gives you a clean async-first API for building IRC bots, desktop clients, and any other application that needs to talk to an IRC server.
Features
- Fully async/await API
- TCP and WebSocket connections out of the box
- Observable collections for channels, queries, users, and server messages — ready for WPF / MAUI data binding
- Built-in IRC command messages (
JOIN,PART,PRIVMSG,NICK,KICK,QUIT,TOPIC, …) - CTCP support (
VERSION,TIME,PING,CLIENTINFO,ACTION) - Extensible custom message handler system
- Fluent builder for client configuration
Installing
Via the NuGet Package Manager Console:
Install-Package NetIRC
Via the .NET CLI:
dotnet add package NetIRC
Pre-release builds are available on MyGet.
Quick Start
using NetIRC;
using NetIRC.Messages;
// Build the client
using var client = Client.CreateBuilder()
.WithNick("MyBot", "My IRC Bot")
.WithServer("irc.libera.chat", 6667)
.Build();
// Called once the server confirms registration (001 Welcome)
client.RegistrationCompleted += async (sender, e) =>
{
if (sender is Client c)
await c.SendAsync(new JoinMessage("#mychannel"));
};
// Called for every channel message
client.Channels.CollectionChanged += (s, e) =>
{
foreach (Channel ch in e.NewItems ?? Array.Empty<object>())
{
ch.Messages.CollectionChanged += (ms, me) =>
{
foreach (ChannelMessage msg in me.NewItems ?? Array.Empty<object>())
Console.WriteLine($"[{ch.Name}] <{msg.User.Nick}> {msg.Text}");
};
}
};
await client.ConnectAsync();
await Task.Delay(Timeout.Infinite); // keep alive
A fully commented, runnable example is in samples/NetIRC.ConsoleCli.
Core Concepts
Client
Client is the entry point. Create one via the fluent builder:
var client = Client.CreateBuilder()
.WithNick("MyNick", "My Real Name") // sets the IRC nick and USER real name
.WithServer("irc.libera.chat", 6667) // host and port
.WithPassword("serverpassword") // optional: server password (PASS command)
.Build();
Or directly via constructor if you need fine-grained control over the connection:
var user = new User("MyNick", "My Real Name");
var connection = new TcpClientConnection("irc.libera.chat", 6667);
using var client = new Client(user, connection);
User
Represents an IRC user. Implements INotifyPropertyChanged so the Nick property can be bound directly in WPF/MAUI.
Console.WriteLine(client.User.Nick);
Channel & Query
| Type | Description |
|---|---|
Channel |
An IRC channel the client has joined. Has an observable Users and Messages collection. |
Query |
A private conversation with another user. Has an observable Messages collection. |
Both are created automatically by the library when a JOIN or PRIVMSG (private) is received.
Observable Collections
All collections implement ObservableCollection<T> so you can subscribe to CollectionChanged:
| Property | Type | Contains |
|---|---|---|
client.Channels |
ChannelCollection |
Channels you have joined |
client.Queries |
QueryCollection |
Active private conversations |
client.Peers |
UserCollection |
All known users |
client.ServerMessages |
ServerMessageCollection |
Server status / motd lines |
Events
| Event | Signature | Fired when |
|---|---|---|
RawDataReceived |
(Client client, string rawData) |
Any raw line is received from the server |
IRCMessageParsed |
(Client client, ParsedIRCMessage msg) |
A raw line has been parsed into a structured message |
RegistrationCompleted |
(object sender, EventArgs e) |
Server sends 001 (Welcome) — safe to join channels |
CtcpReceived |
(Client client, CtcpEventArgs ctcp) |
A CTCP request or reply is received |
client.RawDataReceived += (c, raw) => Console.WriteLine(raw);
client.IRCMessageParsed += (c, msg) =>
{
if (msg.IRCCommand == IRCCommand.TOPIC)
Console.WriteLine($"Topic on {msg.Parameters[0]}: {msg.Trailing}");
};
Sending Messages
Use SendAsync with any IClientMessage implementation:
await client.SendAsync(new JoinMessage("#channel"));
await client.SendAsync(new PartMessage("#channel", "Goodbye!"));
await client.SendAsync(new PrivMsgMessage("#channel", "Hello, world!"));
await client.SendAsync(new NickMessage("NewNick"));
await client.SendAsync(new TopicMessage("#channel", "New topic here"));
await client.SendAsync(new KickMessage("#channel", "SomeUser", "Reason"));
await client.SendAsync(new QuitMessage("Leaving"));
For raw protocol strings:
await client.SendRaw("MODE #channel +m\r\n");
Built-in Message Types
| Class | IRC Command | Direction |
|---|---|---|
JoinMessage |
JOIN |
Client → Server |
PartMessage |
PART |
Client → Server |
PrivMsgMessage |
PRIVMSG |
Both |
NickMessage |
NICK |
Both |
TopicMessage |
TOPIC |
Both |
KickMessage |
KICK |
Both |
QuitMessage |
QUIT |
Both |
NoticeMessage |
NOTICE |
Server → Client |
ModeMessage |
MODE |
Server → Client |
PingMessage / PongMessage |
PING / PONG |
Both (auto-handled) |
PassMessage |
PASS |
Client → Server |
UserMessage |
USER |
Client → Server |
Custom Message Handlers
Implement a custom handler by deriving from CustomMessageHandler<TMessage> and decorating it with [Command]:
using NetIRC.Messages;
[Command(IRCCommand.PRIVMSG)]
public class PrivMsgHandler : CustomMessageHandler<PrivMsgMessage>
{
public override Task HandleAsync(Client client, PrivMsgMessage message)
{
Console.WriteLine($"<{message.From}> {message.Message}");
return Task.CompletedTask;
}
}
Register it on the client:
// Register a specific handler type
client.RegisterCustomMessageHandler<PrivMsgHandler>();
// Or auto-discover all handlers in an assembly
client.RegisterCustomMessageHandlers(typeof(Program).Assembly);
CTCP Support
The following CTCP commands are handled automatically:
| Command | Behaviour |
|---|---|
VERSION |
Replies with NetIRC |
TIME |
Replies with the current local time |
PING |
Echoes the timestamp back |
CLIENTINFO |
Lists supported CTCP commands |
ACTION |
Raises CtcpReceived |
Subscribe to CtcpReceived to handle additional or custom CTCP messages:
client.CtcpReceived += (c, ctcp) =>
{
Console.WriteLine($"CTCP {ctcp.Command} from {ctcp.Nick}");
};
Connection Types
TcpClientConnection (default)
Standard IRC over plain TCP. Used by the builder by default.
var connection = new TcpClientConnection("irc.libera.chat", 6667);
WebSocketClientConnection
For IRC servers that expose a WebSocket endpoint (e.g. KiwiIRC gateway):
var connection = new WebSocketClientConnection(new Uri("wss://irc.example.com/socket"));
using var client = new Client(user, connection);
WPF / UI Thread Dispatcher
If you are building a WPF or WinForms application, observable collection changes must happen on the UI thread. Pass the dispatcher before connecting:
// WPF
client.SetDispatcherInvoker(action => Application.Current.Dispatcher.Invoke(action));
Projects Built with NetIRC
- NetIRC.Desktop — Simple WPF Desktop IRC Client
Feel free to open a pull request to add your project to this list.
Contributing
Contributions are welcome! Open an issue to discuss a bug or feature, then submit a pull request.
- Fork the repo and create a branch from
master - Make your changes and add / update tests under
tests/NetIRC.Tests - Ensure
dotnet testpasses - Open a pull request with a clear description
1.1.2
Fix ci.yml Fix build Update tests project to .NET 10 Update GH actions Upgrade project: fix parser/connection bugs and rewrite documentation (#11) Make use of non-generic TaskCompletionSource Use builder in Client connection tests Use builder and enable stopping the app with Ctrl+C Create a simple client builder Simpler implementation when slicing big messages Implement recommended disposable pattern
1.1.2-preview.2
Split PrivMsg UTF-8 messages every ~400 bytes Update packages and .NET version Use .NET 6 in workflows Update sample Console client to .NET 6 Use latest C# version
1.1.2-preview.1
Split PrivMsg if the length is close to the limit Move \r\n tot a constant VS 2022 Nick validation Update CtcpCommands.cs
1.1.1
Make sure reconnecting doesn't throw an exception Create new TcpClient instance when connecting Use random ports in TcpClientConnection tests Add IRC clients built with NetIRC
1.1.0-preview.3
Trim trailing
1.1.0-preview.2
Use PackageReleaseNotes instead of PackageDescription
1.1.0-preview.1
Update release.yml Add release notes to NuGet package Setting dispatcher invoker action to null should throw Test IComparer implementation in ChannelUserComparer Fixes sending PrivMsg with no spaces and starting with colon Set DispatcherInvoker in constructor Added channel user comparer for sorting Enable setting a dispatcher invoker method Refactor ServerMessage tests and add Timestamp test Rename Date to Timestamp in messages Handle some numeric replies and add to server messages (tag: v1.1.0-alpha) Fix version Renamed events (BREAKING CHANGE) Add basic CTCP handling Fix test for IRCMessage not implementing IClientMessage Test validation of custom message handler registration Fix package description Small refactoring and added WebSocketClientConnection Moved collections to Collections folder Don't build on windows, it's too slow Hey, that's some more tests... Some more tests Remove unnecessary null coalescing operator Use private setters in IRCMessage properties Make Comment immutable Added more tests and refactored a few others Micro performance improvement Add CreatedDate to IRCMessage Add property to identity a Channel Notice Add ModeMessage for MODE command Add ability to send array of channels to PartMessage Remove unused messages for now Add ability to send array of channels or dictionary to JoinMessage Add Kick message and handler Small refactoring Channel GetUser Add channel user with no status Regular dispose Disable test parallelization for now Stop TCP listeners Sample: move classes to their own files Small refactor and tests Add Client connection tests Remove unnecessary lines from csproj
1.0.0
Refactoring pre-1.0 (#9) Add coverage status badge Fix token Set coverallsapp version Add code coverage Fix push condition Add os matrix Fix launching Console client from VS Code Ignore CI build for changes in .vscode folder Update README.md Added GitHub Workflows. Some cleanup (#8) Version 0.1.2 Update dotnet-steps.yml Update NetIRC.ConsoleCli.csproj Use .NET Core 3.1.x Update Azure Pipeline images Update test project target framework and packages Tests are fixed Update a new dispose pattern Use SafeFireAndForget when running data receiver Add ConfigureAwait(false) since we don't care what thread we return to Add null/empty check (#5) Generate version (#2) Set up CI with Azure Pipelines (#1) Update Codecov badge No colors Update README.md Update Build.ps1 Allow sending PASS to the server Update to .NET Core 2.1 Updating Github username Even more tests :) More tests Wait for DataReceived to be trigger before disposing server connection Refactoring TcpClientConnection tests Updated timeout for disconnect test. Appveyor is driving me crazy!! :P Added more tests Not using INotifyPropertyChanged in Query yet Handle nick change Updated the disconnect test to go through the entire pipeline Added test for user leaving channel and refactored client tests Added missing tests for the EventHub - RegistrationCompleted event - Nick event Use ManualResetEvent when only a flag is needed Fix deployment to MyGet Added NuGet badge
0.1.1
Version 0.1.1 Trying to achieve 100% coverage in TcpClientConnection Hmm.. Am I talking to the git repo? \o/ Yeahh, let's see! Apparently same tests take too long to execute in Appveyor Added on more TcpClientConnection test and refactored a couple of others - Using ManualResetEvent to make sure the event is triggered and make sure we don't block for more time than it's necessary Refactored RunDataReceiver Refactored some tests and added on more for TcpClientConnection class Enable executing CodeCoverage.ps1 locally Ignore OpenCover and coverage xml Ignore OpenCover Changed license to MIT Add .vscode configs Disable gcov Converting CodeCoverage.cmd to a PowerShell script Update README.md Started writing some test to the TcpClientConnection class Restore code coverage Updated README.md Some changes in the CI/CD pipeline Update README.md Fixing code coverage Get code coverage results for NetIRC.csproj Fix typo Code Coverage FTW! Added more documentation in classes, methods, events and properties Renamed Users to Peers in the Client class Update appveyor.yml Update README Update folder structure Update project information Started writing some documentation Cleaning up some tests xUnit: Show method name only in test runners Change build configuration in appveyor Added appveyor.yml Fix version Added script to modify the version of the package Update project description Removed appveyor.yml until I configure it properly Updated to .NET Core 1.1 Trying to fix CI Added appveyor.yml Added Query and QueryCollection classes plus some cleanups Added Channel OnMessageReceived event PART and QUIT messages Modeling users and channels. Parsing and processing RPL_NAMREPLY messages JOIN Message Connection Connected and Disconnected events Separating server and client messages Removed unused code Created messages and events to registration numeric replies Treating the trailing as a parameter, cause that's what it is :) It just happens to be the last one NOTICE message Minor changes and cleanups USER message NICK message implementation Refactoring a couple of tests Created ServerMessage class that represents both server and client messages and can trigger events of the EventHub when the message is received from the server. An IRCMessage alone is just ment to be client messages, for example, the PONG message. Sending messages in a more object oriented way :) PrivMsg message, Ping and Pong commands Passing the client as the sender in IRC message event handlers Created an Event Hub to provide events for messages and commands Some more refactorings Update README.md More simplification Simplifying the TcpClientConnection class Updated README.md Converted it into a Portable library targeting .NETStandard 1.3 Using C# 6 getter-only auto-properties Temp icon Created Base IRC EventArgs Updated console client using the new OnPrivMsgReceived event Created event OnPrivMsgReceived Using IRCCommand Enum instead of comparing string Parsing numeric reply Enum Parsing IRC command Enum Bot checks only direct messages Implemented a very simple IRC Bot to execute commands received Parsing IRC prefix Nice IRCMessage ToString override Flush after writing to the stream Simplified irc message parsing Created event OnIRCMessageReceived Parsing more complete data with trailing Parsing data with two parameters Parsing a command with single parameter Started the raw data parser Added RFC and other documentation Fixed exception after disposing the TCP socket Added basic console client functionality Send NICK and USER when connected Responding PING messages OnRawDataReceived event and unit tests Added Moq Nuget package Added tests project Base client and TCP connection Initial commit
- .NETFramework 4.6.1: 4.6.1.0
- .NETStandard 2.0: 2.0.0.0
OwnersFredi Machado |
AuthorsFredi Machado |
Project URLhttps://github.com/fredimachado/NetIRC |
LicenseMIT |
Tagsirc |
Info4199 total downloads |
| 19 downloads for version 1.1.2 |
| Download (57.62 KB) |
| Download symbols (31.14 KB) |
| Found on the current feed only |
Package history
| Version | Size | Last updated | Downloads | Mirrored? | |||
|---|---|---|---|---|---|---|---|
|
|
1.1.3-preview.0.7 | 55.43 KB | Fri, 03 Apr 2026 02:45:36 GMT | 15 |
|
||
|
|
1.1.3-preview.0.6 | 55.38 KB | Fri, 03 Apr 2026 02:07:23 GMT | 14 |
|
||
|
|
1.1.2 | 57.62 KB | Thu, 02 Apr 2026 11:26:27 GMT | 19 |
|
||
|
|
1.1.2-preview.2.11 | 54.58 KB | Thu, 02 Apr 2026 11:05:03 GMT | 13 |
|
||
|
|
1.1.2-preview.2.10 | 54.57 KB | Thu, 02 Apr 2026 10:57:28 GMT | 7 |
|
||
|
|
1.1.2-preview.2.6 | 53.04 KB | Mon, 07 Mar 2022 11:16:46 GMT | 96 |
|
||
|
|
1.1.2-preview.2.5 | 53.05 KB | Thu, 17 Feb 2022 13:17:12 GMT | 86 |
|
||
|
|
1.1.2-preview.2.4 | 53.04 KB | Thu, 17 Feb 2022 13:04:42 GMT | 80 |
|
||
|
|
1.1.2-preview.2 | 55.17 KB | Thu, 10 Feb 2022 14:59:36 GMT | 90 |
|
||
|
|
1.1.2-preview.1.5 | 52.21 KB | Thu, 10 Feb 2022 14:59:06 GMT | 82 |
|
||
|
|
1.1.2-preview.1.4 | 51.88 KB | Tue, 08 Feb 2022 13:57:06 GMT | 98 |
|
||
|
|
1.1.2-preview.1.1 | 51.88 KB | Tue, 08 Feb 2022 12:17:38 GMT | 84 |
|
||
|
|
1.1.2-preview.1 | 54.82 KB | Tue, 08 Feb 2022 11:21:22 GMT | 86 |
|
||
|
|
1.1.2-preview.0.5 | 51.94 KB | Tue, 08 Feb 2022 11:18:30 GMT | 98 |
|
||
|
|
1.1.1 | 52.4 KB | Sat, 05 Feb 2022 05:03:47 GMT | 93 |
|
||
|
|
1.1.0 | 46.38 KB | Mon, 29 Mar 2021 14:36:33 GMT | 96 |
|
||
|
|
1.1.0-preview.3.4 | 49.64 KB | Sat, 05 Feb 2022 04:51:43 GMT | 88 |
|
||
|
|
1.1.0-preview.3 | 52.36 KB | Sun, 04 Apr 2021 15:23:24 GMT | 85 |
|
||
|
|
1.1.0-preview.2 | 52.34 KB | Sun, 04 Apr 2021 14:28:57 GMT | 87 |
|
||
|
|
1.1.0-preview.1 | 54.97 KB | Sun, 04 Apr 2021 14:22:26 GMT | 97 |
|
||
|
|
1.1.0-alpha.10 | 49.49 KB | Sun, 04 Apr 2021 14:15:13 GMT | 86 |
|
||
|
|
1.1.0-alpha.9 | 49.53 KB | Sun, 04 Apr 2021 13:37:21 GMT | 97 |
|
||
|
|
1.1.0-alpha.8 | 49.55 KB | Sun, 04 Apr 2021 13:29:17 GMT | 107 |
|
||
|
|
1.1.0-alpha.6 | 49.52 KB | Sun, 04 Apr 2021 08:01:36 GMT | 86 |
|
||
|
|
1.1.0-alpha.3 | 47.29 KB | Tue, 30 Mar 2021 14:12:12 GMT | 103 |
|
||
|
|
1.1.0-alpha.1 | 47.27 KB | Tue, 30 Mar 2021 13:00:18 GMT | 98 |
|
||
|
|
1.1.0-alpha | 46.42 KB | Mon, 29 Mar 2021 14:38:41 GMT | 90 |
|
||
|
|
1.0.1-alpha.0.32 | 46.42 KB | Mon, 29 Mar 2021 14:24:10 GMT | 100 |
|
||
|
|
1.0.1-alpha.0.30 | 44.08 KB | Fri, 26 Mar 2021 13:23:00 GMT | 88 |
|
||
|
|
1.0.1-alpha.0.29 | 44.08 KB | Fri, 26 Mar 2021 13:14:28 GMT | 97 |
|
||
|
|
1.0.1-alpha.0.28 | 44.07 KB | Fri, 26 Mar 2021 12:45:04 GMT | 92 |
|
||
|
|
1.0.1-alpha.0.25 | 41.14 KB | Thu, 25 Mar 2021 11:57:13 GMT | 87 |
|
||
|
|
1.0.1-alpha.0.23 | 41.15 KB | Thu, 25 Mar 2021 11:47:38 GMT | 98 |
|
||
|
|
1.0.1-alpha.0.22 | 41.15 KB | Thu, 25 Mar 2021 11:24:37 GMT | 82 |
|
||
|
|
1.0.1-alpha.0.21 | 41.18 KB | Thu, 25 Mar 2021 09:03:39 GMT | 93 |
|
||
|
|
1.0.1-alpha.0.19 | 40.89 KB | Thu, 25 Mar 2021 08:32:59 GMT | 98 |
|
||
|
|
1.0.1-alpha.0.6 | 40.36 KB | Wed, 24 Mar 2021 14:31:08 GMT | 91 |
|
||
|
|
1.0.0 | 40.54 KB | Wed, 24 Mar 2021 11:04:56 GMT | 99 |
|
||
|
|
1.0.0-alpha.1.2 | 40.59 KB | Wed, 24 Mar 2021 10:53:19 GMT | 99 |
|
||
|
|
1.0.0-alpha.1 | 40.59 KB | Wed, 24 Mar 2021 10:47:03 GMT | 81 |
|
||
|
|
0.1.2 | 26.87 KB | Sun, 21 Mar 2021 09:12:24 GMT | 84 |
|
||
|
|
0.1.2-alpha.0.54 | 40.62 KB | Wed, 24 Mar 2021 10:41:15 GMT | 94 |
|
||
|
|
0.1.2-alpha.0.45 | 40.6 KB | Wed, 24 Mar 2021 11:02:06 GMT | 93 |
|
||
|
|
0.1.2-alpha.0.43 | 36.69 KB | Sun, 21 Mar 2021 14:13:58 GMT | 95 |
|
||
|
|
0.1.2-alpha.0.40 | 36.68 KB | Sun, 21 Mar 2021 13:49:39 GMT | 87 |
|
||
|
|
0.1.2-alpha.0.39 | 36.69 KB | Sun, 21 Mar 2021 13:40:16 GMT | 99 |
|
||
|
|
0.1.2-alpha.0.38 | 36.69 KB | Sun, 21 Mar 2021 13:10:25 GMT | 93 |
|
||
|
|
0.1.2-alpha.0.35 | 36.7 KB | Sun, 21 Mar 2021 12:56:49 GMT | 82 |
|
||
|
|
0.1.1 | 18.63 KB | Fri, 01 Feb 2019 11:27:56 GMT | 103 |
|
||
|
|
0.1.1-20-PR-3 | 18.87 KB | Fri, 01 Feb 2019 11:30:52 GMT | 83 |
|