当前位置: 首页 > news >正文

C#调用钉钉API发送通知教程

在企业信息化建设中,实时通知是提升工作效率的重要手段。钉钉作为国内流行的企业级通讯工具,提供了丰富的API接口,允许开发者通过代码发送各类通知。本文将详细介绍如何使用C#语言调用钉钉API发送通知,帮助企业实现自动化消息推送。

一、钉钉开放平台配置

在开始编码前,我们需要在钉钉开放平台完成相关配置,获取调用API所需的凭证。

1.1 创建钉钉应用

  1. 登录钉钉开放平台

  2. 进入"应用开发" -> "企业内部开发" -> "应用管理"

  3. 点击"创建应用",填写应用名称、描述等信息

  4. 上传应用图标,选择应用类型为"H5微应用"

  5. 点击"确定创建"按钮完成应用创建

1.2 获取应用凭证

应用创建成功后,我们需要获取两个重要的凭证:

  1. AppKey:应用的唯一标识

  2. AppSecret:应用的密钥,用于生成访问令牌

这两个凭证可以在应用详情页的"凭证与基础信息"中找到。

1.3 添加接口权限

为了能够发送通知,我们需要为应用添加相应的接口权限:

  1. 在应用详情页中,点击"权限管理"

  2. 搜索并添加以下权限:

    • 企业消息通知

    • 获取部门基础信息(如需按部门发送通知)

    • 获取用户基本信息(如需指定用户发送通知)

  3. 点击"申请权限",等待管理员审核通过

1.4 创建自定义机器人(可选)

除了通过应用发送通知外,我们还可以通过自定义机器人发送群消息:

  1. 打开钉钉群聊,点击右上角"群设置"

  2. 选择"智能群助手" -> "添加机器人"

  3. 选择"自定义机器人"

  4. 设置机器人名称、安全设置(建议选择"加签"方式)

  5. 完成创建后,复制Webhook地址,保存备用

二、C#项目准备

现在,我们开始准备C#项目环境,为调用钉钉API做准备。

2.1 创建项目

  1. 打开Visual Studio,创建一个新的控制台应用或Web应用项目

  2. 选择.NET Framework或.NET Core版本(本文以.NET Core 3.1为例)

2.2 添加必要的NuGet包

我们需要添加以下NuGet包来简化开发:

# 使用Package Manager Console
Install-Package Newtonsoft.Json
Install-Package RestSharp

或通过NuGet包管理器界面搜索并安装这些包。

2.3 创建配置文件

在项目中添加一个配置文件appsettings.json,用于存储我们在钉钉开放平台获取的凭证信息:

{"DingTalk": {"AppKey": "your_app_key","AppSecret": "your_app_secret","AgentId": 123456789,"Webhook": "your_webhook_url","Secret": "your_robot_secret"}
}

三、实现钉钉API调用工具类

接下来,我们将创建一个工具类,封装钉钉API的调用方法。

3.1 创建访问令牌管理类

首先,我们需要创建一个类来管理访问令牌(AccessToken):

