C#实现钉钉消息推送


前言

想起之前有个项目需要使用钉钉消息推送报警数据到群里,提醒群里人员知道设备报警。这篇是通过C#实现钉钉消息推送,因为钉钉机器人设定需设置安全设置,有三个(自定义关键词、加签、IP地址(段)),目前是设置自定义关键词通过C#消息推送。


一、钉钉机器人如何设置

1、钉钉机器人设置需建群(在群里才能机器人)
2、点击群设置,在群管理里点击机器人管理
在这里插入图片描述
3、点击添加机器人选择自定义机器人点击添加
在这里插入图片描述

4、在添加钉钉机器人时需要确定加密方式有以下几种:

  • 自定义关键字
  • 加签
  • IP地址段

注:因目前所选方式为第一种,所以需输入自定义关键字,如:"报警:"
在这里插入图片描述
5、点击完成后,钉钉会给出一个webhook,需复制webhook在C#中使用。
在这里插入图片描述
6、如果自定义机器人在群里发送招呼话语,说明已建造设置成功。

二、C#实现钉钉消息推送

1.钉钉消息类型

钉钉消息有六种消息类型,总结如下:

类型是否支持交互关键特性适用场景
文本(text)纯文本,支持@成员简单通知、报警
Markdown支持Markdown格式化复杂内容(如日志报告)
链接(link)标题+图片+跳转链接带缩略图的通知
ActionCard单、多 1-2个可点击按钮审批、任务处理
FeedCard多条链接列表聚合通知(如新闻列表)

2.代码实现

使用C#控制台实现钉钉机器人消息推送。

1)DingTalkRobot类型

钉钉机器人信息推送,代码如下(示例):

using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

public class DingTalkRobot
{
    private readonly string _webhookUrl;
    private readonly HttpClient _httpClient;

    public DingTalkRobot(string webhookUrl)
    {
        _webhookUrl = webhookUrl ?? throw new ArgumentNullException(nameof(webhookUrl));
        _httpClient = new HttpClient();
    }

    /// <summary>
    /// 发送文本消息
    /// </summary>
    /// <param name="content">消息内容</param>
    /// <param name="atMobiles">需要@的手机号数组</param>
    /// <param name="isAtAll">是否@所有人</param>
    public async Task SendTextMessageAsync(string content, string[] atMobiles = null, bool isAtAll = false)
    {
        var message = new
        {
            msgtype = "text",
            text = new
            {
                content = content
            },
            at = new
            {
                atMobiles = atMobiles ?? Array.Empty<string>(),
                isAtAll = isAtAll
            }
        };

        await SendMessageAsync(message);
    }

    /// <summary>
    /// 发送Markdown消息
    /// </summary>
    /// <param name="title">标题</param>
    /// <param name="text">Markdown格式内容</param>
    /// <param name="atMobiles">需要@的手机号数组</param>
    /// <param name="isAtAll">是否@所有人</param>
    public async Task SendMarkdownMessageAsync(string title, string text, string[] atMobiles = null, bool isAtAll = false)
    {
        var message = new
        {
            msgtype = "markdown",
            markdown = new
            {
                title = title,
                text = text
            },
            at = new
            {
                atMobiles = atMobiles ?? Array.Empty<string>(),
                isAtAll = isAtAll
            }
        };

        await SendMessageAsync(message);
    }

    /// <summary>
    /// 发送链接消息
    /// </summary>
    /// <param name="title">标题</param>
    /// <param name="text">内容</param>
    /// <param name="messageUrl">跳转链接</param>
    /// <param name="picUrl">图片链接(可选)</param>
    public async Task SendLinkMessageAsync(string title, string text, string messageUrl, string picUrl = "")
    {
        var message = new
        {
            msgtype = "link",
            link = new
            {
                title = title,
                text = text,
                messageUrl = messageUrl,
                picUrl = picUrl
            }
        };

        await SendMessageAsync(message);
    }

    /// <summary>
    /// 发送 单按钮 ActionCard​消息
    /// </summary>
    /// <param name="title">消息标题,显示在消息顶部</param>
    /// <param name="text">消息内容,支持Markdown语法</param>
    /// <param name="singleTitle">单个按钮的文本(不超过20字符)</param>
    /// <param name="singleUrl">按钮跳转链接(需HTTP/HTTPS)</param>
    /// <param name="atMobiles">需要@的群成员手机号数组</param>
    /// <param name="isAtAll">是否@所有人(慎用)</param>
    /// <returns></returns>
    public async Task SendActionCardAsync(string title, string text, string singleTitle, string singleUrl, string[] atMobiles = null, bool isAtAll = false)
    {
        var message = new
        {
            msgtype = "actionCard",
            actionCard = new
            {
                title = title,
                text = text,
                singleTitle = singleTitle,
                singleURL = singleUrl,
                btnOrientation = "0" // "0"垂直按钮,"1"水平按钮
            },
            at = new
            {
                atMobiles = atMobiles ?? Array.Empty<string>(),
                isAtAll = isAtAll
            }
        };
        await SendMessageAsync(message);
    }

