C#发送钉钉通知机器人
某个项目,测试环境下,通知开发组人员各种情况,比如给测试额外信息支持之类,就想到了用钉钉机器人通知。
不过官方只有py和java,php的,没有c#。这里写一套仅供参考。注释都在代码里面了。重点在签名和发送那块。其他可忽略!
吐槽一下,文中有java 和 php就被自动定义关键字“java”和“php”了!c#却没有被带入关键字!果然是四等人!
/// <summary>
/// 返回结果 不是重点,仅仅是完整性
/// </summary>
/// <typeparam name="T"></typeparam>
public class Result<T>
{
/// <summary>
/// 状态
/// </summary>
public bool Status;
/// <summary>
/// 状态代码
/// </summary>
public long StatusCode;
/// <summary>
/// 消息
/// </summary>
public String Message = string.Empty;
/// <summary>
/// 数据
/// </summary>
public T Data;
/// <summary>
/// 错误详情 用于调试获取错误详细信息, 可不写
/// </summary>
public string ErrorDetail = "";
}
/// <summary>
/// 运营通知接口,这个不是核心可以不看
/// </summary>
public interface IOperationNotification
{
/// <summary>
/// 发送通知
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
Result<string> Send(string msg);
}
/// <summary>
/// 钉钉运营通知 重点在内
/// </summary>
public class DingDingOperationNotification : IOperationNotification
{
/// <summary>
/// 钉钉结果,这是钉钉的官方返回结果结构,没错errcode就是0
/// </summary>
public class dingdingResult
{
public int errcode { get; set; }
public string errmsg { get; set; }
}
/// <summary>
/// 钉钉发送通知,调用入口
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public Result<string> Send(string msg)
{
if (msg.NullEmpty()) {
// 这是个扩展方法,用一段错误信息string直接构成一个错误返回结构
// 这个真的是方便用,但是首次创造的时候 经理妹妹看不懂。其他一些同事也看不懂
// 还有个用成功结果数据构成成功结果的扩展方法
// 这类扩展多了 会都出现在点符号后的提示中。要注意命名
return "没有发送内容".FailRes<string>();
}
var send_res = this.SendToDingDing(msg);
var res_x = send_res.ToObject<dingdingResult>();
if (res_x.errcode == 0)
{
// 还有个用成功结果数据构成成功结果的扩展方法
// 这里是 Result<string> 字符串是成功的结果,不是错误信息
return "ok".SuccRes();
}
else
{
return res_x.errmsg.FailRes<string>();
}
}
/// <summary>
/// 发送到钉钉 机器人 重点方法 链接构成,数据构成
/// TOKEN 要更换成相应的
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public string SendToDingDing(string msg)
{
string main_url = "https://oapi.dingtalk.com/robot/send?access_token=TOKEN";
// 这里要参考官方文档制定发送内容的允许关键字
string data = $"{{"msgtype": "text","text": {{"content": "验证信息:{msg}"}}}}";
var sign = TransEx.sign();// 签名是重点
// 必须urlcode
var urlcode_sign = HttpUtility.UrlEncode(sign.Item2);
// 组成格式
string fin_url = $"{main_url}×tamp={sign.Item1}&sign={urlcode_sign}";
// 这里用了 扩展方式的post,可以自己定义
// 用最终url字符串做扩展直接post这个url, 主要是方便用,特方便
var res = fin_url.HttpPost(data: data);
return res;
}
/// <summary>
/// 时间戳1970年
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public TimeSpan GetTimeSpan1970(DateTime time)
{
return time - new DateTime(1970, 01, 01, 0, 0, 0, 0);
}
/// <summary>
/// 元年时间戳
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public TimeSpan GetTimeSpan(DateTime time)
{
return time - new DateTime();
}
/// <summary>
/// 时间戳转长整型
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public long GetLongTimeSpan(DateTime time)
{
var timestamp = time.GetTimeSpan1970();
long long_timestamp = Convert.ToInt64(Math.Round(timestamp.TotalMilliseconds));
return long_timestamp;
}
/// <summary>
/// 钉钉签名-- 这里超级重要 --
/// </summary>
/// <returns></returns>
public Tuple<long, string> sign()
{
// 钉钉用的是utc时间做时间戳,不是本地时间
long timestamp = DateTime.UtcNow.GetLongTimeSpan();
// 官方给你的secret
string secret = "SECRET";
Encoding code = UTF8Encoding.UTF8;//utf8
var secret_byte = code.GetBytes(secret);
string string_to_sign = $"{timestamp}
{secret}";//看官方,签名组成法
// 签名转字节
var string_to_sign_enc = code.GetBytes(string_to_sign);
// 散列加密用HMAC SHA256,用的key就是secret字节组
byte[] hash = new HMACSHA256(secret_byte).ComputeHash(string_to_sign_enc);
// 要base64
var base64Code = Convert.ToBase64String(hash);
return new Tuple<long, string>(timestamp, base64Code);
}
/// <summary>
/// 钉钉post
/// </summary>
/// <param name="url"></param>
/// <param name="data"></param>
/// <param name="contentType"></param>
/// <returns></returns>
public string HttpPost(string url, string data = "", string contentType = "application/json")
{
string res = "";
var t = Task.Run(async () =>
{
using (HttpClient client = new HttpClient())
{
try
{
var uri = url;
HttpRequestMessage req = new HttpRequestMessage(new HttpMethod("POST"), uri);
req.Content = new StringContent(data);
req.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
return await client.SendAsync(req).Result.Content.ReadAsStringAsync();
//return client.GetAsync(uri).Result.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
return await Task.Run<string>(() => { return ex.Message; });
}
}
});
Task.WaitAll(t);
res = t.Result;
return res;
}
/// <summary>
/// 成功的结果
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="msg"></param>
/// <returns></returns>
public static Result<T> SuccRes<T>(this T data, string msg = "")
{
return new Result<T>() { Data = data, Message = msg, Status = true, StatusCode = 1 };
}
/// <summary>
/// 失败的结果
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="msg">失败消息</param>
/// <param name="errCode">错误代码,通常为-1,指定前端重新登录时用401(仅用于公众号用户中心接口上)</param>
/// <param name="errDetail">错误明细</param>
/// <returns></returns>
public static Result<T> FailRes<T>(this string msg, int errCode = -1, string errDetail = "")
{
return new Result<T>() { Data = default(T), Message = msg, Status = false, StatusCode = errCode, ErrorDetail = errDetail };
}
}
/// <summary>
/// 运营管理
/// </summary>
public class OperationManager
{
/// <summary>
/// 创建通知器
/// </summary>
/// <returns></returns>
public static IOperationNotification CreateNotification()
{
return new DingDingOperationNotification();
}
}
以上是 C#发送钉钉通知机器人 的全部内容, 来源链接: utcz.com/z/518328.html