using Newtonsoft.Json;
using RestSharp;
using System;
using System.Configuration;
using System.Threading.Tasks;
​
public class DingTalkTokenManager
{private static string _accessToken = string.Empty;private static DateTime _tokenExpireTime = DateTime.MinValue;private readonly string _appKey;private readonly string _appSecret;
​public DingTalkTokenManager(string appKey, string appSecret){_appKey = appKey;_appSecret = appSecret;}
​public async Task<string> GetAccessTokenAsync(){// 检查令牌是否已过期,如未过期则直接返回if (!string.IsNullOrEmpty(_accessToken) && DateTime.Now < _tokenExpireTime){return _accessToken;}
​// 调用钉钉API获取新的访问令牌var client = new RestClient("https://oapi.dingtalk.com");var request = new RestRequest("gettoken", Method.GET);request.AddParameter("appkey", _appKey);request.AddParameter("appsecret", _appSecret);
​var response = await client.ExecuteAsync(request);var result = JsonConvert.DeserializeObject<dynamic>(response.Content);
​if (result.errcode == 0){_accessToken = result.access_token;// 访问令牌有效期为7200秒,我们设置提前10分钟刷新_tokenExpireTime = DateTime.Now.AddSeconds(result.expires_in - 600);return _accessToken;}else{throw new Exception($"获取访问令牌失败:{result.errmsg}");}}
}

3.2 创建钉钉消息发送类

接下来,我们创建一个类来处理各种类型的消息发送:

using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
​
public class DingTalkMessageSender
{private readonly DingTalkTokenManager _tokenManager;private readonly string _agentId;private readonly string _webhook;private readonly string _secret;
​public DingTalkMessageSender(string appKey, string appSecret, string agentId, string webhook = "", string secret = ""){_tokenManager = new DingTalkTokenManager(appKey, appSecret);_agentId = agentId;_webhook = webhook;_secret = secret;}
​/// <summary>/// 发送工作通知消息/// </summary>public async Task<dynamic> SendWorkNoticeAsync(string userIdList, string deptIdList, string toAllUser, string message){var accessToken = await _tokenManager.GetAccessTokenAsync();var client = new RestClient("https://oapi.dingtalk.com");var request = new RestRequest("topapi/message/corpconversation/asyncsend_v2", Method.POST);request.AddParameter("access_token", accessToken);
​var requestBody = new{agent_id = _agentId,userid_list = userIdList, // 用户ID列表,多个用户用逗号分隔dept_id_list = deptIdList, // 部门ID列表,多个部门用逗号分隔to_all_user = toAllUser, // 是否发送给全员msg = new{msgtype = "text",text = new { content = message }}};
​request.AddJsonBody(requestBody);var response = await client.ExecuteAsync(request);return JsonConvert.DeserializeObject<dynamic>(response.Content);}
​/// <summary>/// 通过机器人发送群消息/// </summary>public async Task<dynamic> SendRobotMessageAsync(string message){if (string.IsNullOrEmpty(_webhook)){throw new Exception("Webhook地址未配置");}
​var client = new RestClient(_webhook);var request = new RestRequest(Method.POST);// 如果配置了加签,需要生成签名if (!string.IsNullOrEmpty(_secret)){var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString();var stringToSign = $"{timestamp}\n{_secret}";var signature = ComputeHmacSha256(stringToSign);request.AddQueryParameter("timestamp", timestamp);request.AddQueryParameter("sign", signature);}
​var requestBody = new{msgtype = "text",text = new { content = message }};
​request.AddJsonBody(requestBody);var response = await client.ExecuteAsync(request);return JsonConvert.DeserializeObject<dynamic>(response.Content);}
​/// <summary>/// 计算HMAC-SHA256签名/// </summary>private string ComputeHmacSha256(string data){var encoding = new UTF8Encoding();byte[] keyBytes = encoding.GetBytes(_secret);byte[] messageBytes = encoding.GetBytes(data);
​using (var hmacsha256 = new HMACSHA256(keyBytes)){byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);return Convert.ToBase64String(hashmessage);}}
}

四、实现发送不同类型的通知

钉钉支持多种消息类型,除了基本的文本消息外,还支持链接、Markdown、卡片等丰富的消息类型。下面我们来实现几种常见的消息发送方式。

4.1 发送文本消息

/// <summary>
/// 发送文本消息(扩展方法)
/// </summary>
public async Task<dynamic> SendTextMessageAsync(string userIdList, string message)
{return await SendWorkNoticeAsync(userIdList, "", "false", message);
}

4.2 发送Markdown消息

