此文章借鉴钉钉系列教程http://blog.youkuaiyun.com/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
}
}
到此为止,所有的内容都已经发完,如果有不明白的地方可以留言,如果有错误的地方也请指出,谢谢。