本文目录
前言
上一篇我们通过实战分享了使用Go推送钉钉消息,由于技痒,笔者现在也编写了一个.NET Core的Demo,作为简单的对照和说明。
最后,由于精力有限,笔者希望有兴趣的朋友可以分享下使用CoreRT将.NET Core编译成机器代码这块的实践。
目录
使用.NET Core推送钉钉消息
这里我们使用.NET Core来完成相关需求,注意,这里是.NET Core,而不是ASP.NET Core。需求和上面类似,工程相关依赖如下所示:
<PackageReferenceInclude=\"Microsoft.Extensions.Configuration\"Version=\"2.2.0\"/> <PackageReferenceInclude=\"Microsoft.Extensions.Configuration.CommandLine\"Version=\"2.2.0\"/> <PackageReferenceInclude=\"Microsoft.Extensions.Configuration.EnvironmentVariables\"Version=\"2.2.0\"/> <PackageReferenceInclude=\"Microsoft.Extensions.Http\"Version=\"2.2.0\"/> <PackageReferenceInclude=\"Newtonsoft.Json\"Version=\"12.0.1\"/>
以下是相关的主体代码:
获取参数
从环境变量或者命令行参数获取配置:
///<summary> ///环境变量列表 ///</summary> privatestaticreadonlystring[] EnvList = { //钉钉机器人地址 \"WEBHOOK\", //@的手机号码 \"AT_MOBILES\", //@所有人 \"IS_AT_ALL\", //消息内容 \"MESSAGE\", //消息类型(仅支持文本和markdown) \"MSG_TYPE\" }; privatestaticvoid Main(string[] args) { var config = newConfigurationBuilder() //支持命令行参数 .AddCommandLine(args) //支持环境变量 .AddEnvironmentVariables() .Build(); #region参数检查 foreach (var envName in EnvList) { var value =config[envName]; if (string.IsNullOrWhiteSpace(value)&& envName != \"AT_MOBILES\" && envName !=\"IS_AT_ALL\") { Console.WriteLine($\"{envName}不能为空!\"); return; } } if (string.IsNullOrWhiteSpace(config[\"AT_MOBILES\"]) &&string.IsNullOrWhiteSpace(config[\"IS_AT_ALL\"])) { Console.WriteLine(\"必须设置参数 AT_MOBILES 和 IS_AT_ALL 两者之一!\"); return; } #endregion try { //推送消息 SetDataAndSendWebhooks(config).Wait(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }
设置消息数据格式
设置消息格式,为了简单,这里我们使用匿名类:
///<summary> ///设置消息并调用Webhook ///</summary> ///<param name=\"config\"></param> ///<returns></returns> privatestaticasync Task SetDataAndSendWebhooks(IConfigurationRoot config) { var at = new { AtMobiles = config[\"AT_MOBILES\"]?.Split(\',\'), IsAtAll = Convert.ToBoolean(config[\"IS_AT_ALL\"] ?? \"false\") }; switch (config[\"MSG_TYPE\"]) { case\"text\": { var data = new { Msgtype = \"text\", Text = new { Content =config[\"MESSAGE\"] }, At = at }; awaitSendWebhooks(config[\"WEBHOOK\"], data); break; } case\"markdown\": { var data = new { Msgtype = \"markdown\", Markdown = new { Title = \"钉钉通知\", Text = config[\"MESSAGE\"] }, At = at }; awaitSendWebhooks(config[\"WEBHOOK\"], data); break; } default: { Console.WriteLine($\"不支持的格式:{config[\"MSG_TYPE\"]}\"); break; } } }
发送请求
此处代码使用Newtonsoft.Json做JSON序列化,然后使用Microsoft.Extensions.Http的HttpClient库来发送Post请求。
在数据格式这块,我们通过配置做了以下设置:
-
忽略Null值。也就是为null的属性不做JSON序列化。
-
设置属性命名规则为Camel-Case驼峰式命名法,首字母小写。
主体代码如下所示:
///<summary> ///调用webhook ///</summary> ///<typeparamname=\"T\"></typeparam> ///<param name=\"url\">webhook地址</param> ///<param name=\"data\">消息</param> ///<returns></returns> privatestaticasync Task SendWebhooks<T>(string url, T data) where T : class { JsonConvert.DefaultSettings = newFunc<JsonSerializerSettings>(() =>newJsonSerializerSettings() { NullValueHandling =NullValueHandling.Ignore, ContractResolver = newCamelCasePropertyNamesContractResolver() }); var jsonData =JsonConvert.SerializeObject(data); Console.WriteLine(jsonData); using (var httpClient = new HttpClient()) { var content = newStringContent(jsonData); content.Headers.ContentType = newMediaTypeHeaderValue(\"application/json\"); var result = awaithttpClient.PostAsync(url, content); result.EnsureSuccessStatusCode(); Console.WriteLine($\"Send webhook succeed. StatusCode:{result.StatusCode}\"); } }
设置Dockerfile
在之前我们已经讲述过,使用了分阶段构建。整个Dockerfile基本上使用VS Docker tool生成:
FROMmicrosoft/dotnet:2.2-runtime AS base WORKDIR /app FROMmicrosoft/dotnet:2.2-sdk AS build WORKDIR /src COPY DingTalk.NET/DingTalk.NET.csprojDingTalk.NET/ RUN dotnet restoreDingTalk.NET/DingTalk.NET.csproj COPY . . WORKDIR /src/DingTalk.NET RUN dotnet buildDingTalk.NET.csproj -c Release -o /app FROM build AS publish RUN dotnet publish DingTalk.NET.csproj-c Release -o /app FROM base AS final WORKDIR /app COPY --from=publish/app . ENTRYPOINT [\"dotnet\", \"DingTalk.NET.dll\"] # 注意不要单独使用 MAINTAINER 指令,MAINTAINER已被Label标签代替 LABEL MAINTAINER =\"xinlai@xin-lai.com\" # LABEL指令用于将元数据添加到镜像,支持键值对和JSON,我们可以使用 docker inspect 命令来查看 LABELDingtalkComponent=\'{\\ \"description\": \"使用钉钉发送通知消息.\",\\ \"input\": [\\ {\"name\": \"WEBHOOK\",\"desc\": \"必填, 钉钉机器人Webhook地址\"},\\ {\"name\":\"AT_MOBILES\", \"desc\": \"非必填,被@人的手机号\"},\\ {\"name\":\"IS_AT_ALL\", \"desc\": \"非必填,@所有人时:true, 否则为:false\"},\\ {\"name\": \"MESSAGE\",\"desc\": \"必填,自定义发送的消息内容\"},\\ {\"name\":\"MSG_TYPE\", \"desc\": \"必填,自定义发送的消息类型,目前仅支持text和markdown\"}\\ ]\\ }\'
编译完成后,我们来查看下镜像大小:
注意:
通过上图我们可以看到,镜像大小不到200M,相比GO体重大了许多,但是相比其他语言却轻了不少。不过,我们可以通过官方开源库CoreRT将.NET Core编译成机器代码,也就是.NET Core也可以做到编译完成后只有几M大小。有兴趣的朋友可以分享下这块的实践。
运行并设置环境变量推送消息
我们使用PowerShell编写简单脚本如下所示:
docker build --rm-f \"Dockerfile\" -t dingtalk.net:latest . docker run --rm -e\"WEBHOOK=https://oapi.dingtalk.com/robot/send?access_token={yourAccess Token}\" ` -e \"MESSAGE=*使用.NET Core发送钉钉消息。*\" ` -e \"IS_AT_ALL=true\" ` -e \"MSG_TYPE=markdown\" ` -d dingtalk.net
效果如图: