此文章借鉴钉钉系列教程http://blog.****.net/wxbluethink/article/details/77435242,增加自己的理解,记录钉钉通过调用机器人发送消息到钉钉群。
环境:VS2015 WinForm 控制台程序
1、首先在钉钉后端添加机器人,具体步骤参考钉钉开发文档:
2、设置好之后,在后台写代码(源码从调用到最基础的工具类的顺序呈现):
1>、先看调用方法:
namespace MyDDTest { class Program { static void Main ( string [ ] args ) { ApiTool . SendTextMsg ("其他测试" ,Microapplication .Other. ToString ( ) ); } } }
2>、发送消息的方法体如下:
/// <summary> /// 通过机器人发送公告到钉钉群 /// </summary> /// <param name="Content">发送的消息内容</param> /// <param name="AgentID">微应用</param> /// <returns>发送JSON格式</returns> public static SendMessageResult SendTextMsg (string Content,string AgentID ) { var txtmsg = new { //开发者ID touser = ConfigHelper.FetchDeveloperID(), //发送消息类型 msgtype = MsgType . text . ToString ( ), //微应用ID agentid = ConfigHelper.FetchAgentID(AgentID), //消息内容 text = new { content = Content } }; //发送消息的URL string apiurl = FormatApiUrlWithToken ( Urls . message_send ); //把上面的内容转成JSON格式 string json = JsonConvert . SerializeObject ( txtmsg ); //以POST请求的方式发送消息 var result = Analyze . POST<SendMessageResult> ( apiurl ,json ); //发送消息 return result; }3>、<1>中调用方法的参数来源( Microapplication .Other. ToString ())
namespace MyDDTest { /// <summary> /// 钉钉微应用列举,代表钉钉后台所有的微应用 /// </summary> public enum Microapplication { /// <summary> /// 签到 /// </summary> Sign, /// <summary> /// 考勤打卡 /// </summary> CkeckWork, /// <summary> /// 日志 /// </summary> Log, /// <summary> /// 公告 /// </summary> Notice, /// <summary> /// 审批 /// </summary> Approval, /// <summary> /// 钉邮 /// </summary> Mail, /// <summary> /// 钉盘 /// </summary> Disc, /// <summary> /// 智能报表 /// </summary> Report, /// <summary> /// 电话会议 /// </summary> Teleconferencing, /// <summary> /// 视频会议 /// </summary> Videoconferencing, /// <summary> /// 客户管理 /// </summary> CustomerManager, /// <summary> /// 办公电话 /// </summary> OfficePhone, /// <summary> /// 钉钉运动 /// </summary> Motion, /// <summary> /// 企业主页 /// </summary> Homepage, /// <summary> /// 其他测试 /// </summary> Other } }
4>、获取开发者ID类,类名ConfigHelper.cs,内容从app.config中读取:
using System; using System . Configuration; namespace MyDDTest { public class ConfigHelper { /// <summary> /// 得到CorpId /// </summary> /// <returns></returns> public static string FetchCorpID ( ) { return FetchValue ( Keys . corpid ); } /// <summary> /// 得到corpSecret /// </summary> /// <returns></returns> public static string FetchCorpSecret ( ) { return FetchValue ( Keys . corpsecret ); } /// <summary> /// 得到AgentID /// </summary> /// <param name="names"></param> /// <returns></returns> public static string FetchAgentID ( string names ) { return FetchValue ( names ); } /// <summary> /// 得到开发者ID,必须是钉钉管理员 /// </summary> /// <returns></returns> public static string FetchDeveloperID ( ) { return FetchValue ( "DevelopmentID" ); } /// <summary> /// 根据key获取config中的value /// </summary> /// <param name="key"></param> /// <returns></returns> private static string FetchValue ( string key ) { string value = ConfigurationManager . AppSettings [ key ]; if ( value == null ) { throw new Exception ( $"{key} is null.请确认配置文件中是否已配置." ); } return value; } } }
5>、app.config中参数,key对应<3>中的列举:
<appSettings> <add key="corpid" value="ding%¥@#¥%%……&&**()()*&……&………………" /> <add key="corpsecret" value="Oa@#@¥%%¥……&&*&……%¥¥#@##¥¥%%" /> <add key="Sign" value="1111111" /> <add key="CkeckWork" value="111111" /> <add key="Log" value="111111" /> <add key="Notice" value="111111" /> <add key="Approval" value="1111111" /> <add key="Mail" value="111111" /> <add key="Disc" value="111111" /> <add key="Report" value="111111" /> <add key="Teleconferencing" value="111111" /> <add key="Videoconferencing" value="111111" /> <add key="CustomerManager" value="111111" /> <add key="OfficePhone" value="11111111" /> <add key="Motion" value="1111111" /> <add key="Homepage" value="11111111" /> <add key="DevelopmentID" value="11111111111111111111" /> <add key="Other" value="111111111111" /> </appSettings>
6>、消息类型,可以参考钉钉开发文档
以下通过枚举呈现:
namespace MyDDTest { public enum MsgType { text, actionCard, image, voice, file, link, OA, markdown } }
7>、获取发送消息的url请求地址
/// <summary> /// 获取发送消息的url /// </summary> /// <param name="Url">url</param> /// <param name="forceUpdate"></param> /// <returns></returns> public static string FormatApiUrlWithToken ( string Url ,bool forceUpdate = false ) { //获取token UpdateAccessToken ( forceUpdate ); string apiurl = $"{Url}?{Keys . access_token}={AccessToken . Value}"; return apiurl; }
8>、获取Token
/// <summary> /// 接受Token /// </summary> /// <param name="forced">true:强制更新.false:按缓存是否到期来更新</param> public static void UpdateAccessToken ( bool forced = false ) { //ConstVars.CACHE_TIME是缓存时间(常量,也可放到配置文件中),这样在有效期内则直接从缓存中获取票据,不需要再向服务器中获取。 if ( !forced && AccessToken . Begin . AddSeconds ( ConstVars . CACHE_TIME ) >= DateTime . Now ) { return; } string CorpID = ConfigHelper . FetchCorpID ( ); string CorpSecret = ConfigHelper . FetchCorpSecret ( ); string TokenUrl = Urls . gettoken; string apiurl = $"{TokenUrl}?{Keys . corpid}={CorpID}&{Keys . corpsecret}={CorpSecret}"; TokenResult tokenResult = Analyze . Get<TokenResult> ( apiurl ); if ( tokenResult . ErrCode == ErrCodeEnum . OK ) { AccessToken . Value = tokenResult . Access_token; AccessToken . Begin = DateTime . Now; } }
9>、发送消息的URL来源
namespace MyDDTest { /// <summary> /// SDK使用的URL /// </summary> public sealed class Urls { /// <summary> /// 创建会话 /// </summary> public const string chat_create="https://oapi.dingtalk.com/chat/create"; /// <summary> /// 获取会话信息 /// </summary> public const string chat_get="https://oapi.dingtalk.com/chat/get"; /// <summary> /// 发送会话消息 /// </summary> public const string chat_send="https://oapi.dingtalk.com/chat/send"; /// <summary> /// 更新会话消息 /// </summary> public const string chat_update="https://oapi.dingtalk.com/chat/update"; /// <summary> /// 获取部门列表 /// </summary> public const string department_list="https://oapi.dingtalk.com/department/list"; /// <summary> /// 获取访问票记 /// </summary> public const string gettoken="https://oapi.dingtalk.com/gettoken"; /// <summary> /// 发送消息 /// </summary> public const string message_send="https://oapi.dingtalk.com/message/send"; /// <summary> /// 用户列表 /// </summary> public const string user_list="https://oapi.dingtalk.com/user/list"; /// <summary> /// 用户详情 /// </summary> public const string user_get="https://oapi.dingtalk.com/user/get"; /// <summary> /// 获取JSAPI的票据 /// </summary> public const string get_jsapi_ticket="https://oapi.dingtalk.com/get_jsapi_ticket"; /// <summary> /// 发起审批 /// </summary> public const string get_Examination_and_approval="https://eco.taobao.com/router/rest"; } }10>、<2>中的
var result = Analyze . POST<SendMessageResult> ( apiurl ,json );
请求方式来源:
Analyze:请求类
using Newtonsoft . Json; using System . Collections . Generic; namespace MyDDTest { public class Analyze { /// <summary> /// GET请求 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="requestUrl"></param> /// <returns></returns> public static T Get<T> ( string requestUrl ) where T : ResultPackage, new() { string resultJson = RequestHelper . Get ( requestUrl ); return AnalyzeResult<T> ( resultJson ); } /// <summary> /// POST请求 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="requestUrl"></param> /// <param name="requestParamOfJsonStr"></param> /// <returns></returns> public static T POST<T> ( string requestUrl ,string requestParamOfJsonStr ) where T : ResultPackage, new() { string resultJson = RequestHelper . Post ( requestUrl ,requestParamOfJsonStr ); return AnalyzeResult<T> ( resultJson ); } /// <summary> /// 分析结果 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="resultJson"></param> /// <returns></returns> public static T AnalyzeResult<T> ( string resultJson ) where T : ResultPackage, new() { ResultPackage tempResult = null; if ( !string . IsNullOrEmpty ( resultJson ) ) { tempResult = JsonConvert . DeserializeObject<ResultPackage> ( resultJson ); } T result = null; if ( tempResult != null && tempResult . IsOK ( ) ) { result = JsonConvert . DeserializeObject<T> ( resultJson ); } else if ( tempResult != null ) { result = tempResult as T; } else if ( tempResult == null ) { result = new T ( ); } result . Json = resultJson; return result; } } }
RequestHelper:请求帮助类
using System . Collections . Generic; using System . IO; using System . Net; using System . Text; namespace MyDDTest { public class RequestHelper { /// <summary> /// 执行基本的命令方法,以GET方法 /// </summary> /// <param name="apiurl"></param> /// <returns></returns> public static string Get ( string apiurl ) { WebRequest request = WebRequest . Create ( @apiurl ); request . Method = "GET"; WebResponse response = request . GetResponse ( ); Stream stream = response . GetResponseStream ( ); Encoding encode = Encoding . UTF8; StreamReader reader = new StreamReader ( stream ,encode ); string resultJson = reader . ReadToEnd ( ); return resultJson; } /// <summary> /// 以post方式提交命令 /// </summary> /// <param name="apiurl"></param> /// <param name="jsonString"></param> /// <returns></returns> public static string Post ( string apiurl ,string jsonString ) { WebRequest requset = WebRequest . Create ( @apiurl ); requset . Method = "POST"; requset . ContentType = "application/json"; byte [ ] bs = Encoding . UTF8 . GetBytes ( jsonString ); requset . ContentLength = bs . Length; Stream newStream = requset . GetRequestStream ( ); newStream . Write ( bs ,0 ,bs . Length ); newStream . Close ( ); WebResponse response = requset . GetResponse ( ); Stream stream = response . GetResponseStream ( ); Encoding encode = Encoding . UTF8; StreamReader reader = new StreamReader ( stream ,encode ); string resultJson = reader . ReadToEnd ( ); return resultJson; } } }
SendMessageResult:请求结果类
namespace MyDDTest { public class SendMessageResult:ResultPackage { public string receiver { get; set; } } }
ResultPackage:请求结果类
namespace MyDDTest { public class ResultPackage { public ErrCodeEnum ErrCode { get; set; } = ErrCodeEnum . Unknown; /// <summary> /// 错误消息 /// </summary> public string ErrMsg { get;set; } /// <summary> /// 结果的Json形式 /// </summary> public string Json { get; set; } public bool IsOK ( ) { return ErrCode == ErrCodeEnum . OK; } public override string ToString ( ) { string info = $"{nameof ( ErrCode )}:{ErrCode},{nameof ( ErrMsg )}:{ErrMsg}"; return info; } } }
11>、<8>中的TokenResult
namespace MyDDTest { public class TokenResult:ResultPackage { public string Access_token { get; set; } } }
12>、<8>中的AccessToken
/// <summary> /// 创建静态字段,保证全局一致 /// </summary> public static AccessToken AccessToken=new AccessToken();13>、<12>中的
AccessToken
using System; namespace MyDDTest { /// <summary> /// 访问票据 /// </summary> public class AccessToken { /// <summary> /// 票据的值 /// </summary> public string Value { get;set; } /// <summary> /// 票据的开始时间 /// </summary> public DateTime Begin { get; set; } = DateTime . Parse ( "1970-01-01" ); } }
14>、<8>中的缓存
namespace MyDDTest { public class ConstVars { /// <summary> /// 缓存的JS票据的KEY /// </summary> public const string CACHE_JS_TICKET_KEY = "CACHE_JS_TICKET_KEY"; /// <summary> /// 缓存时间 /// </summary> public const int CACHE_TIME = 5000; } }
15>、<8>中的请求错误码ErrCodeEnum . OK
namespace MyDDTest { /// <summary> /// 请求返回的错误码 /// </summary> public enum ErrCodeEnum { OK=0, VolidAccessToken=40014, /// <summary> /// 未知 /// </summary> Unknown=int.MaxValue } }到此为止,所有的内容都已经发完,如果有不明白的地方可以留言,如果有错误的地方也请指出,谢谢。