/// <summary>
/// 发送Markdown消息
/// </summary>
public async Task<dynamic> SendMarkdownMessageAsync(string userIdList, string title, string markdownText)
{var accessToken = await _tokenManager.GetAccessTokenAsync();var client = new RestClient("https://oapi.dingtalk.com");var request = new RestRequest("topapi/message/corpconversation/asyncsend_v2", Method.POST);request.AddParameter("access_token", accessToken);
​var requestBody = new{agent_id = _agentId,userid_list = userIdList,to_all_user = "false",msg = new{msgtype = "markdown",markdown = new{title = title,text = markdownText}}};
​request.AddJsonBody(requestBody);var response = await client.ExecuteAsync(request);return JsonConvert.DeserializeObject<dynamic>(response.Content);
}

4.3 发送卡片消息

/// <summary>
/// 发送卡片消息
/// </summary>
public async Task<dynamic> SendActionCardMessageAsync(string userIdList, string title, string markdownText, string singleTitle, string singleURL)
{var accessToken = await _tokenManager.GetAccessTokenAsync();var client = new RestClient("https://oapi.dingtalk.com");var request = new RestRequest("topapi/message/corpconversation/asyncsend_v2", Method.POST);request.AddParameter("access_token", accessToken);
​var requestBody = new{agent_id = _agentId,userid_list = userIdList,to_all_user = "false",msg = new{msgtype = "action_card",action_card = new{title = title,text = markdownText,single_title = singleTitle,single_url = singleURL,btn_orientation = "0"}}};
​request.AddJsonBody(requestBody);var response = await client.ExecuteAsync(request);return JsonConvert.DeserializeObject<dynamic>(response.Content);
}

五、完整使用示例

下面是一个完整的使用示例,展示如何在实际项目中使用我们创建的工具类发送钉钉通知:

using Microsoft.Extensions.Configuration;
using System;
using System.IO;
using System.Threading.Tasks;
​
class Program
{static async Task Main(string[] args){// 读取配置文件var configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
​// 获取配置信息var appKey = configuration["DingTalk:AppKey"];var appSecret = configuration["DingTalk:AppSecret"];var agentId = configuration["DingTalk:AgentId"];var webhook = configuration["DingTalk:Webhook"];var secret = configuration["DingTalk:Secret"];
​try{// 初始化消息发送器var messageSender = new DingTalkMessageSender(appKey, appSecret, agentId, webhook, secret);
​// 示例1:发送工作通知文本消息Console.WriteLine("发送工作通知文本消息...");var userIdList = "user1,user2";var textResponse = await messageSender.SendTextMessageAsync(userIdList, "这是一条测试消息,由C#程序发送。");Console.WriteLine($"发送结果:{JsonConvert.SerializeObject(textResponse)}");
​// 示例2:发送Markdown消息Console.WriteLine("\n发送Markdown消息...");var markdownTitle = "项目进度通知";var markdownContent = @"# 项目进度通报\n\n> 项目A已完成70%\n> 项目B已完成45%\n\n## 本周重点任务\n- 完成项目A的模块三开发\n- 开始项目B的系统测试\n\n**请相关负责人注意时间节点!**";var markdownResponse = await messageSender.SendMarkdownMessageAsync(userIdList, markdownTitle, markdownContent);Console.WriteLine($"发送结果:{JsonConvert.SerializeObject(markdownResponse)}");
​// 示例3:发送卡片消息Console.WriteLine("\n发送卡片消息...");var cardTitle = "重要会议通知";var cardContent = @"# 产品评审会议\n\n**时间:** 2023年10月15日 14:00-16:00\n**地点:** 三楼会议室A\n**参会人员:** 产品部全体成员、开发团队负责人\n\n## 会议议程\n1. 产品需求回顾\n2. 功能设计评审\n3. 开发进度同步\n4. 问题讨论与解决";var cardResponse = await messageSender.SendActionCardMessageAsync(userIdList, cardTitle, cardContent, "查看详情", "https://example.com/meeting-details");Console.WriteLine($"发送结果:{JsonConvert.SerializeObject(cardResponse)}");
​// 示例4:通过机器人发送群消息Console.WriteLine("\n通过机器人发送群消息...");var robotResponse = await messageSender.SendRobotMessageAsync("【系统通知】服务器备份任务已完成,备份文件大小:2.5GB");Console.WriteLine($"发送结果:{JsonConvert.SerializeObject(robotResponse)}");
​Console.WriteLine("\n所有消息发送完成!");}catch (Exception ex){Console.WriteLine($"发送消息时发生错误:{ex.Message}");}
​Console.ReadLine();}
}

