Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DingTalkBot

A small .NET class library for sending text messages to a DingTalk custom robot group via the signed webhook API.

The library targets both .NET Framework and modern .NET, and is usable from VB.NET and C#. It performs the HMAC-SHA256 request signing internally, posts the message, and returns a simple result structure. It does not write any logs and does not swallow errors: network failures and non-success HTTP responses are surfaced as exceptions so the caller decides how to handle them.


Table of Contents


Features

  • Signed webhook requests (timestamp + HMAC-SHA256 + Base64 + URL encoding)
  • Text messages with optional @all, @userIds, and @mobiles
  • No logging output; the library is silent by design
  • Single shared HttpClient instance to avoid socket exhaustion
  • Multi-targeted: net472, net6.0, net8.0
  • No third-party dependencies beyond System.Text.Json on .NET Framework

Requirements

Target framework System.Net.Http System.Text.Json
.NET Framework 4.7.2 Included in the framework Installed via NuGet
.NET 6 / .NET 8 Built into the runtime Built into the runtime

A DingTalk custom robot requires:

  • An access_token from the robot webhook URL
  • A secret from the robot security settings (signature mode must be enabled)

Installation

NuGet

The library is published as PawLab.DingTalkBot.

Install via the .NET CLI:

dotnet add package PawLab.DingTalkBot

Install via the Package Manager Console in Visual Studio:

Install-Package PawLab.DingTalkBot

Build from source

git clone https://example.com/your-repo/DingTalkBot.git
cd DingTalkBot
dotnet build -c Release

The output DLLs are placed under:

bin/Release/net472/DingTalkBot.dll
bin/Release/net6.0/DingTalkBot.dll
bin/Release/net8.0/DingTalkBot.dll

Reference from another project

<ItemGroup>
  <ProjectReference Include="..\DingTalkBot\DingTalkBot.vbproj" />
</ItemGroup>

Or reference the compiled DLL directly:

<ItemGroup>
  <Reference Include="DingTalkBot">
    <HintPath>lib\DingTalkBot.dll</HintPath>
  </Reference>
</ItemGroup>

If you target .NET Framework, also add:

<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
  <PackageReference Include="System.Text.Json" Version="8.0.5" />
</ItemGroup>

Or


Quick Start

VB.NET

Imports DingTalkBot

Module Program
    Sub Main()
        Dim bot As New DingTalkBot("your_access_token", "your_secret")

        ' 1. Plain message, no mentions
        Dim r1 As DingTalkBot.ResponseResult = bot.Send("Hello from VB.NET")

        ' 2. Mention everyone
        Dim r2 As DingTalkBot.ResponseResult = bot.Send("Heads up, everyone", isAtAll:=True)

        ' 3. Mention specific users and mobile numbers
        Dim atUserIds As String() = {"userid_1", "userid_2"}
        Dim atMobiles As String() = {"13800000000"}
        Dim r3 As DingTalkBot.ResponseResult = bot.Send("Meeting starts now", atUserIds, atMobiles)

        If r1.errCode <> 0 Then
            Console.WriteLine($"Send failed: {r1.errCode} - {r1.errMsg}")
        End If
    End Sub
End Module

C#

using DingTalkBot;

class Program
{
    static void Main()
    {
        var bot = new DingTalkBot("your_access_token", "your_secret");

        // 1. Plain message, no mentions
        DingTalkBot.ResponseResult r1 = bot.Send("Hello from C#");

        // 2. Mention everyone
        DingTalkBot.ResponseResult r2 = bot.Send("Heads up, everyone", isAtAll: true);

        // 3. Mention specific users and mobile numbers
        var atUserIds = new[] { "userid_1", "userid_2" };
        var atMobiles = new[] { "13800000000" };
        DingTalkBot.ResponseResult r3 = bot.Send("Meeting starts now", atUserIds, atMobiles);

        if (r1.errCode != 0)
        {
            Console.WriteLine($"Send failed: {r1.errCode} - {r1.errMsg}");
        }
    }
}

Note: because the class is nested, ResponseResult is addressed as DingTalkBot.ResponseResult from C#. Inside the class itself you can use the short name.


