Sending DingTalk Messages with .NET Core Applications

Implementing DingTalk Webhook Integration

This implementation demonstrates how to send notifications to DingTalk using .NET Core console applications. The solution supports both text and markdown message formats with flexible configuration options.

Required Dependencies

The project requires the following NuGet packages:

<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />

Configuration Parameter Handling

The application retrieves configuration from both environment variables and command-line arguments:

private static readonly string[] RequiredParams = 
{
    "WEBHOOK",
    "AT_MOBILES", 
    "IS_AT_ALL",
    "MESSAGE",
    "MSG_TYPE"
};

private static void Main(string[] args)
{
    var configuration = new ConfigurationBuilder()
        .AddCommandLine(args)
        .AddEnvironmentVariables()
        .Build();

    // Validate required parameters
    foreach (var param in RequiredParams)
    {
        var value = configuration[param];
        if (string.IsNullOrWhiteSpace(value) && 
            param != "AT_MOBILES" && param != "IS_AT_ALL")
        {
            Console.WriteLine($"{param} is required!");
            return;
        }
    }

    if (string.IsNullOrWhiteSpace(configuration["AT_MOBILES"]) && 
        string.IsNullOrWhiteSpace(configuration["IS_AT_ALL"]))
    {
        Console.WriteLine("Either AT_MOBILES or IS_AT_ALL must be specified!");
        return;
    }

    try
    {
        ProcessMessageDelivery(configuration).Wait();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

Message Format Configuration

The application constructs appropriate message payloads based on the specified message type:

private static async Task ProcessMessageDelivery(IConfigurationRoot config)
{
    var mentionSettings = new
    {
        AtMobiles = config["AT_MOBILES"]?.Split(','),
        IsAtAll = Convert.ToBoolean(config["IS_AT_ALL"] ?? "false")
    };

    switch (config["MSG_TYPE"])
    {
        case "text":
            var textPayload = new
            {
                Msgtype = "text",
                Text = new { Content = config["MESSAGE"] },
                At = mentionSettings
            };
            await ExecuteWebhookCall(config["WEBHOOK"], textPayload);
            break;

        case "markdown":
            var markdownPayload = new
            {
                Msgtype = "markdown",
                Markdown = new 
                { 
                    Title = "DingTalk Notification", 
                    Text = config["MESSAGE"] 
                },
                At = mentionSettings
            };
            await ExecuteWebhookCall(config["WEBHOOK"], markdownPayload);
            break;

        default:
            Console.WriteLine($"Unsupported message type: {config["MSG_TYPE"]}");
            break;
    }
}

HTTP Request Execution

The webhook execution method handles JSON serialization and HTTP POST requests:

private static async Task ExecuteWebhookCall<t>(string webhookUrl, T payload) where T : class
{
    JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
    {
        NullValueHandling = NullValueHandling.Ignore,
        ContractResolver = new CamelCasePropertyNamesContractResolver()
    };

    var jsonContent = JsonConvert.SerializeObject(payload);
    Console.WriteLine(jsonContent);

    using (var httpClient = new HttpClient())
    {
        var requestContent = new StringContent(jsonContent);
        requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        
        var response = await httpClient.PostAsync(webhookUrl, requestContent);
        response.EnsureSuccessStatusCode();
        
        Console.WriteLine($"Webhook call successful. Status: {response.StatusCode}");
    }
}
</t>

Docker Container Configuration

The Dockerfile uses multi-stage build for optimized image size:

FROM mcr.microsoft.com/dotnet/runtime:2.2 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:2.2 AS build
WORKDIR /src
COPY DingTalkSender/DingTalkSender.csproj DingTalkSender/
RUN dotnet restore DingTalkSender/DingTalkSender.csproj
COPY . .
WORKDIR /src/DingTalkSender
RUN dotnet build DingTalkSender.csproj -c Release -o /app

FROM build AS publish
RUN dotnet publish DingTalkSender.csproj -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "DingTalkSender.dll"]

LABEL Description="DingTalk notification sender component"
LABEL InputConfig='{
    "WEBHOOK": "Required: DingTalk webhook URL",
    "AT_MOBILES": "Optional: Phone numbers to mention",
    "IS_AT_ALL": "Optional: Mention all users (true/false)",
    "MESSAGE": "Required: Message content",
    "MSG_TYPE": "Required: Message type (text/markdown)"
}'

Deployment and Execution

Build and run the container with environment variables:

docker build -t dingtalk-sender:latest .

docker run --rm \
  -e "WEBHOOK=https://oapi.dingtalk.com/robot/send?access_token={token}" \
  -e "MESSAGE=*Notification from .NET Core application*" \
  -e "IS_AT_ALL=true" \
  -e "MSG_TYPE=markdown" \
  dingtalk-sender

Tags: .NET Core DingTalk Webhook docker HttpClient

Posted on Mon, 14 Sep 2026 16:13:01 +0000 by PoOP