简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人

前文

一个简易的API调用框架

准备工作

关于钉钉机器人的API文档

点击这里

nuget安装apilay

简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人_第1张图片

新建项目

这种就不在赘述了


简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人_第2张图片

返回值

经过一些简单的测试发现几个接口,返回值都是一样的{"errmsg":"ok","errcode":0}
所以可以定义一个公共的返回值,
为了保证一些扩展性,可以继承 Dictionary

/// 
/// 返回值基类
/// 
public class ResponseResult : Dictionary
{
    /// 
    /// 错误消息, 请求正确返回"ok"
    /// 
    public string errmsg
    {
        get => this["errmsg"] as string;
        set => this["errmsg"] = value;
    }
    /// 
    /// 错误代码, 请求正确返回0
    /// 
    public int errcode
    {
        get => this["errcode"] is int i ? i : int.TryParse(this["errcode"] + "", out var code) ? code : int.MinValue;
        set => this["errcode"] = value.ToString();
    }
    /// 
    /// 返回值原文
    /// 
    public string OriginalResult { get; set; }
}

请求基类

定义一个请求基类,将一些公共部分提取出来,如MethodContentTypePathaccess_token参数,Json序列化,返回值判断等操作

public abstract class SendBase : ApRequest
{
    /// 
    /// 将返回值解析为 ResponseResult
    /// 
    ///  http状态码 
    ///  响应正文 
    ///  用于获取响应头的委托方法 
    /// 
    public sealed override ResponseResult GetData(int statusCode, byte[] content, Func getHeader)
    {
        if (content == null || content.Length == 0)
        {
            if (statusCode != 200 && statusCode != 0)
            {
                return new ResponseResult() { errcode = statusCode, errmsg = "请求服务器异常" };
            }
            return new ResponseResult() { errcode = int.MinValue + 1, errmsg = "服务器返回为空" };
        }
        var json = Encoding.UTF8.GetString(content, 0, content.Length);
        try
        {
            var result = (ResponseResult)Units.ToJsonObject(json, typeof(ResponseResult));
            result.OriginalResult = json;
            return result;
        }
        catch (Exception e)
        {
            return new ResponseResult() { errcode = statusCode == 200 || statusCode == 0 ? int.MinValue : statusCode, errmsg = e.Message, OriginalResult = json };
        }
    }

    /// 
    /// url_query 参数 
    /// 
    [QueryValue(Name = "access_token")]
    public string AccessToken { get; set; }
    public override string Method => "POST";
    public override string ContentType => "application/json;charset=utf-8";
    public override string Path => "/robot/send";
    /// 
    /// 提交正文内容
    /// 
    protected abstract object Content { get; }

    /// 
    /// json字符串转为字节
    /// 
    public override byte[] Body => Encoding.UTF8.GetBytes(Units.ToJsonString(Content));
}

定义会话

我这里将一个独立的机器人定义为一个会话,所以通过access_token实例化,
另外可以在会话中设置请求根域名,方便切换环境,
根据需要包装Invoke方法

public sealed class Robot : ApSession
{
    public Robot(string accessToken) 
        => AccessToken = accessToken ?? throw new ArgumentNullException(nameof(accessToken));

    /// 
    /// 机器人标识
    /// 
    public string AccessToken { get; }

    /// 
    /// 机器人api域名
    /// 
    public string BaseUrl => "https://oapi.dingtalk.com/";

    /// 
    /// 利用机器人发送消息
    /// 
    /// 
    public async Task Send(SendBase request)
    {
        if (request == null) throw new ArgumentNullException(nameof(request));
        request.AccessToken = AccessToken;
        var result = await Invoke(BaseUrl, request, CancellationToken.None);
        if (result.errcode != 0)
        {
            throw new ApRequestException(result.errcode, result.errmsg);
        }
    }
}

到这里基本对象都已经定义完了

先尝试定义一个最简单的markdown消息

简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人_第3张图片
文档说明

继承 SendBase 按照要求构造正文参数

public sealed class SendMarkdown : SendBase
{
    protected override object Content => new
    {
        msgtype = "markdown",
        markdown = new
        {
            title = Title?.Length > 20 ? Title.Substring(0, 17) + "..." : Title ?? "",
            text = Text ?? "",
        }
    };

    /// 
    /// markdown格式的消息 
    /// 
    public string Text { get; set; }
    /// 
    /// 首屏会话透出的展示内容 
    /// 
    public string Title { get; set; }
}

发送 markdown消息

自己建一个群,添加一个机器人


简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人_第4张图片

在机器人设置中获取机器人的accesstoken


简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人_第5张图片

测试代码

static void Main(string[] args)
{
    var robot = new Robot("4aa82a4e65b81103****");
    robot.Send(new SendMarkdown()
    {
        Title = "测试一下消息",
        Text = "##标题一 \n> 引用  \n\n* 列表1\n* 列表2\n* 列表3"
    }).Wait();
}
简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人_第6张图片

其他类型的消息

测试成功,就可以编写其他类型的消息了
根据文档写就好了

Text

public sealed class SendText : SendBase
{

    public SendText(string text)
    {
        Text = text;
    }

    protected override object Content => new
    {
        msgtype = "text",
        text = new
        {
            content = Text,
        },
        at = new
        {
            atMobiles = IsAtAll ? EmptyList : At ?? EmptyList,
            isAtAll = IsAtAll,
        },
    };

    /// 
    /// 消息内容
    /// 
    public string Text { get; set; }

    /// 
    /// @所有人时:true,否则为:false
    /// 
    public bool IsAtAll { get; set; }