API Reference

Constructor

Public Sub New(accessToken As String, secret As String)
public DingTalkBot(string accessToken, string secret)
Parameter Description
accessToken The robot webhook access token. Must not be null or empty.
secret The signature secret from the robot security settings. Must not be null or empty.

Throws ArgumentNullException if either argument is null or an empty string.

The access token and secret are captured once at construction time. The signed URL is regenerated on every call, so long-lived instances are safe.

Send overloads

Public Function Send(msg As String, Optional isAtAll As Boolean = False) As ResponseResult
Public Function Send(msg As String, Optional atUserID As String() = Nothing,
                     Optional atUserMobile As String() = Nothing) As ResponseResult
public ResponseResult Send(string msg, bool isAtAll = false)
public ResponseResult Send(string msg, string[] atUserID = null, string[] atUserMobile = null)
Parameter Description
msg The plain text message body.
isAtAll When true, the message mentions every member in the group.
atUserID An array of DingTalk user IDs to mention. May be null.
atUserMobile An array of mobile numbers to mention. May be null.

Both overloads produce the same payload shape. Empty arrays are sent as [], matching the behavior of the official Python sample.

Return value: a ResponseResult populated from the DingTalk response body.

ResponseResult

Public Structure ResponseResult
    Public errCode As Integer
    Public errMsg As String
End Structure
Field Description
errCode 0 means success. Any other value is a DingTalk-side error.
errMsg Human readable status, for example ok.

DingTalk returns a body similar to:

{"errcode":0,"errmsg":"ok"}

The fields are public and immutable in practice; treat the structure as a read-only value object.


Exceptions

The library does not catch exceptions internally. Expect the following.

Exception Raised when
ArgumentNullException accessToken or secret is null or empty.
HttpRequestException DNS failure, connection reset, timeout, or a non-2xx HTTP status code.
JsonException The response body is not valid JSON, or the expected fields are missing or of the wrong type.
TaskCanceledException The request is cancelled or times out at the HttpClient level.

Example of defensive calling code:

Try
    Dim result = bot.Send("Hello")
    If result.errCode <> 0 Then
        Console.WriteLine($"DingTalk rejected the message: {result.errMsg}")
    End If
Catch ex As HttpRequestException
    Console.WriteLine($"Network problem: {ex.Message}")
Catch ex As JsonException
    Console.WriteLine($"Unexpected response body: {ex.Message}")
End Try
try
{
    var result = bot.Send("Hello");
    if (result.errCode != 0)
    {
        Console.WriteLine($"DingTalk rejected the message: {result.errMsg}");
    }
}
catch (HttpRequestException ex)
{
    Console.WriteLine($"Network problem: {ex.Message}");
}
catch (JsonException ex)
{
    Console.WriteLine($"Unexpected response body: {ex.Message}");
}

Notes and Caveats

  1. isAtAll is serialized as a JSON boolean. Some older samples send the string "true" instead; the boolean form is what the current DingTalk documentation specifies.

  2. The two Send overloads can be ambiguous when called with a single argument. When calling from PowerShell or from a dynamic language, pass the second argument explicitly so the correct overload is selected:

    $bot.Send($msg, [bool]$false)

    From VB.NET and C# the named-argument form is clearer:

    bot.Send(msg, isAtAll:=False)
    bot.Send(msg, isAtAll: false);
  3. atUserIds support depends on the robot type. For custom webhook robots the atMobiles path is the more reliable way to mention people.

  4. The signing logic lives in DingTalkBot.Utilities.GenerateSignatureUrl. The returned URL already contains access_token, timestamp, and sign as query parameters and is ready to use as-is.

  5. A single static HttpClient is shared across all instances. If you need per-call timeouts or custom handlers, use IHttpClientFactory and inject the client instead.

  6. The library is intentionally synchronous. If you need async, wrap the call in Task.Run or open an issue to request an SendAsync overload.


License

Apache-2.0

About

🤖 A DingTalk Webhook Bot Library. | 一个简易钉钉机器人类库

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages