├── README.md
├── Auth
├── IAuthHelper.cs
└── AuthHelper.cs
├── Message
├── IMessage.cs
├── OAMessage
│ ├── OAMessage.cs
│ └── OAMessageContent.cs
├── LinkMessage
│ ├── LinkMessage.cs
│ └── LinkMessageContent.cs
├── FileMessage
│ ├── FileMessage.cs
│ └── FileMessageContent.cs
├── TextMessage
│ ├── TextMessage.cs
│ └── TextMessageContent.cs
├── ImageMessage
│ ├── ImageMessage.cs
│ └── ImageMessageContent.cs
├── VoiceMessage
│ ├── VoiceMessage.cs
│ └── VoiceMessageContent.cs
├── MarkdownMessage
│ ├── MarkdownMessage.cs
│ └── MarkdownMessageContent.cs
├── ActionCardMessage
│ ├── ActionCardMessage.cs
│ └── ActionCardMessageContent.cs
├── MessageSentResult.cs
└── MessageHelper.cs
├── Util
├── CheckParameterHelper.cs
└── HttpHelper.cs
├── DingDingException
├── DingDingApiResultException.cs
└── DingDingApiException.cs
├── DingTalkSDK.sln
├── DingTalkSDK.csproj
├── Env.cs
├── Department
├── Department.cs
└── DepartmentHelper.cs
├── User
├── User.cs
└── UserHelper.cs
└── .gitignore
/README.md:
--------------------------------------------------------------------------------
1 | # 钉钉服务端SDK
2 | https://open-doc.dingtalk.com/microapp/serverapi2
3 |
4 | nuget可以直接安装:Install-Package DingTalkSDK
5 |
--------------------------------------------------------------------------------
/Auth/IAuthHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Auth
6 | {
7 | public interface IAuthHelper
8 | {
9 | public string getAccessToke();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Message/IMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message
6 | {
7 | public interface IMessage
8 | {
9 | public string msgtype { get;}
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Util/CheckParameterHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DingTalkSDK.Util
8 | {
9 | public sealed class CheckParameterHelper
10 | {
11 | // private void CheckTokenNotNull
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Message/OAMessage/OAMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.OAMessage
6 | {
7 | ///
8 | /// OA消息
9 | ///
10 | public class OAMessage : IMessage
11 | {
12 | public string msgtype { get =>"oa";}
13 | public OAMessageContent oa { get; set; }
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Message/LinkMessage/LinkMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.LinkMessage
6 | {
7 | ///
8 | /// 链接消息
9 | ///
10 | public class LinkMessage : IMessage
11 | {
12 | public string msgtype { get => "link"; }
13 | public LinkMessageContent link { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Message/FileMessage/FileMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.FileMessage
6 | {
7 | ///
8 | /// 附件类消息
9 | ///
10 | public class FileMessage : IMessage
11 | {
12 | public string msgtype { get => "file"; }
13 | public FileMessageContent file { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Message/TextMessage/TextMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.TextMessage
6 | {
7 | ///
8 | /// 文字类消息
9 | ///
10 | public class TextMessage : IMessage
11 | {
12 | public string msgtype { get => "text"; }
13 | public TextMessageContent text { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Message/ImageMessage/ImageMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.ImageMessage
6 | {
7 | ///
8 | /// 图片类消息
9 | ///
10 | public class ImageMessage : IMessage
11 | {
12 | public string msgtype { get => "image"; }
13 | public ImageMessageContent image { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Message/VoiceMessage/VoiceMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.VoiceMessage
6 | {
7 | ///
8 | /// 语音类消息
9 | ///
10 | public class VoiceMessage : IMessage
11 | {
12 | public string msgtype { get => "voice"; }
13 | public VoiceMessageContent voice { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Message/TextMessage/TextMessageContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.TextMessage
6 | {
7 | ///
8 | /// 文字消息的内容
9 | ///
10 | public class TextMessageContent
11 | {
12 | ///
13 | /// 消息内容,建议500字符以内
14 | ///
15 | public string content { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Message/MarkdownMessage/MarkdownMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.MarkdownMessage
6 | {
7 | ///
8 | /// Markdown消息
9 | ///
10 | public class MarkdownMessage : IMessage
11 | {
12 | public string msgtype { get => "markdown"; }
13 | public MarkdownMessageContent markdown { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Message/FileMessage/FileMessageContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.FileMessage
6 | {
7 | ///
8 | /// 附件消息的内容
9 | ///
10 | public class FileMessageContent
11 | {
12 | ///
13 | /// 媒体文件id,引用的媒体文件最大10MB
14 | ///
15 | public string media_id { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Message/ActionCardMessage/ActionCardMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.ActionCardMessage
6 | {
7 | ///
8 | /// 卡片消息
9 | ///
10 | public class ActionCardMessage : IMessage
11 | {
12 | public string msgtype { get => "action_card"; }
13 | public ActionCardMessageContent action_card { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Message/ImageMessage/ImageMessageContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.ImageMessage
6 | {
7 | ///
8 | /// 图片类消息的内容
9 | ///
10 | public class ImageMessageContent
11 | {
12 | ///
13 | /// 媒体文件id,可以通过媒体文件接口上传图片获取。建议宽600像素 x 400像素,宽高比3 : 2
14 | ///
15 | public string media_id { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Message/VoiceMessage/VoiceMessageContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.VoiceMessage
6 | {
7 | ///
8 | /// 语音消息的内容
9 | ///
10 | public class VoiceMessageContent
11 | {
12 | ///
13 | /// 媒体文件id。2MB,播放长度不超过60s,AMR格式
14 | ///
15 | public string media_id { get; set; }
16 | ///
17 | /// 正整数,小于60,表示音频时长
18 | ///
19 | public int duration { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Message/MarkdownMessage/MarkdownMessageContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.MarkdownMessage
6 | {
7 | ///
8 | /// markdown消息内容
9 | ///
10 | public class MarkdownMessageContent
11 | {
12 | ///
13 | /// 首屏会话透出的展示内容
14 | ///
15 | public string title { get; set; }
16 | ///
17 | /// markdown格式的消息,建议500字符以内
18 | ///
19 | public string text { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Message/MessageSentResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message
6 | {
7 | ///
8 | /// 消息发送后的返回结果
9 | ///
10 | public class MessageSentResult
11 | {
12 | ///
13 | /// 返回码
14 | ///
15 | public string errcode { get; set; }
16 | ///
17 | /// 对返回码的文本描述内容
18 | ///
19 | public string errmsg { get; set; }
20 | ///
21 | /// 创建的发送任务id
22 | ///
23 | public string task_id { get; set; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/DingDingException/DingDingApiResultException.cs:
--------------------------------------------------------------------------------
1 | using MongoDB.Bson;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DingTalkSDK.DingDingException
9 | {
10 | public class DingDingApiResultException : DingDingApiException
11 | {
12 | public static readonly int ERR_RESULT_RESOLUTION = -2;
13 |
14 | public DingDingApiResultException(String field) : base(ERR_RESULT_RESOLUTION, "Cannot resolve field " + field + " from oapi resonpse")
15 | {
16 | }
17 | public DingDingApiResultException(int errCode,string errMsg):base(errCode,errMsg)
18 | {
19 |
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/DingDingException/DingDingApiException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DingTalkSDK.DingDingException
8 | {
9 | public class DingDingApiException:Exception
10 | {
11 | public int ErrCode { get; set; }
12 | public string ErrMsg { get; set; }
13 | public DingDingApiException(int errCode, String errMsg) : base("error code: " + errCode + ", error message: " + errMsg)
14 | {
15 | ErrCode = errCode;
16 | ErrMsg = errMsg;
17 | }
18 |
19 | public void printStackTrace()
20 | {
21 | Console.WriteLine(string.Format("errCode={0} errMsg={1}", ErrCode, ErrMsg));
22 | }
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/Message/LinkMessage/LinkMessageContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.LinkMessage
6 | {
7 | ///
8 | /// 链接消息的内容
9 | ///
10 | public class LinkMessageContent
11 | {
12 | ///
13 | /// 消息点击链接地址,当发送消息为小程序时支持小程序跳转链接
14 | ///
15 | public string messageUrl { get; set; }
16 | ///
17 | /// 图片地址
18 | ///
19 | public string picUrl { get; set; }
20 | ///
21 | /// 消息标题,建议100字符以内
22 | ///
23 | public string title { get; set; }
24 | ///
25 | /// 消息描述,建议500字符以内
26 | ///
27 | public string text { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/DingTalkSDK.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29613.14
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DingTalkSDK", "DingTalkSDK.csproj", "{DA70F4CC-C8E6-4E11-AD0B-598E7675D65B}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {DA70F4CC-C8E6-4E11-AD0B-598E7675D65B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {DA70F4CC-C8E6-4E11-AD0B-598E7675D65B}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {DA70F4CC-C8E6-4E11-AD0B-598E7675D65B}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {DA70F4CC-C8E6-4E11-AD0B-598E7675D65B}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {692B1BB7-BAAC-48E9-82FB-444A2BAFBD7D}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/Auth/AuthHelper.cs:
--------------------------------------------------------------------------------
1 | using DingTalkSDK.DingDingException;
2 | using DingTalkSDK.Util;
3 | using Microsoft.Extensions.Caching.Memory;
4 | using MongoDB.Bson;
5 | using System;
6 |
7 | namespace DingTalkSDK.Auth
8 | {
9 | public class AuthHelper
10 | {
11 | public static String getAccessToken()
12 | {
13 | string accessonToken;
14 | if (String.IsNullOrWhiteSpace(Env.CorpId))
15 | {
16 | throw new ArgumentException("请先初始化Env中的CorpId");
17 | }
18 | if (String.IsNullOrWhiteSpace(Env.CorpSecret))
19 | {
20 | throw new ArgumentException("请先初始化Env中的CorpSecret");
21 | }
22 |
23 | String url = Env.OAPI_HOST + "/gettoken?" +
24 | "corpid=" + Env.CorpId + "&corpsecret=" + Env.CorpSecret;
25 | BsonDocument response = HttpHelper.httpGet(url);
26 | if (response.Contains("access_token"))
27 | {
28 | accessonToken = response["access_token"].ToString();
29 | }
30 | else
31 | {
32 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
33 | }
34 |
35 | return accessonToken;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/DingTalkSDK.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | true
6 | 0.9.5
7 | 钉钉的服务端SDK
8 | https://github.com/joychin/DingDingSDK
9 | https://github.com/joychin/DingDingSDK
10 | Github
11 | https://raw.githubusercontent.com/joychin/DingDingSDK/master/LICENSE
12 | https://raw.githubusercontent.com/joychin/DingDingSDK/master/LICENSE
13 |
14 | false
15 | 0.9.5.0
16 | 0.9.5.0
17 |
18 |
19 |
20 |
21 | all
22 | runtime; build; native; contentfiles; analyzers; buildtransitive
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Env.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DingTalkSDK.Auth;
7 |
8 | namespace DingTalkSDK
9 | {
10 | ///
11 | /// 钉钉的环境配置
12 | ///
13 | public class Env
14 | {
15 | public const string OAPI_HOST = "https://oapi.dingtalk.com";
16 |
17 | ///
18 | /// 企业Id
19 | ///
20 | public static string CorpId { get; set; }
21 |
22 | ///
23 | /// 企业应用的凭证密钥
24 | ///
25 | public static string CorpSecret { get; set; }
26 | ///
27 | /// Token 更新日期
28 | ///
29 | private static DateTime Accesson_token_UpdateTime
30 | {
31 | get;set;
32 | }
33 |
34 | ///
35 | /// Access_Token
36 | ///
37 | public static string Access_token
38 | {
39 | get
40 | {
41 | //钉钉规定7200秒过期,这里我们用6900秒过期
42 |
43 | if (
44 | Accesson_token_UpdateTime == DateTime.MinValue
45 | || Accesson_token_UpdateTime == null
46 | || (DateTime.Now - Accesson_token_UpdateTime).TotalSeconds > 6900
47 | )
48 | {
49 | var accessonToken = AuthHelper.getAccessToken();
50 | Env.Accesson_token_UpdateTime = DateTime.Now;
51 | return accessonToken;
52 | }
53 | else
54 | {
55 | return Access_token;
56 | }
57 | }
58 | set => Access_token = value;
59 | }
60 |
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Message/ActionCardMessage/ActionCardMessageContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.ActionCardMessage
6 | {
7 | public class ActionCardMessageContent_btn_json_list
8 | {
9 | ///
10 | /// 使用独立跳转ActionCard样式时的按钮的标题,最长20个字符
11 | ///
12 | public string title { get; set; }
13 | ///
14 | /// 消息点击链接地址,当发送消息为小程序时支持小程序跳转链接,最长500个字符
15 | ///
16 | public string action_url { get; set; }
17 | }
18 | ///
19 | /// 卡片消息内容
20 | /// 卡片消息支持整体跳转ActionCard样式和独立跳转ActionCard样式:
21 | ///(1)整体跳转ActionCard样式,支持一个点击Action,需要传入参数 single_title和 single_url;
22 | ///(2)独立跳转ActionCard样式,支持多个点击Action,需要传入参数 btn_orientation 和 btn_json_list;
23 | ///
24 | public class ActionCardMessageContent
25 | {
26 | ///
27 | /// 透出到会话列表和通知的文案,最长64个字符
28 | ///
29 | public string title { get; set; }
30 | ///
31 | /// 消息内容,支持markdown,语法参考标准markdown语法。建议1000个字符以内
32 | ///
33 | public string markdown { get; set; }
34 | ///
35 | /// 使用整体跳转ActionCard样式时的标题,必须与single_url同时设置,最长20个字符
36 | ///
37 | public string single_title { get; set; }
38 | ///
39 | /// 消息点击链接地址,当发送消息为小程序时支持小程序跳转链接,最长500个字符
40 | ///
41 | public string single_url { get; set; }
42 | ///
43 | /// 使用独立跳转ActionCard样式时的按钮排列方式,竖直排列(0),横向排列(1);必须与btn_json_list同时设置
44 | ///
45 | public string btn_orientation { get; set; }
46 | ///
47 | /// 使用独立跳转ActionCard样式时的按钮列表;必须与btn_orientation同时设置
48 | ///
49 | public ActionCardMessageContent_btn_json_list btn_json_list { get; set; }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Message/MessageHelper.cs:
--------------------------------------------------------------------------------
1 | using DingTalkSDK.DingDingException;
2 | using DingTalkSDK.Util;
3 | using MongoDB.Bson;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | namespace DingTalkSDK.Message
9 | {
10 | ///
11 | /// 消息通知
12 | ///
13 | public class MessageHelper
14 | {
15 | ///
16 | /// 发送工作通知消息
17 | ///
18 | /// accessToken
19 | /// 应用agentId
20 | /// 是否发送给企业全部用户
21 | /// 消息内容,消息类型和样例参考“消息类型与数据格式”。最长不超过2048个字节
22 | /// 接收者的用户userid列表,最大列表长度:100
23 | /// 接收者的部门id列表,最大列表长度:20, 接收者是部门id下(包括子部门下)的所有用户
24 | /// 消息task_id
25 | public static string SendCorpconversation(String accessToken, string agent_id,Boolean to_all_user, IMessage msg,string userid_list,string dept_id_list)
26 | {
27 | if (String.IsNullOrWhiteSpace(accessToken))
28 | {
29 | throw new ArgumentException("accessToken 不能为空");
30 | }
31 | if (String.IsNullOrWhiteSpace(agent_id))
32 | {
33 | throw new ArgumentException("应用agentId 不能为空");
34 | }
35 |
36 | String url = Env.OAPI_HOST + "/topapi/message/corpconversation/asyncsend_v2?" +
37 | "access_token=" + accessToken;
38 | #region 创建参数
39 | BsonDocument args = new BsonDocument();
40 | args["agent_id"] = agent_id;
41 | args["userid_list"] = userid_list;
42 | args["dept_id_list"] = dept_id_list;
43 | args["to_all_user"] = to_all_user;
44 | args["msg"] = msg;
45 | #endregion
46 | BsonDocument response = HttpHelper.httpPost(url, args);
47 | if (HttpHelper.CheckResponseOk(response))
48 | {
49 | return response["task_id"].ToString();
50 | }
51 | else
52 | {
53 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Department/Department.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DingTalkSDK.Department
8 | {
9 | public class Department
10 | {
11 | public String lang = "zh_CN";
12 | ///
13 | /// 部门id,创建部门的时候不用填写
14 | ///
15 | public long id;
16 | ///
17 | /// 部门名称。长度限制为1~64个字符。不允许包含字符‘-’‘,’以及‘,’。
18 | ///
19 | public String name;
20 | ///
21 | /// 父部门id。根部门id为1,如果创建的是根部门,则不传这个参数
22 | ///
23 | public String parentid;
24 | ///
25 | /// 在父部门中的次序值,order值小的排序靠前
26 | ///
27 | public string order;
28 | ///
29 | /// 是否创建一个关联此部门的企业群,默认为false
30 | ///
31 | public bool createDeptGroup = false;
32 |
33 | ///
34 | /// 是否隐藏部门,true表示隐藏,false表示显示,默认为false
35 | ///
36 | public bool deptHiding = false;
37 |
38 | ///
39 | /// 可以查看指定隐藏部门的其他部门列表,如果部门隐藏,则此值生效,取值为其他的部门id组成的字符串,使用“|”符号进行分割。总数不能超过200
40 | ///
41 | public string deptPerimits;
42 | ///
43 | /// 可以查看指定隐藏部门的其他人员列表,如果部门隐藏,则此值生效,取值为其他的人员userid组成的的字符串,使用“|”符号进行分割。总数不能超过200
44 | ///
45 | public string userPerimits;
46 |
47 | ///
48 | /// 是否本部门的员工仅可见员工自己,为true时,本部门员工默认只能看到员工自己,默认为false
49 | ///
50 | public bool outerDept = false;
51 | ///
52 | /// 本部门的员工仅可见员工自己为true时,可以配置额外可见部门,值为部门id组成的的字符串,使用“|”符号进行分割。总数不能超过200
53 | ///
54 | public string outerPermitDepts;
55 | ///
56 | /// 本部门的员工仅可见员工自己为true时,可以配置额外可见人员,值为userid组成的的字符串,使用“|”符号进行分割。总数不能超过200
57 | ///
58 | public string outerPermitUsers;
59 | ///
60 | /// 部门标识字段,开发者可用该字段来唯一标识一个部门,并与钉钉外部通讯录里的部门做映射
61 | ///
62 | public string sourceIdentifier;
63 | public override string ToString()
64 | {
65 | return "Department[id:" + id + " Name:" + name + " Parentid:" + parentid + "]";
66 | }
67 |
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/User/User.cs:
--------------------------------------------------------------------------------
1 | using MongoDB.Bson;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DingTalkSDK.User
9 | {
10 | public class User
11 | {
12 | ///
13 | /// 员工唯一标识ID(不可修改),企业内必须唯一。长度为1~64个字符,如果不传,服务器将自动生成一个userid
14 | ///
15 | public String userid;
16 | ///
17 | /// 成员名称。长度为1~64个字符
18 | ///
19 | public String name;
20 | ///
21 | /// 在对应的部门中的排序, Map结构的json字符串, key是部门的Id, value是人员在这个部门的排序值
22 | ///
23 | public BsonDocument orderInDepts;
24 | ///
25 | /// 数组类型,数组里面值为整型,成员所属部门id列表
26 | ///
27 | public List department;
28 | ///
29 | /// 职位信息。长度为0~64个字符
30 | ///
31 | public String position;
32 | ///
33 | /// 手机号码,企业内必须唯一,不可重复
34 | ///
35 | public String mobile;
36 | ///
37 | /// 电话号码
38 | ///
39 | public String tel;
40 | ///
41 | /// 邮箱
42 | ///
43 | public String email;
44 | ///
45 | /// 工作地
46 | ///
47 | public String workPlace;
48 | ///
49 | /// 员工工号。对应显示到OA后台和客户端个人资料的工号栏目。长度为0~64个字符
50 | ///
51 | public String jobnumber;
52 | ///
53 | /// 企业邮箱
54 | ///
55 | public String orgEmail;
56 | ///
57 | /// 是否号码隐藏, true表示隐藏, false表示不隐藏。隐藏手机号后,手机号在个人资料页隐藏,但仍可对其发DING、发起钉钉免费商务电话。
58 | ///
59 | public bool isHide;
60 | ///
61 | /// 是否高管模式,true表示是,false表示不是。开启后,手机号码对所有员工隐藏。普通员工无法对其发DING、发起钉钉免费商务电话。高管之间不受影响。
62 | ///
63 | public bool isSenior;
64 | ///
65 | /// 扩展属性,可以设置多种属性(但手机上最多只能显示10个扩展属性,具体显示哪些属性,请到OA管理后台->设置->通讯录信息设置和OA管理后台->设置->手机端显示信息设置)
66 | ///
67 | public BsonDocument extattr;
68 |
69 | public User()
70 | {
71 | }
72 |
73 | public User(String userid, String name)
74 | {
75 | this.userid = userid;
76 | this.name = name;
77 | }
78 | public override string ToString()
79 | {
80 | //List users;
81 | return "User[userid:" + userid + ", name:" + name + ", department:" + department +
82 | ", position:" + position + ", mobile:" + mobile + ", email:" + email +
83 | ", extattr:" + extattr + "]";
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Message/OAMessage/OAMessageContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace DingTalkSDK.Message.OAMessage
6 | {
7 | public class OAMessageContent_head
8 | {
9 | ///
10 | /// 消息头部的背景颜色。长度限制为8个英文字符,其中前2为表示透明度,后6位表示颜色值。不要添加0x
11 | ///
12 | public string bgcolor { get;set;}
13 | ///
14 | /// 消息的头部标题 (向普通会话发送时有效,向企业会话发送时会被替换为微应用的名字),长度限制为最多10个字符
15 | ///
16 | public string text { get; set; }
17 | }
18 | public class OAMessageContent_body_form
19 | {
20 | ///
21 | /// 消息体的关键字
22 | ///
23 | public string key { get; set; }
24 | ///
25 | /// 消息体的关键字对应的值
26 | ///
27 | public string value { get; set; }
28 | }
29 | public class OAMessageContent_body_rich
30 | {
31 | ///
32 | /// 单行富文本信息的数目
33 | ///
34 | public string num { get; set; }
35 | ///
36 | /// 单行富文本信息的单位
37 | ///
38 | public string unit { get; set; }
39 | }
40 | public class OAMessageContent_body
41 | {
42 | ///
43 | /// 消息体的标题,建议50个字符以内
44 | ///
45 | public string title { get; set; }
46 | ///
47 | /// 消息体的表单,最多显示6个,超过会被隐藏
48 | ///
49 | public List form { get; set; }
50 | ///
51 | /// 单行富文本信息
52 | ///
53 | public OAMessageContent_body_rich rich { get; set; }
54 | ///
55 | /// 消息体的内容,最多显示3行
56 | ///
57 | public string content { get; set; }
58 | ///
59 | /// 消息体中的图片,支持图片资源@mediaId
60 | ///
61 | public string image { get; set; }
62 | ///
63 | /// 自定义的附件数目。此数字仅供显示,钉钉不作验证
64 | ///
65 | public string file_count { get; set; }
66 | ///
67 | /// 自定义的作者名字
68 | ///
69 | public string author { get; set; }
70 | }
71 | ///
72 | /// OA类消息的内容
73 | ///
74 | public class OAMessageContent
75 | {
76 | ///
77 | /// 消息点击链接地址,当发送消息为小程序时支持小程序跳转链接
78 | ///
79 | public string message_url { get;set;}
80 | ///
81 | /// PC端点击消息时跳转到的地址
82 | ///
83 | public string pc_message_url { get; set; }
84 | ///
85 | /// 消息头部内容
86 | ///
87 | public OAMessageContent_head head { get; set; }
88 | ///
89 | /// 消息体
90 | ///
91 | public OAMessageContent_body body { get; set; }
92 |
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Util/HttpHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using MongoDB.Bson;
5 | using Newtonsoft.Json.Bson;
6 |
7 | namespace DingTalkSDK.Util
8 | {
9 | internal class HttpHelper
10 | {
11 | private static CookieContainer cookie = new CookieContainer();
12 |
13 | ///
14 | /// 使用GET从url获取数据
15 | ///
16 | /// 获取数据的url
17 | /// 附带的data,可以不传,直接在url里面拼接参数,如果传了,url里面的参数就会被忽略
18 | /// 格式化的BsonDocument
19 | public static BsonDocument httpGet(String url, BsonDocument data = null)
20 | {
21 | WebClient client = new WebClient();
22 | client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
23 | if (data != null)
24 | {
25 | foreach (var item in data)
26 | {
27 | client.QueryString.Add(item.Name, item.Value.ToString());
28 | }
29 | }
30 | var respostData = client.DownloadData(url);
31 | return BsonDocument.Parse(System.Text.UTF8Encoding.UTF8.GetString(respostData));
32 | }
33 |
34 | ///
35 | /// 使用GET从url获取数据
36 | ///
37 | /// 获取数据的url
38 | /// 附带的data,可以不传,直接在url里面拼接参数,如果传了,url里面的参数就会被忽略
39 | /// 格式化的BsonDocument
40 | public static async Task httpGetAsync(String url, BsonDocument data = null)
41 | {
42 | WebClient client = new WebClient();
43 | client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
44 | if (data != null)
45 | {
46 | foreach (var item in data)
47 | {
48 | client.QueryString.Add(item.Name, item.Value.ToString());
49 | }
50 | }
51 |
52 | var respostData = await client.DownloadDataTaskAsync(url);
53 | return BsonDocument.Parse(System.Text.UTF8Encoding.UTF8.GetString(respostData));
54 | }
55 |
56 | ///
57 | /// 使用POST从url获取数据
58 | ///
59 | /// 获取数据的url
60 | /// 附带的data
61 | /// 格式化的BsonDocument
62 | public static BsonDocument httpPost(String url, BsonDocument data)
63 | {
64 | WebClient client = new WebClient();
65 | client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
66 | var postdata = System.Text.UTF8Encoding.UTF8.GetBytes((data.ToString()));
67 | var respostData = client.UploadData(url, postdata);
68 | return BsonDocument.Parse(System.Text.UTF8Encoding.UTF8.GetString(respostData));
69 | }
70 |
71 | ///
72 | /// 使用POST从url获取数据
73 | ///
74 | /// 获取数据的url
75 | /// 附带的data
76 | /// 格式化的BsonDocument
77 | public static async Task httpPostAsync(String url, BsonDocument data)
78 | {
79 | WebClient client = new WebClient();
80 | client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
81 | var postdata = System.Text.UTF8Encoding.UTF8.GetBytes((data.ToString()));
82 | var respostData = await client.UploadDataTaskAsync(url, postdata);
83 | return BsonDocument.Parse(System.Text.UTF8Encoding.UTF8.GetString(respostData));
84 | }
85 | ///
86 | /// 检查请求是否执行成功
87 | ///
88 | ///
89 | ///
90 | public static bool CheckResponseOk(BsonDocument response)
91 | {
92 | if (response.Contains("errcode") && response["errcode"].ToInt64() == 0)
93 | {
94 | return true;
95 | }
96 | else
97 | {
98 | return false;
99 | }
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 |
56 | # StyleCop
57 | StyleCopReport.xml
58 |
59 | # Files built by Visual Studio
60 | *_i.c
61 | *_p.c
62 | *_i.h
63 | *.ilk
64 | *.meta
65 | *.obj
66 | *.iobj
67 | *.pch
68 | *.pdb
69 | *.ipdb
70 | *.pgc
71 | *.pgd
72 | *.rsp
73 | *.sbr
74 | *.tlb
75 | *.tli
76 | *.tlh
77 | *.tmp
78 | *.tmp_proj
79 | *.log
80 | *.vspscc
81 | *.vssscc
82 | .builds
83 | *.pidb
84 | *.svclog
85 | *.scc
86 |
87 | # Chutzpah Test files
88 | _Chutzpah*
89 |
90 | # Visual C++ cache files
91 | ipch/
92 | *.aps
93 | *.ncb
94 | *.opendb
95 | *.opensdf
96 | *.sdf
97 | *.cachefile
98 | *.VC.db
99 | *.VC.VC.opendb
100 |
101 | # Visual Studio profiler
102 | *.psess
103 | *.vsp
104 | *.vspx
105 | *.sap
106 |
107 | # Visual Studio Trace Files
108 | *.e2e
109 |
110 | # TFS 2012 Local Workspace
111 | $tf/
112 |
113 | # Guidance Automation Toolkit
114 | *.gpState
115 |
116 | # ReSharper is a .NET coding add-in
117 | _ReSharper*/
118 | *.[Rr]e[Ss]harper
119 | *.DotSettings.user
120 |
121 | # JustCode is a .NET coding add-in
122 | .JustCode
123 |
124 | # TeamCity is a build add-in
125 | _TeamCity*
126 |
127 | # DotCover is a Code Coverage Tool
128 | *.dotCover
129 |
130 | # AxoCover is a Code Coverage Tool
131 | .axoCover/*
132 | !.axoCover/settings.json
133 |
134 | # Visual Studio code coverage results
135 | *.coverage
136 | *.coveragexml
137 |
138 | # NCrunch
139 | _NCrunch_*
140 | .*crunch*.local.xml
141 | nCrunchTemp_*
142 |
143 | # MightyMoose
144 | *.mm.*
145 | AutoTest.Net/
146 |
147 | # Web workbench (sass)
148 | .sass-cache/
149 |
150 | # Installshield output folder
151 | [Ee]xpress/
152 |
153 | # DocProject is a documentation generator add-in
154 | DocProject/buildhelp/
155 | DocProject/Help/*.HxT
156 | DocProject/Help/*.HxC
157 | DocProject/Help/*.hhc
158 | DocProject/Help/*.hhk
159 | DocProject/Help/*.hhp
160 | DocProject/Help/Html2
161 | DocProject/Help/html
162 |
163 | # Click-Once directory
164 | publish/
165 |
166 | # Publish Web Output
167 | *.[Pp]ublish.xml
168 | *.azurePubxml
169 | # Note: Comment the next line if you want to checkin your web deploy settings,
170 | # but database connection strings (with potential passwords) will be unencrypted
171 | *.pubxml
172 | *.publishproj
173 |
174 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
175 | # checkin your Azure Web App publish settings, but sensitive information contained
176 | # in these scripts will be unencrypted
177 | PublishScripts/
178 |
179 | # NuGet Packages
180 | *.nupkg
181 | # The packages folder can be ignored because of Package Restore
182 | **/[Pp]ackages/*
183 | # except build/, which is used as an MSBuild target.
184 | !**/[Pp]ackages/build/
185 | # Uncomment if necessary however generally it will be regenerated when needed
186 | #!**/[Pp]ackages/repositories.config
187 | # NuGet v3's project.json files produces more ignorable files
188 | *.nuget.props
189 | *.nuget.targets
190 |
191 | # Microsoft Azure Build Output
192 | csx/
193 | *.build.csdef
194 |
195 | # Microsoft Azure Emulator
196 | ecf/
197 | rcf/
198 |
199 | # Windows Store app package directories and files
200 | AppPackages/
201 | BundleArtifacts/
202 | Package.StoreAssociation.xml
203 | _pkginfo.txt
204 | *.appx
205 |
206 | # Visual Studio cache files
207 | # files ending in .cache can be ignored
208 | *.[Cc]ache
209 | # but keep track of directories ending in .cache
210 | !*.[Cc]ache/
211 |
212 | # Others
213 | ClientBin/
214 | ~$*
215 | *~
216 | *.dbmdl
217 | *.dbproj.schemaview
218 | *.jfm
219 | *.pfx
220 | *.publishsettings
221 | orleans.codegen.cs
222 |
223 | # Including strong name files can present a security risk
224 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
225 | #*.snk
226 |
227 | # Since there are multiple workflows, uncomment next line to ignore bower_components
228 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
229 | #bower_components/
230 |
231 | # RIA/Silverlight projects
232 | Generated_Code/
233 |
234 | # Backup & report files from converting an old project file
235 | # to a newer Visual Studio version. Backup files are not needed,
236 | # because we have git ;-)
237 | _UpgradeReport_Files/
238 | Backup*/
239 | UpgradeLog*.XML
240 | UpgradeLog*.htm
241 | ServiceFabricBackup/
242 | *.rptproj.bak
243 |
244 | # SQL Server files
245 | *.mdf
246 | *.ldf
247 | *.ndf
248 |
249 | # Business Intelligence projects
250 | *.rdl.data
251 | *.bim.layout
252 | *.bim_*.settings
253 | *.rptproj.rsuser
254 |
255 | # Microsoft Fakes
256 | FakesAssemblies/
257 |
258 | # GhostDoc plugin setting file
259 | *.GhostDoc.xml
260 |
261 | # Node.js Tools for Visual Studio
262 | .ntvs_analysis.dat
263 | node_modules/
264 |
265 | # Visual Studio 6 build log
266 | *.plg
267 |
268 | # Visual Studio 6 workspace options file
269 | *.opt
270 |
271 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
272 | *.vbw
273 |
274 | # Visual Studio LightSwitch build output
275 | **/*.HTMLClient/GeneratedArtifacts
276 | **/*.DesktopClient/GeneratedArtifacts
277 | **/*.DesktopClient/ModelManifest.xml
278 | **/*.Server/GeneratedArtifacts
279 | **/*.Server/ModelManifest.xml
280 | _Pvt_Extensions
281 |
282 | # Paket dependency manager
283 | .paket/paket.exe
284 | paket-files/
285 |
286 | # FAKE - F# Make
287 | .fake/
288 |
289 | # JetBrains Rider
290 | .idea/
291 | *.sln.iml
292 |
293 | # CodeRush
294 | .cr/
295 |
296 | # Python Tools for Visual Studio (PTVS)
297 | __pycache__/
298 | *.pyc
299 |
300 | # Cake - Uncomment if you are using it
301 | # tools/**
302 | # !tools/packages.config
303 |
304 | # Tabs Studio
305 | *.tss
306 |
307 | # Telerik's JustMock configuration file
308 | *.jmconfig
309 |
310 | # BizTalk build output
311 | *.btp.cs
312 | *.btm.cs
313 | *.odx.cs
314 | *.xsd.cs
315 |
316 | # OpenCover UI analysis results
317 | OpenCover/
318 |
319 | # Azure Stream Analytics local run output
320 | ASALocalRun/
321 |
322 | # MSBuild Binary and Structured Log
323 | *.binlog
324 |
325 | # NVidia Nsight GPU debugger configuration file
326 | *.nvuser
327 |
328 | # MFractors (Xamarin productivity tool) working folder
329 | .mfractor/
330 |
331 | # Local History for Visual Studio
332 | .localhistory/
333 |
--------------------------------------------------------------------------------
/Department/DepartmentHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using DingTalkSDK.DingDingException;
5 | using DingTalkSDK.Util;
6 | using MongoDB.Bson;
7 |
8 | namespace DingTalkSDK.Department
9 | {
10 | public class DepartmentHelper
11 | {
12 | ///
13 | /// 创建部门
14 | ///
15 | /// token
16 | /// 部门名称
17 | /// 父部门名称
18 | ///
19 | /// 创建成功的部门ID
20 | public static long CreateDepartment(String accessToken, Department department)
21 | {
22 |
23 | if (String.IsNullOrWhiteSpace(accessToken))
24 | {
25 | throw new ArgumentException("accessToken 不能为空");
26 | }
27 | if (String.IsNullOrWhiteSpace(department.name))
28 | {
29 | throw new ArgumentException("部门名称不能为空");
30 | }
31 | if (String.IsNullOrWhiteSpace(department.parentid))
32 | {
33 | throw new ArgumentException("父部门id不能为空");
34 | }
35 |
36 | String url = Env.OAPI_HOST + "/department/create?" +
37 | "access_token=" + accessToken;
38 |
39 | #region 创建参数
40 | BsonDocument args = new BsonDocument();
41 | args["name"] = department.name;
42 | args["parentid"] = department.parentid;
43 | if (!string.IsNullOrWhiteSpace(department.order))
44 | {
45 | args["order"] = department.order;
46 | }
47 | args["createDeptGroup"] = department.createDeptGroup;
48 | args["deptHiding"] = department.deptHiding;
49 | if (!string.IsNullOrWhiteSpace(department.deptPerimits))
50 | {
51 | args["deptPerimits"] = department.deptPerimits;
52 | }
53 | if (!string.IsNullOrWhiteSpace(department.userPerimits))
54 | {
55 | args["userPerimits"] = department.userPerimits;
56 | }
57 | args["outerDept"] = department.outerDept;
58 | if (!string.IsNullOrWhiteSpace(department.outerPermitDepts))
59 | {
60 | args["outerPermitDepts"] = department.outerPermitDepts;
61 | }
62 | if (!string.IsNullOrWhiteSpace(department.outerPermitUsers))
63 | {
64 | args["outerPermitUsers"] = department.outerPermitUsers;
65 | }
66 | if (!string.IsNullOrWhiteSpace(department.sourceIdentifier))
67 | {
68 | args["sourceIdentifier"] = department.sourceIdentifier;
69 | }
70 | #endregion
71 |
72 | BsonDocument response = HttpHelper.httpPost(url, args);
73 | if (HttpHelper.CheckResponseOk(response))
74 | {
75 | return response["id"].ToInt64();
76 | }
77 | else
78 | {
79 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
80 | }
81 | }
82 | ///
83 | /// 创建部门
84 | ///
85 | /// token
86 | /// 部门名称
87 | /// 父部门名称
88 | ///
89 | /// 创建成功的部门ID
90 | public static async Task CreateDepartmentAsync(String accessToken, Department department)
91 | {
92 |
93 | if (String.IsNullOrWhiteSpace(accessToken))
94 | {
95 | throw new ArgumentException("accessToken 不能为空");
96 | }
97 | if (String.IsNullOrWhiteSpace(department.name))
98 | {
99 | throw new ArgumentException("部门名称不能为空");
100 | }
101 | if (String.IsNullOrWhiteSpace(department.parentid))
102 | {
103 | throw new ArgumentException("父部门id不能为空");
104 | }
105 |
106 | String url = Env.OAPI_HOST + "/department/create?" +
107 | "access_token=" + accessToken;
108 |
109 | #region 创建参数
110 | BsonDocument args = new BsonDocument();
111 | args["name"] = department.name;
112 | args["parentid"] = department.parentid;
113 | if (!string.IsNullOrWhiteSpace(department.order))
114 | {
115 | args["order"] = department.order;
116 | }
117 | args["createDeptGroup"] = department.createDeptGroup;
118 | args["deptHiding"] = department.deptHiding;
119 | if (!string.IsNullOrWhiteSpace(department.deptPerimits))
120 | {
121 | args["deptPerimits"] = department.deptPerimits;
122 | }
123 | if (!string.IsNullOrWhiteSpace(department.userPerimits))
124 | {
125 | args["userPerimits"] = department.userPerimits;
126 | }
127 | args["outerDept"] = department.outerDept;
128 | if (!string.IsNullOrWhiteSpace(department.outerPermitDepts))
129 | {
130 | args["outerPermitDepts"] = department.outerPermitDepts;
131 | }
132 | if (!string.IsNullOrWhiteSpace(department.outerPermitUsers))
133 | {
134 | args["outerPermitUsers"] = department.outerPermitUsers;
135 | }
136 | if (!string.IsNullOrWhiteSpace(department.sourceIdentifier))
137 | {
138 | args["sourceIdentifier"] = department.sourceIdentifier;
139 | }
140 | #endregion
141 |
142 | BsonDocument response = await HttpHelper.httpPostAsync(url, args);
143 | if (HttpHelper.CheckResponseOk(response))
144 | {
145 | return response["id"].ToInt64();
146 | }
147 | else
148 | {
149 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
150 | }
151 | }
152 | ///
153 | /// 列出所有的部门
154 | ///
155 | /// accessToken
156 | /// 部门列表
157 | public static List ListDepartments(String accessToken)
158 | {
159 | if (String.IsNullOrWhiteSpace(accessToken))
160 | {
161 | throw new ArgumentException("accessToken 不能为空");
162 | }
163 | String url = Env.OAPI_HOST + "/department/list?" +
164 | "access_token=" + accessToken;
165 | BsonDocument response = HttpHelper.httpGet(url);
166 | if (HttpHelper.CheckResponseOk(response))
167 | {
168 | BsonArray arr = response["department"].AsBsonArray;
169 | List list = new List();
170 | for (int i = 0; i < arr.Count; i++)
171 | {
172 | list.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(arr[i].ToString()));
173 | }
174 | return list;
175 | }
176 | else
177 | {
178 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
179 | }
180 | }
181 |
182 | ///
183 | /// 列出所有的部门
184 | ///
185 | /// accessToken
186 | /// 部门列表
187 | public static async Task> ListDepartmentsAsync(String accessToken)
188 | {
189 | if (String.IsNullOrWhiteSpace(accessToken))
190 | {
191 | throw new ArgumentException("accessToken 不能为空");
192 | }
193 | String url = Env.OAPI_HOST + "/department/list?" +
194 | "access_token=" + accessToken;
195 | BsonDocument response = await HttpHelper.httpGetAsync(url);
196 | if (HttpHelper.CheckResponseOk(response))
197 | {
198 | BsonArray arr = response["department"].AsBsonArray;
199 | List list = new List();
200 | for (int i = 0; i < arr.Count; i++)
201 | {
202 | list.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(arr[i].ToString()));
203 | }
204 | return list;
205 | }
206 | else
207 | {
208 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
209 | }
210 | }
211 | ///
212 | /// 删除部门
213 | ///
214 | /// accessontoken
215 | /// 部门id
216 | /// 是否删除成功
217 | public static bool DeleteDepartment(String accessToken, long id)
218 | {
219 | if (String.IsNullOrWhiteSpace(accessToken))
220 | {
221 | throw new ArgumentException("accessToken 不能为空");
222 | }
223 | String url = Env.OAPI_HOST + "/department/delete?" +
224 | "access_token=" + accessToken + "&id=" + id;
225 | BsonDocument response = HttpHelper.httpGet(url);
226 | if (!HttpHelper.CheckResponseOk(response))
227 | {
228 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
229 | }
230 | return true;
231 | }
232 | ///
233 | /// 删除部门
234 | ///
235 | /// accessontoken
236 | /// 部门id
237 | /// 是否删除成功
238 | public static async Task DeleteDepartmentAsync(String accessToken, long id)
239 | {
240 | if (String.IsNullOrWhiteSpace(accessToken))
241 | {
242 | throw new ArgumentException("accessToken 不能为空");
243 | }
244 | String url = Env.OAPI_HOST + "/department/delete?" +
245 | "access_token=" + accessToken + "&id=" + id;
246 | BsonDocument response = await HttpHelper.httpGetAsync(url);
247 | if (!HttpHelper.CheckResponseOk(response))
248 | {
249 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
250 | }
251 | return true;
252 | }
253 | ///
254 | /// 更新部门
255 | ///
256 | /// accessToken
257 | /// 部门实体
258 | /// 更新的部门id
259 | public static long UpdateDepartment(String accessToken, Department department)
260 | {
261 | if (String.IsNullOrWhiteSpace(accessToken))
262 | {
263 | throw new ArgumentException("accessToken 不能为空");
264 | }
265 | String url = Env.OAPI_HOST + "/department/update?" +
266 | "access_token=" + accessToken;
267 | #region 创建参数
268 | BsonDocument args = new BsonDocument();
269 | args["name"] = department.name;
270 | args["parentid"] = department.parentid;
271 | if (!string.IsNullOrWhiteSpace(department.order))
272 | {
273 | args["order"] = department.order;
274 | }
275 | args["createDeptGroup"] = department.createDeptGroup;
276 | args["deptHiding"] = department.deptHiding;
277 | if (!string.IsNullOrWhiteSpace(department.deptPerimits))
278 | {
279 | args["deptPerimits"] = department.deptPerimits;
280 | }
281 | if (!string.IsNullOrWhiteSpace(department.userPerimits))
282 | {
283 | args["userPerimits"] = department.userPerimits;
284 | }
285 | args["outerDept"] = department.outerDept;
286 | if (!string.IsNullOrWhiteSpace(department.outerPermitDepts))
287 | {
288 | args["outerPermitDepts"] = department.outerPermitDepts;
289 | }
290 | if (!string.IsNullOrWhiteSpace(department.outerPermitUsers))
291 | {
292 | args["outerPermitUsers"] = department.outerPermitUsers;
293 | }
294 | if (!string.IsNullOrWhiteSpace(department.sourceIdentifier))
295 | {
296 | args["sourceIdentifier"] = department.sourceIdentifier;
297 | }
298 | #endregion
299 | BsonDocument response = HttpHelper.httpPost(url, args);
300 | if (HttpHelper.CheckResponseOk(response))
301 | {
302 | return response["id"].ToInt64();
303 | }
304 | else
305 | {
306 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
307 | }
308 | }
309 | ///
310 | /// 更新部门
311 | ///
312 | /// accessToken
313 | /// 部门实体
314 | /// 更新的部门id
315 | public static async Task UpdateDepartmentAsync(String accessToken, Department department)
316 | {
317 | if (String.IsNullOrWhiteSpace(accessToken))
318 | {
319 | throw new ArgumentException("accessToken 不能为空");
320 | }
321 | String url = Env.OAPI_HOST + "/department/update?" +
322 | "access_token=" + accessToken;
323 | #region 创建参数
324 | BsonDocument args = new BsonDocument();
325 | args["name"] = department.name;
326 | args["parentid"] = department.parentid;
327 | if (!string.IsNullOrWhiteSpace(department.order))
328 | {
329 | args["order"] = department.order;
330 | }
331 | args["createDeptGroup"] = department.createDeptGroup;
332 | args["deptHiding"] = department.deptHiding;
333 | if (!string.IsNullOrWhiteSpace(department.deptPerimits))
334 | {
335 | args["deptPerimits"] = department.deptPerimits;
336 | }
337 | if (!string.IsNullOrWhiteSpace(department.userPerimits))
338 | {
339 | args["userPerimits"] = department.userPerimits;
340 | }
341 | args["outerDept"] = department.outerDept;
342 | if (!string.IsNullOrWhiteSpace(department.outerPermitDepts))
343 | {
344 | args["outerPermitDepts"] = department.outerPermitDepts;
345 | }
346 | if (!string.IsNullOrWhiteSpace(department.outerPermitUsers))
347 | {
348 | args["outerPermitUsers"] = department.outerPermitUsers;
349 | }
350 | if (!string.IsNullOrWhiteSpace(department.sourceIdentifier))
351 | {
352 | args["sourceIdentifier"] = department.sourceIdentifier;
353 | }
354 | #endregion
355 | BsonDocument response = await HttpHelper.httpPostAsync(url, args);
356 | if (HttpHelper.CheckResponseOk(response))
357 | {
358 | return response["id"].ToInt64();
359 | }
360 | else
361 | {
362 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
363 | }
364 | }
365 | ///
366 | /// 获取钉钉上某个企业/组织内的人数。
367 | ///
368 | /// accessToken
369 | /// 0:包含未激活钉钉的人员数量,1:不包含未激活钉钉的人员数量
370 | ///
371 | public static long GetOrgUserCount(String accessToken, int onlyActive)
372 | {
373 | String url = Env.OAPI_HOST + "/department/get_org_user_count";
374 | if (String.IsNullOrWhiteSpace(accessToken))
375 | {
376 | throw new ArgumentException("accessToken 不能为空");
377 | }
378 |
379 | if (onlyActive != 0 && onlyActive != 1)
380 | {
381 | throw new ArgumentException("onlyActive,只能是1或者是0。0:包含未激活钉钉的人员数量,1:不包含未激活钉钉的人员数量");
382 | }
383 | BsonDocument args = new BsonDocument();
384 | args["access_token"] = "accessToken";
385 | args["onlyActive"] = onlyActive;
386 | var response = HttpHelper.httpGet(url, args);
387 | if (HttpHelper.CheckResponseOk(response))
388 | {
389 | return response["count"].ToInt64();
390 | }
391 | else
392 | {
393 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
394 | }
395 | }
396 | ///
397 | /// 获取钉钉上某个企业/组织内的人数。
398 | ///
399 | /// accessToken
400 | /// 0:包含未激活钉钉的人员数量,1:不包含未激活钉钉的人员数量
401 | ///
402 | public static async Task GetOrgUserCountAsync(String accessToken, int onlyActive)
403 | {
404 | String url = Env.OAPI_HOST + "/department/get_org_user_count";
405 | if (String.IsNullOrWhiteSpace(accessToken))
406 | {
407 | throw new ArgumentException("accessToken 不能为空");
408 | }
409 |
410 | if (onlyActive != 0 && onlyActive != 1)
411 | {
412 | throw new ArgumentException("onlyActive,只能是1或者是0。0:包含未激活钉钉的人员数量,1:不包含未激活钉钉的人员数量");
413 | }
414 | BsonDocument args = new BsonDocument();
415 | args["access_token"] = "accessToken";
416 | args["onlyActive"] = onlyActive;
417 | var response = await HttpHelper.httpGetAsync(url, args);
418 | if (HttpHelper.CheckResponseOk(response))
419 | {
420 | return response["count"].ToInt64();
421 | }
422 | else
423 | {
424 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
425 | }
426 | }
427 | }
428 | }
429 |
--------------------------------------------------------------------------------
/User/UserHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using DingTalkSDK.DingDingException;
6 | using DingTalkSDK.Util;
7 | using MongoDB.Bson;
8 |
9 | namespace DingTalkSDK.User
10 | {
11 | public class UserHelper
12 | {
13 | ///
14 | ///
15 | /// 创建成员
16 | ///
17 | /// access_token
18 | /// user
19 | /// 创建的用户ID
20 | public static string CreateUser(String accessToken, User user)
21 | {
22 |
23 | if (String.IsNullOrWhiteSpace(accessToken))
24 | {
25 | throw new ArgumentException("accessToken 不能为空");
26 | }
27 | if (String.IsNullOrWhiteSpace(user.name))
28 | {
29 | throw new ArgumentException("name 必须不能为空");
30 | }
31 | if (String.IsNullOrWhiteSpace(user.mobile))
32 | {
33 | throw new ArgumentException("mobile 必须不能为空");
34 | }
35 | if (String.IsNullOrWhiteSpace(user.userid))
36 | {
37 | throw new ArgumentException("userid 必须不能为空");
38 | }
39 | if (user.department.Count == 0)
40 | {
41 | throw new ArgumentException("user 的构造参数 department 必须不能为空");
42 | }
43 |
44 | String url = Env.OAPI_HOST + "/user/create";
45 |
46 | BsonDocument args = new BsonDocument();
47 | args["access_token"] = accessToken;
48 | args["name"] = user.name;
49 | args["mobile"] = user.mobile;
50 | args["userid"] = user.userid;
51 | var deptlist = "[";
52 | foreach (var item in user.department)
53 | {
54 | deptlist += item.ToString() + ",";
55 | }
56 | deptlist = deptlist.Remove(deptlist.Count() - 1) + "]";
57 | args["department"] = deptlist;
58 |
59 | BsonDocument response = HttpHelper.httpPost(url, args);
60 |
61 | if (HttpHelper.CheckResponseOk(response))
62 | {
63 | return response["userid"].ToString();
64 | }
65 | else
66 | {
67 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
68 | }
69 | }
70 | ///
71 | ///
72 | /// 创建成员
73 | ///
74 | /// access_token
75 | /// user
76 | /// 创建的用户ID
77 | public static async Task CreateUserAsync(String accessToken, User user)
78 | {
79 |
80 | if (String.IsNullOrWhiteSpace(accessToken))
81 | {
82 | throw new ArgumentException("accessToken 不能为空");
83 | }
84 | if (String.IsNullOrWhiteSpace(user.name))
85 | {
86 | throw new ArgumentException("name 必须不能为空");
87 | }
88 | if (String.IsNullOrWhiteSpace(user.mobile))
89 | {
90 | throw new ArgumentException("mobile 必须不能为空");
91 | }
92 | if (String.IsNullOrWhiteSpace(user.userid))
93 | {
94 | throw new ArgumentException("userid 必须不能为空");
95 | }
96 | if (user.department.Count == 0)
97 | {
98 | throw new ArgumentException("user 的构造参数 department 必须不能为空");
99 | }
100 |
101 | String url = Env.OAPI_HOST + "/user/create";
102 |
103 | BsonDocument args = new BsonDocument();
104 | args["access_token"] = accessToken;
105 | args["name"] = user.name;
106 | args["mobile"] = user.mobile;
107 | args["userid"] = user.userid;
108 | var deptlist = "[";
109 | foreach (var item in user.department)
110 | {
111 | deptlist += item.ToString() + ",";
112 | }
113 | deptlist = deptlist.Remove(deptlist.Count() - 1) + "]";
114 | args["department"] = deptlist;
115 |
116 | var response = await HttpHelper.httpPostAsync(url, args);
117 | if (HttpHelper.CheckResponseOk(response))
118 | {
119 | return response["userid"].ToString();
120 | }
121 | else
122 | {
123 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
124 | }
125 | }
126 |
127 | ///
128 | /// 更新成员
129 | ///
130 | /// access_token
131 | /// user
132 | /// 是否更新成功
133 | public static bool UpdateUser(String accessToken, User user)
134 | {
135 |
136 | if (String.IsNullOrWhiteSpace(accessToken))
137 | {
138 | throw new ArgumentException("accessToken 不能为空");
139 | }
140 | if (String.IsNullOrWhiteSpace(user.userid))
141 | {
142 | throw new ArgumentException("userid 必须不能为空");
143 | }
144 |
145 | String url = Env.OAPI_HOST + "/user/update";
146 | BsonDocument args = new BsonDocument();
147 | args["access_token"] = accessToken;
148 | args["name"] = user.name;
149 | args["mobile"] = user.mobile;
150 | args["userid"] = user.userid;
151 | var deptlist = "[";
152 | foreach (var item in user.department)
153 | {
154 | deptlist += item.ToString() + ",";
155 | }
156 | deptlist = deptlist.Remove(deptlist.Count() - 1) + "]";
157 | args["department"] = deptlist;
158 |
159 | BsonDocument response = HttpHelper.httpPost(url, args);
160 |
161 | if (!HttpHelper.CheckResponseOk(response))
162 | {
163 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
164 | }
165 | return true;
166 | }
167 |
168 | ///
169 | /// 更新成员
170 | ///
171 | /// access_token
172 | /// user
173 | /// 是否更新成功
174 | public static async Task UpdateUserAsync(String accessToken, User user)
175 | {
176 | if (String.IsNullOrWhiteSpace(accessToken))
177 | {
178 | throw new ArgumentException("accessToken 不能为空");
179 | }
180 | if (String.IsNullOrWhiteSpace(user.userid))
181 | {
182 | throw new ArgumentException("userid 必须不能为空");
183 | }
184 |
185 | String url = Env.OAPI_HOST + "/user/update";
186 | BsonDocument args = new BsonDocument();
187 | args["access_token"] = accessToken;
188 | args["name"] = user.name;
189 | args["mobile"] = user.mobile;
190 | args["userid"] = user.userid;
191 | var deptlist = "[";
192 | foreach (var item in user.department)
193 | {
194 | deptlist += item.ToString() + ",";
195 | }
196 | deptlist = deptlist.Remove(deptlist.Count() - 1) + "]";
197 | args["department"] = deptlist;
198 |
199 | BsonDocument response = await HttpHelper.httpPostAsync(url, args);
200 |
201 | if (!HttpHelper.CheckResponseOk(response))
202 | {
203 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
204 | }
205 | return true;
206 | }
207 | ///
208 | /// 删除
209 | ///
210 | /// access_token
211 | /// userid
212 | /// 是否删除成功
213 | public static bool DeleteUser(String accessToken, String userid)
214 | {
215 | if (String.IsNullOrWhiteSpace(accessToken))
216 | {
217 | throw new ArgumentException("accessToken 不能为空");
218 | }
219 | if (String.IsNullOrWhiteSpace(userid))
220 | {
221 | throw new ArgumentException("userid 必须不能为空");
222 | }
223 | String url = Env.OAPI_HOST + "/user/delete?" +
224 | "access_token=" + accessToken + "&userid=" + userid;
225 | BsonDocument response = HttpHelper.httpGet(url);
226 |
227 | if (!HttpHelper.CheckResponseOk(response))
228 | {
229 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
230 | }
231 | return true;
232 | }
233 | ///
234 | /// 删除
235 | ///
236 | /// access_token
237 | /// userid
238 | /// 是否删除成功
239 | public static async Task DeleteUserAsync(String accessToken, String userid)
240 | {
241 | if (String.IsNullOrWhiteSpace(accessToken))
242 | {
243 | throw new ArgumentException("accessToken 不能为空");
244 | }
245 | if (String.IsNullOrWhiteSpace(userid))
246 | {
247 | throw new ArgumentException("userid 必须不能为空");
248 | }
249 | String url = Env.OAPI_HOST + "/user/delete?" +
250 | "access_token=" + accessToken + "&userid=" + userid;
251 | BsonDocument response = await HttpHelper.httpGetAsync(url);
252 |
253 | if (!HttpHelper.CheckResponseOk(response))
254 | {
255 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
256 | }
257 | return true;
258 | }
259 |
260 |
261 | ///
262 | /// 获取用户信息
263 | ///
264 | /// access_token
265 | /// userid
266 | public static User GetUser(String accessToken, String userid)
267 | {
268 | if (String.IsNullOrWhiteSpace(accessToken))
269 | {
270 | throw new ArgumentException("accessToken 不能为空");
271 | }
272 | if (String.IsNullOrWhiteSpace(userid))
273 | {
274 | throw new ArgumentException("userid 不能为空");
275 | }
276 | String url = Env.OAPI_HOST + "/user/get?" +
277 | "access_token=" + accessToken + "&userid=" + userid;
278 | BsonDocument json = HttpHelper.httpGet(url);
279 | return Newtonsoft.Json.JsonConvert.DeserializeObject(json.ToString());
280 | }
281 | ///
282 | /// 获取用户信息
283 | ///
284 | /// access_token
285 | /// userid
286 | public static async Task GetUserAsync(String accessToken, String userid)
287 | {
288 | if (String.IsNullOrWhiteSpace(accessToken))
289 | {
290 | throw new ArgumentException("accessToken 不能为空");
291 | }
292 | if (String.IsNullOrWhiteSpace(userid))
293 | {
294 | throw new ArgumentException("userid 不能为空");
295 | }
296 | String url = Env.OAPI_HOST + "/user/get?" +
297 | "access_token=" + accessToken + "&userid=" + userid;
298 | BsonDocument json = await HttpHelper.httpGetAsync(url);
299 | return Newtonsoft.Json.JsonConvert.DeserializeObject(json.ToString());
300 | }
301 |
302 | ///
303 | /// 批量删除成员
304 | ///
305 | /// access_token
306 | /// 用户列表
307 | /// 是否删除成功
308 | public static bool BatchDeleteUser(String accessToken, List useridlist)
309 | {
310 | if (String.IsNullOrWhiteSpace(accessToken))
311 | {
312 | throw new ArgumentException("accessToken 不能为空");
313 | }
314 | if (useridlist.Count == 0)
315 | {
316 | throw new ArgumentException("useridlist 不能为空");
317 | }
318 | String url = Env.OAPI_HOST + "/user/batchdelete?" +
319 | "access_token=" + accessToken;
320 | BsonDocument args = new BsonDocument();
321 | args["useridlist"] = new BsonArray(useridlist);
322 | BsonDocument response = HttpHelper.httpPost(url, args);
323 | if (!HttpHelper.CheckResponseOk(response))
324 | {
325 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
326 | }
327 | return true;
328 | }
329 |
330 | ///
331 | /// 批量删除成员
332 | ///
333 | /// access_token
334 | /// 用户列表
335 | /// 是否删除成功
336 | public static async Task BatchDeleteUserAsync(String accessToken, List useridlist)
337 | {
338 | if (String.IsNullOrWhiteSpace(accessToken))
339 | {
340 | throw new ArgumentException("accessToken 不能为空");
341 | }
342 | if (useridlist.Count == 0)
343 | {
344 | throw new ArgumentException("useridlist 不能为空");
345 | }
346 | String url = Env.OAPI_HOST + "/user/batchdelete?" +
347 | "access_token=" + accessToken;
348 | BsonDocument args = new BsonDocument();
349 | args["useridlist"] = new BsonArray(useridlist);
350 | BsonDocument response = await HttpHelper.httpPostAsync(url, args);
351 | if (!HttpHelper.CheckResponseOk(response))
352 | {
353 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
354 | }
355 | return true;
356 | }
357 | ///
358 | /// 获取部门成员
359 | ///
360 | /// access_token
361 | /// 部门id
362 | /// 部门成员list
363 | public static List GetDepartmentUser(String accessToken, long department_id)
364 | {
365 | if (String.IsNullOrWhiteSpace(accessToken))
366 | {
367 | throw new ArgumentException("accessToken 不能为空");
368 | }
369 | String url = Env.OAPI_HOST + "/user/simplelist?" +
370 | "access_token=" + accessToken + "&department_id=" + department_id;
371 | BsonDocument response = HttpHelper.httpGet(url);
372 | if (HttpHelper.CheckResponseOk(response))
373 | {
374 | List list = new List();
375 | BsonArray arr = response["userlist"].AsBsonArray;
376 | for (int i = 0; i < arr.Count; i++)
377 | {
378 | list.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(arr[i].ToString()));
379 | }
380 | return list;
381 | }
382 | else
383 | {
384 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
385 | }
386 | }
387 |
388 | ///
389 | /// 获取部门成员的简单信息,此接口只包含userid和name
390 | ///
391 | /// access_token
392 | /// 部门id
393 | /// 部门成员list
394 | public static async Task> GetDepartmentUserAsync(String accessToken, long department_id)
395 | {
396 | if (String.IsNullOrWhiteSpace(accessToken))
397 | {
398 | throw new ArgumentException("accessToken 不能为空");
399 | }
400 | String url = Env.OAPI_HOST + "/user/simplelist?" +
401 | "access_token=" + accessToken + "&department_id=" + department_id;
402 | BsonDocument response = await HttpHelper.httpGetAsync(url);
403 | if (HttpHelper.CheckResponseOk(response))
404 | {
405 | List list = new List();
406 | BsonArray arr = response["userlist"].AsBsonArray;
407 | for (int i = 0; i < arr.Count; i++)
408 | {
409 | list.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(arr[i].ToString()));
410 | }
411 | return list;
412 | }
413 | else
414 | {
415 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
416 | }
417 | }
418 |
419 | ///
420 | /// 获取部门成员的详细信息
421 | ///
422 | /// access_token
423 | /// 部门id
424 | /// 部门成员list
425 | public static List GettDepartmentUserDetail(String accessToken, long department_id)
426 | {
427 | if (String.IsNullOrWhiteSpace(accessToken))
428 | {
429 | throw new ArgumentException("accessToken 不能为空");
430 | }
431 | String url = Env.OAPI_HOST + "/user/list?" +
432 | "access_token=" + accessToken + "&department_id=" + department_id;
433 | BsonDocument response = HttpHelper.httpGet(url);
434 | if (HttpHelper.CheckResponseOk(response))
435 | {
436 | BsonArray arr = response["userlist"].AsBsonArray;
437 | List list = new List();
438 | for (int i = 0; i < arr.Count; i++)
439 | {
440 | var bd = arr[i].ToBsonDocument();
441 | if (bd.Contains("order"))
442 | {
443 | bd.Set("order", bd.GetValue("order").AsInt64.ToString());
444 | }
445 | list.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(arr[i].ToString()));
446 | }
447 | return list;
448 | }
449 | else
450 | {
451 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
452 | }
453 | }
454 | ///
455 | /// 获取部门成员的详细信息
456 | ///
457 | /// access_token
458 | /// 部门id
459 | /// 部门成员list
460 | public static async Task> GettDepartmentUserDetailAsync(String accessToken, long department_id)
461 | {
462 | if (String.IsNullOrWhiteSpace(accessToken))
463 | {
464 | throw new ArgumentException("accessToken 不能为空");
465 | }
466 | String url = Env.OAPI_HOST + "/user/list?" +
467 | "access_token=" + accessToken + "&department_id=" + department_id;
468 | BsonDocument response = await HttpHelper.httpGetAsync(url);
469 | if (rHttpHelper.CheckResponseOk(response))
470 | {
471 | BsonArray arr = response["userlist"].AsBsonArray;
472 | List list = new List();
473 | for (int i = 0; i < arr.Count; i++)
474 | {
475 | var bd = arr[i].ToBsonDocument();
476 | if (bd.Contains("order"))
477 | {
478 | bd.Set("order", bd.GetValue("order").AsInt64.ToString());
479 | }
480 | list.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(arr[i].ToString()));
481 | }
482 | return list;
483 | }
484 | else
485 | {
486 | throw new DingDingApiResultException(response["errcode"].AsInt32, response["errmsg"].AsString);
487 | }
488 | }
489 | }
490 | }
491 |
--------------------------------------------------------------------------------