文章转载自:

http://EIQ7gn1Q.mrgby.cn
http://3OgeTqBM.mrgby.cn
http://oAQGzwl2.mrgby.cn
http://5mcvL4qS.mrgby.cn
http://0iEg3Igl.mrgby.cn
http://sjJcPdv5.mrgby.cn
http://tWDphMit.mrgby.cn
http://5Wrwn6CX.mrgby.cn
http://zAKGdDuf.mrgby.cn
http://C8l3jKvw.mrgby.cn
http://mLvMOEbd.mrgby.cn
http://s5CNow9L.mrgby.cn
http://zhiutSfD.mrgby.cn
http://iRnLNSkk.mrgby.cn
http://R8PbOvZB.mrgby.cn
http://MnvBWf2x.mrgby.cn
http://2sNqJaml.mrgby.cn
http://ZlZgiDLE.mrgby.cn
http://hPOP7CE2.mrgby.cn
http://uG5nDqBz.mrgby.cn
http://GVDbijKW.mrgby.cn
http://RXOQzED0.mrgby.cn
http://9YqaALPK.mrgby.cn
http://0o72Z74B.mrgby.cn
http://2UVgs18F.mrgby.cn
http://ek8u1v1C.mrgby.cn
http://mXouUYZ8.mrgby.cn
http://bpoQXM1H.mrgby.cn
http://vuol1BNF.mrgby.cn
http://lVWTbCMZ.mrgby.cn
http://www.dtcms.com/a/385668.html

相关文章:

  • 电子电气架构 --- 产线EOL为何需要智能升级?
  • 无人机姿态控制系统详解与实现
  • 7.Redis 主从复制(重在理解)
  • 从零搭建RAG应用:跳过LangChain,掌握文本分块、向量检索、指代消解等核心技术实现
  • 从0开始做一个完整项目 -- 软件跨平台编译打包全流程
  • comfyUI实战——使用openArt的工作流
  • linux 之 struct attribute
  • 强化学习PPO-分类任务
  • 决策树模型全解析:从分类到回归(基于鸢尾花数据集)
  • shell脚本部署lamp
  • c语言6:static 关键字控制变量/函数的 “生命周期” 与 “可见性”
  • MySQL 数据库对象与视图:从概念到实战,掌握虚拟表的核心价值
  • 【VPX361】基于3U VPX总线架构的XCZU47DR射频收发子模块
  • 消火栓设备工程量计算 -【图形识别】秒计量
  • 基于LangGraph的深度研究智能体技术解析
  • 【哈希表】1512. 好数对的数目|2506. 统计相似字符串对的数目
  • Java--多线程基础知识(2)
  • 活泼解析pthread_join函数:多线程世界的等待仪式
  • 机器视觉的智能手表后盖激光打标应用
  • 第七章 来日方长(2025.8学习总结)
  • 卡方检验公式中分母 (a+b)(c+d)(a+c)(b+d)的本质
  • IT基础知识——数据库
  • 电子衍射模拟:基于GPU加速的MATLAB/Julia实现
  • yum只安装指定软件库中的包
  • CentOS网卡接口配置文件详细指南
  • 计算机视觉 - 对比学习(上)MoCo + SimCLR + SWaV
  • SQL模糊查询完全指南
  • Qit_计网笔记
  • 新发布、却被遗忘的旗舰级编程模型、grok-code-fast-1
  • Python爬虫的反爬接口:应对策略与实战指南