C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C#调用钉钉API

C#调用钉钉API发送通知的实现示例

作者:阿登林

本文介绍了使用C#调用钉钉API实现企业通知推送的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

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

一、钉钉开放平台配置

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

1.1 创建钉钉应用

1.2 获取应用凭证

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

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

1.3 添加接口权限

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

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

搜索并添加以下权限:

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

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

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

二、C#项目准备

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

2.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();
    }
}

到此这篇关于C#调用钉钉API发送通知的实现示例的文章就介绍到这了,更多相关C#调用钉钉API内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文