    /// 
    /// 被@人的手机号
    /// 
    public List At { get; set; } = new List();

    static readonly List EmptyList = new List();
}

Link

public sealed class SendLink : SendBase
{
    protected override object Content => new
    {
        msgtype = "link",
        link = new
        {
            text = Text,
            title = Title?.Length > 20 ? Title.Substring(0, 17) + "..." : Title ?? "",
            picUrl = PictureUrl,
            messageUrl = LinkUrl,
        },
    };

    /// 
    /// 消息内容。如果太长只会部分展示
    /// 
    public string Text { get; set; }
    /// 
    /// 消息标题
    /// 
    public string Title { get; set; }
    /// 
    /// 图片URL
    /// 
    public string PictureUrl { get; set; }
    /// 
    /// 点击消息跳转的URL
    /// 
    public string LinkUrl { get; set; }
}

SingleActionCard

public sealed class SendSingleActionCard : SendBase
{
    protected override object Content => new
    {
        msgtype = "actionCard",
        actionCard = new
        {
            title = Title?.Length > 20 ? Title.Substring(0, 17) + "..." : Title ?? "",
            text = Text,
            hideAvatar = HideAvatar ? "1" : "0",
            btnOrientation = VerticalButton ? "0" : "1",
            singleTitle = LinkText ?? "查看详情",
            singleURL = LinkUrl,
        },
    };

    /// 
    /// 首屏会话透出的展示内容 
    /// 
    public string Title { get; set; }
    /// 
    /// markdown格式的消息 
    /// 
    public string Text { get; set; }
    /// 
    /// 是否隐藏发消息者头像
    /// 
    public bool HideAvatar { get; set; }
    /// 
    /// 是否竖直排列按钮, false为横向排列 
    /// 
    public bool VerticalButton { get; set; } = true;
    /// 
    /// 链接文字
    /// 
    public string LinkText { get; set; }
    /// 
    /// 链接URL
    /// 
    public string LinkUrl { get; set; }
}

MultisActionCard

public sealed class SendMultisActionCard : SendBase
{
    protected override object Content => new
    {
        msgtype = "actionCard",
        actionCard = new
        {
            title = Title?.Length > 20 ? Title.Substring(0, 17) + "..." : Title ?? "",
            text = Text,
            hideAvatar = HideAvatar ? "1" : "0",
            btnOrientation = VerticalButton ? "0" : "1",
            btns = Links.Select(x => new
            {
                title = x.Key,
                actionURL = x.Value,
            }).ToList(),
        },
    };


    /// 
    /// 首屏会话透出的展示内容 
    /// 
    public string Title { get; set; }
    /// 
    /// markdown格式的消息 
    /// 
    public string Text { get; set; }
    /// 
    /// 是否隐藏发消息者头像
    /// 
    public bool HideAvatar { get; set; }
    /// 
    /// 是否竖直排列按钮, false为横向排列 
    /// 
    public bool VerticalButton { get; set; } = true;
    /// 
    /// 超链接组
    /// 
    public Dictionary Links = new Dictionary();
    
}

FeedCard

public class SendFeedCard : SendBase
{
    protected override object Content => new
    {
        msgtype = "feedCard",
        feedCard = new { links = _items }
    };

    readonly List _items = new List();

    /// 
    /// 添加项
    /// 
    ///  信息文本 
    ///  跳转链接 
    ///  图片URL 
    public void AddItem(string title, string linkUrl, string pictureUrl)
    {
        if (string.IsNullOrWhiteSpace(title)) throw new ArgumentNullException(nameof(title));
        if (string.IsNullOrWhiteSpace(linkUrl)) throw new ArgumentNullException(nameof(linkUrl));
        if (string.IsNullOrWhiteSpace(pictureUrl)) throw new ArgumentNullException(nameof(pictureUrl));
        _items.Add(new { title, messageURL = linkUrl, picURL = pictureUrl });
    }
}
 
 

测试

测试代码

static void Main(string[] args)
{
    var robot = new Robot("4aa82a4e65b8110*****");
    robot.Send(new SendMarkdown()
    {
        Title = "测试一下消息",
        Text = "##标题一 \n> 引用  \n\n* 列表1\n* 列表2\n* 列表3"
    }).Wait();

    robot.Send(new SendText("测试Text")
    {
        At = { "15657966053" } // @我自己
    }).Wait();

    robot.Send(new SendLink()
    {
        Title = "测试Link",
        Text = "测试Link",
        LinkUrl = "http://baidu.com"
    }).Wait();

    robot.Send(new SendSingleActionCard()
    {
        Title = "测试SingleActionCard",
        Text = "测试SingleActionCard",
        LinkText = "点击我去百度",
        LinkUrl = "http://baidu.com"
    }).Wait();

    robot.Send(new SendMultisActionCard()
    {
        Title = "测试MultisActionCard",
        Text = "测试MultisActionCard",
        HideAvatar = true,
        VerticalButton = false,
        Links =
        {
            ["去百度"] = "http://baidu.com",
            ["去谷歌"] = "http://google.cn",
        }
    }).Wait();

    var feedCard = new SendFeedCard();
    feedCard.AddItem("去百度", "http://baidu.com", "https://www.baidu.com/img/bd_logo1.png");
    feedCard.AddItem("去谷歌", "http://google.cn", "http://www.google.cn/landing/cnexp/google-search.png");
    robot.Send(feedCard).Wait();
}

测试结果


简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人_第7张图片

你可能感兴趣的:(简易API调用框架(blqw.Apilay)示例 —— 钉钉机器人)