    /// <summary>
    /// 发送 多按钮 ActionCard消息
    /// </summary>
    /// <param name="title">消息标题</param>
    /// <param name="text">消息内容</param>
    /// <param name="buttons">按钮列表(最多2个)</param>
    /// <param name="btnOrientation">按钮排列方向:“0”(垂直,默认) 或 “1”(水平)</param>
    /// <param name="atMobiles">需要@的手机号数组</param>
    /// <param name="isAtAll">是否@所有人</param>
    /// <returns></returns>
    public async Task SendMultiActionCardAsync(string title, string text, List<DingTalkButton> buttons, string btnOrientation = "0", // "0"垂直,"1"水平
    string[] atMobiles = null, bool isAtAll = false)
    {
        var message = new
        {
            msgtype = "actionCard",
            actionCard = new
            {
                title = title,
                text = text,
                btns = buttons.Select(b => new { title = b.Title, actionURL = b.Url }).ToArray(),
                btnOrientation = btnOrientation
            },
            at = new
            {
                atMobiles = atMobiles ?? Array.Empty<string>(),
                isAtAll = isAtAll
            }
        };
        await SendMessageAsync(message);
    }

    /// <summary>
    /// 发送FeedCard消息
    /// </summary>
    /// <param name="links">链接列表(最多5条)</param>
    /// <returns></returns>
    public async Task SendFeedCardAsync(List<FeedCardLink> links)
    {
        var message = new
        {
            msgtype = "feedCard",
            feedCard = new
            {
                links = links.Select(link => new
                {
                    title = link.Title,
                    messageURL = link.MessageUrl,
                    picURL = link.PicUrl
                }).ToArray()
            }
        };
        await SendMessageAsync(message);
    }

    // FeedCard 链接定义类
    public class FeedCardLink
    {
        //链接标题(小于等于64字符)
        public string Title { get; set; }
        //跳转链接(需HTTP/HTTPS)
        public string MessageUrl { get; set; }
        //图片链接(可选,建议尺寸:520x275像素)
        public string PicUrl { get; set; }
    }

    // 按钮定义类
    public class DingTalkButton
    {
        //按钮文本(小于等于20字符)
        public string Title { get; set; }
        //跳转链接(需HTTP/HTTPS)
        public string Url { get; set; }
    }

    private async Task SendMessageAsync(object message)
    {
        var json = Newtonsoft.Json.JsonConvert.SerializeObject(message);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        var response = await _httpClient.PostAsync(_webhookUrl, content);
        response.EnsureSuccessStatusCode();

        var responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"钉钉机器人响应: {responseContent}");
    }
}

2)Program类型

钉钉机器人发送消息实现类,代码如下:

using static DingTalkRobot;
using static System.Net.Mime.MediaTypeNames;

public class Program
{
    static async Task Main(string[] args)
    {
        // 实际Webhook URL
        var webhookUrl = "https://oapi.dingtalk.com/robot/send?access_token=ea8b2fe200c23a4ec8a9569c88ca9561d4f7ebe9bb10d1146ed07e49904c0627\r\n";
        var dingTalkRobot = new DingTalkRobot(webhookUrl);

        try
        {
            //关键字 = “报警:” 需在title、content参数加关键字
            //1、发送文本消息(消息长度不超过20kb)
            await dingTalkRobot.SendTextMessageAsync("报警:这是一条测试消息",
                atMobiles: new[] { "13812345678" },
                isAtAll: false);

            //2、发送Markdown消息(1、不支持HTML和复杂表格 2、总长度不超过8192字节)
            await dingTalkRobot.SendMarkdownMessageAsync(
                "报警:项目更新通知",
                "### 项目状态更新\n" +
                "> 项目进度: 80%\n\n" +
                "> 剩余时间: 2天\n\n" +
                "![screenshot](https://example.com/image.png)\n" +
                "###### [查看详情](https://example.com)",
                atMobiles: new[] { "13812345678" });

            //3、发送链接消息(最后两个 跳转链接 图片链接)
            await dingTalkRobot.SendLinkMessageAsync(
                "报警:系统报警通知",
                "生产环境出现异常,请及时处理",
                "https://www.bilibili.com/video/BV1ZU4y1q7sn/?share_source=copy_web&vd_source=ad0206b6bbe094bb6fa542017f2e474b",
                "https://www.bilibili.com/opus/366829175324803541?from=search&spm_id_from=333.337.0.0");

            //4、发送单按钮 ActionCard消息
            await dingTalkRobot.SendActionCardAsync(
                title: "报警:任务审批",
                text: "**申请人**: 张三\n**内容**: 采购申请\n请及时处理!",
                singleTitle: "点击审批",
                singleUrl: "https://example.com/approve?id=123");

            //5、发送多按钮 ActionCard消息
            var buttons = new List<DingTalkButton>
            {
                new DingTalkButton { Title = "同意", Url = "https://example.com/agree" },
                new DingTalkButton { Title = "拒绝", Url = "https://example.com/reject" }
            };

            await dingTalkRobot.SendMultiActionCardAsync(
                title: "报警:请假审批",
                text: "**员工**: 李四\n**天数**: 3天",
                buttons: buttons,
                btnOrientation: "1" // 水平排列按钮
            );

            //6、发送FeedCard消息
            var links = new List<FeedCardLink>
            {
                new FeedCardLink
                {
                    Title = "报警:系统报警",
                    MessageUrl = "https://example.com/alert1",
                    PicUrl = "https://example.com/alert.png"
                },
                new FeedCardLink
                {
                    Title = "报警:新任务",
                    MessageUrl = "https://example.com/task1",
                    PicUrl = "https://example.com/task.png"
                }
            };

            await dingTalkRobot.SendFeedCardAsync(links);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发送钉钉消息失败: {ex.Message}");
        }
    }
}

3)运行结果

图片1 图片2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值