GVKun编程网logo

Docker最全教程之使用.NET Core推送钉钉消息(十九)(docker 推送harbor)

29

在本文中,我们将为您详细介绍Docker最全教程之使用.NETCore推送钉钉消息的相关知识,并且为您解答关于十九的疑问,此外,我们还会提供一些关于ASP.NETCore基于Socket实现消息推送实

在本文中,我们将为您详细介绍Docker最全教程之使用.NET Core推送钉钉消息的相关知识,并且为您解答关于十九的疑问,此外,我们还会提供一些关于ASP.NET Core基于Socket实现消息推送实战演练、C#实现推送钉钉消息的方法示例、DingTalk 钉钉消息推送(.net core 3 WebApi 尝鲜记)、Docker 最全教程 —— 从理论到实战(二)的有用信息。

本文目录一览:

Docker最全教程之使用.NET Core推送钉钉消息(十九)(docker 推送harbor)

Docker最全教程之使用.NET Core推送钉钉消息(十九)(docker 推送harbor)

前言

上一篇我们通过实战分享了使用Go推送钉钉消息,由于技痒,笔者现在也编写了一个.NET Core的Demo,作为简单的对照和说明。

最后,由于精力有限,笔者希望有兴趣的朋友可以分享下使用CoreRT将.NET Core编译成机器代码这块的实践。

 

目录

  • 使用.NET Core推送钉钉消息

  • 获取参数

  • 设置消息数据格式

  • 发送请求

  • 设置Dockerfile

  • 运行并设置环境变量推送消息

 

使用.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

 

效果如图:

 

原文出处:https://www.cnblogs.com/codelove/p/10576322.html

ASP.NET Core基于Socket实现消息推送实战演练

ASP.NET Core基于Socket实现消息推送实战演练

1、课程介绍和实例演示

1、课程介绍
在前面的分享课程中关于ASP.NET Core中如何实现消息推送,我们已经学过了《ASP.NET Core基于SignalR实现消息推送实战演练》、《ASP.NET Core基于WebSocket实现消息推送实战演练》,《ASP.NET Core基于SuperWebSocket实现消息推送实战演练》今天我们要学习的是如何通过微软原生的System.Net.sockets来实现消息推送实战演练。
特别注意本次分享课程是在《C#网络编程技术Socket实战演练》的基础之上演变和升级过来了,原来的课程是.NET Framework平台,现在给大家分享的是ASP.NET Core跨平台。

2、实例演示
1)、客户端与服务端互发消息
2)、客户端断线重连。
2、Socket客户端与服务端通信原理
3、Socket类库介绍和选择
4、用户(User)如何与Socket对象建立关系
5、ASP.NET Core使用自定义中间件添加Socket



 

《ASP.NET Core基于第三方WebSocket框架实战演练》

1、课程介绍
2、WebSocket介绍
3、为什么选择第三方WebSocket框架
4、第三方WebSocket框架如何选择
5、用户(User)如何与Socket对象建立关系
6、.NET中使用Fleck框架入门体验
7、ASP.NET Core如何通过自定义中间件集成Fleck框架
8、使用.NET客户端实现与Fleck服务端通信

9、ASP.NET Core如何通过标准中间件集成Fleck框架


《ASP.NET Core基于第三方websocket-sharp框架实战演练》

1、WebSocketSharp介绍
2、WebSocketSharp简单使用
3、ASP.NET Core使用后台系统服务
4、ASP.NET Core使用后台系统服务集成websocket-sharp框架
5、websocket-sharp客户端与服务通信

C#实现推送钉钉消息的方法示例

C#实现推送钉钉消息的方法示例

本文实例讲述了C#实现推送钉钉消息的方法。分享给大家供大家参考,具体如下:

利用钉钉提供的API可以推送消息到用户的钉钉app。根据钉钉的官方文档,调用钉钉的api需要一个AccessToken,我们先获取这个AccessToken。

string CorpId = "你的CorpId ";
string CorpSecret = "你的CorpSecret ";
public string AccessToken = "";
string AccessUrl = string.Format("https://oapi.dingtalk.com/gettoken?corpid={0}&corpsecret={1}", CorpId, CorpSecret);
Newtonsoft.Json.Linq.JToken json = Newtonsoft.Json.Linq.JToken.Parse(HttpGet(AccessUrl));
AccessToken = json["access_token"].ToString();

这里利用到了Newtonsoft.Json类解析返回来的json数据,用法网上很多资料可以查找到。HttpGet是我封装好的一个类,可以在这篇《C#基于HttpWebRequest实现发送HTTP请求的方法》查看,下面的HttpPost也是如此。

有了AccessToken,我们就可以调用钉钉的api了,发送推送的相关api 在,文档已经写得很清晰了,我们只需要发送一个json格式的数据过去,就可以推送数据了。

string MessageUrl = "https://oapi.dingtalk.com/message/send?access_token=" + AccessToken;
var json_req = new
{
  touser = "用户id1|用户id2", //接受推送userid,不同用户用|分割
  toparty = "",  //接受推送部门id
  agentid = "1",
  msgtype = "text", //推送类型
  text = new
      {
        content = "要推送的内容"
      }
};
string jsonRequest = JsonConvert.SerializeObject(json_req);//将对象转换为json
HttpPost(MessageUrl, jsonRequest);

其中HttpPost是我已经封装好的一个类,需要注意的是,agentid指的是以哪个应用的身份推送消息,这个id可以在钉钉管理后台的应用里面查看得到。

最后的效果:

更多关于C#相关内容感兴趣的读者可查看本站专题:《C#程序设计之线程使用技巧总结》、《C#窗体操作技巧汇总》、《C#常见控件用法教程》、《WinForm控件用法总结》、《C#数据结构与算法教程》、《C#数组操作技巧总结》及《C#面向对象程序设计入门教程》

希望本文所述对大家C#程序设计有所帮助。

您可能感兴趣的文章:
  • C#如何实现调取钉钉考勤接口的功能

DingTalk 钉钉消息推送(.net core 3 WebApi 尝鲜记)

DingTalk 钉钉消息推送(.net core 3 WebApi 尝鲜记)

我发了个朋友圈,Swagger 真他妈的牛 B,解放了开发 API 的码农,麻麻再也不用担心我们写 API 文档耽误回家吃饭了。

 

 

 

 

/// <summary>
        /// 发送钉钉消息
        /// </summary>
        /// <param name="toUser">Employee的userid,多个使用|分隔</param>
        /// <param name="title">标题</param>
        /// <param name="content">发送内容</param>  
        /// <param name="sourceUrl">消息向导地址</param>
        /// <returns></returns>
        private ApiResult SendCardMessageToEmployee(string toUser, string title, string content, string sourceUrl)
        {
            var result = new ApiResult
            {
                Success = false,
                ResponseDatetime = DateTime.Now.ToString(),
                ResultMessage = "操作失败!",
                ResultObject = null
            };
            try
            {
                toUser = toUser.Trim(''|'');
                string JSONData = "{\"touser\":\"" + toUser +
                    "\",\"toparty\":\"\",\"agentid\":\"" + _settings.Value.sendmessage_agentid + "\",\"msgtype\":\"action_card\",\"action_card\":{\"title\":\"" + title + "\",\"markdown\":\"<font size=7 face=\''黑体\''>DingTalk中间件提醒: </font> \n \n " +
                    content + "\r \n " + "\r \n " + "\r \n " + DateTime.Now.ToString() +
                    "\",\"single_title\": \"查看详情\",\"single_url\": \"" + sourceUrl + "\"}}";
                var access_token = GetAccessToke();
                var tokenObj = access_token.ResultObject as AccessToken;
                string url = "https://oapi.dingtalk.com/message/send?access_token=" + tokenObj.access_token;
                string response = GetResponseData(JSONData, url);
                result.ResultObject = response;
                result.Success = string.IsNullOrEmpty(response);
                result.ResultMessage = "API调用成功!Requst Url:[" + url + "],Content:[" + JSONData + "]";
            }
            catch (Exception ex)
            {
                result.ResultObject = ex;
                _logger.LogError(ex, ex.Message, new object[] { });
            }
            return result;
        }


        /// <summary>
        /// 发送钉钉消息
        /// </summary>
        /// <param name="toUser">Employee的userid,多个使用|分隔</param> 
        /// <param name="content">发送内容</param>        
        /// <param name="sourceUrl">发送内容</param>    
        /// <returns></returns>
        private ApiResult SendMediaMessageToEmployee(string toUser, string content, string sourceUrl)
        {
            var result = new ApiResult
            {
                Success = false,
                ResponseDatetime = DateTime.Now.ToString(),
                ResultMessage = "操作失败!",
                ResultObject = null
            };
            try
            {
                toUser = toUser.Trim(''|'');
                string JSONData = "{\"touser\":\"" + toUser + "\",\"toparty\":\"\",\"agentid\":\"" + _settings.Value.sendmessage_agentid + "\",\"" + content + ",\"single_title\": \"查看详情\",\"single_url\": \"" + sourceUrl + "\"}}";
                var access_token = GetAccessToke();
                var tokenObj = access_token.ResultObject as AccessToken;
                string url = "https://oapi.dingtalk.com/message/send?access_token=" + tokenObj.access_token;
                string response = GetResponseData(JSONData, url);
                result.ResultObject = response;
                result.Success = string.IsNullOrEmpty(response);
                result.ResultMessage = "API调用成功!Requst Url:[" + url + "],Content:[" + JSONData + "]";
            }
            catch (Exception ex)
            {
                result.ResultObject = ex;
                _logger.LogError(ex, ex.Message, new object[] { });
            }
            return result;
        }
        /// <summary>
        /// 给指定员工发送钉钉消息1
        /// </summary>
        /// <param name="userid">指定员工的职员ID</param>
        /// <param name="title">标题</param>
        /// <param name="content">发送内容</param>
        /// <param name="sourceUrl">消息向导地址</param>
        /// <returns></returns>
        [HttpGet]
        [HttpPost]
        public ApiResult SendDingTalkMessage(string userid, string title, string content, string sourceUrl = "http://www.cquni.com")
        {
            if (string.IsNullOrEmpty(title))
                title = "通知";
            var result = new ApiResult
            {
                Success = false,
                ResponseDatetime = DateTime.Now.ToString(),
                ResultMessage = "操作失败!",
                ResultObject = null
            };
            try
            {
                var rs = SendCardMessageToEmployee(userid, title, content, sourceUrl);
                result.Success = rs.Success;
                result.ResultMessage = rs.ResultMessage;
                result.ResultObject = rs.ResultObject;
            }
            catch (Exception ex)
            {
                result.ResultObject = ex;
            }
            return result;
        }
    

 

/// <summary>
        /// 给指定员工发送钉钉消息2
        /// </summary>
        /// <param name="departmentName">部门名称</param>
        /// <param name="employeeName">人员姓名</param>
        /// <param name="title">消息标题</param>
        /// <param name="content">消息内容</param>
        /// <param name="sourceUrl">url</param>
        /// <returns></returns>
        [HttpGet]
        [HttpPost]
        public ApiResult SendDingTalkMessageExt(string departmentName, string employeeName, string title, string content, string sourceUrl = "http://www.cquni.com")
        {
            var result = new ApiResult
            {
                Success = false,
                ResponseDatetime = DateTime.Now.ToString(),
                ResultMessage = "操作失败!",
                ResultObject = null
            };
            if (string.IsNullOrEmpty(title))
                title = "通知";
            var deptment = GetDepartmentInfo().department;
            if (deptment != null && deptment.Count > 0)
            {
                var currDept = deptment.Where(d => d.name.Contains(departmentName)).FirstOrDefault();
                if (currDept == null)
                {
                    result.ResultMessage = "获取人员的部门信息出错,输入部门名称:" + departmentName;
                }
                else
                {
                    var employeeList = GetDepartmentEmployeeList(currDept).userlist;
                    if (employeeList != null && employeeList.Count > 0)
                    {
                        var currentEmp = employeeList.Where(e => e.name.Contains(employeeName)).FirstOrDefault();
                        try
                        {
                            var rs = SendCardMessageToEmployee(currentEmp.userid, title, content, sourceUrl);
                            return rs;
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex.Message, new object[]
                            {
                                ex,
                                ex.InnerException
                            });
                        }
                    }
                    else
                    {
                        result.ResultMessage = string.Format("很奇怪,这个部门''{0}''一个人也没有!", departmentName);
                    }
                }
            }
            else
            {
                result.ResultMessage = "获取公司部门信息出错!";
            }
            return result;
        }

        /// <summary>
        /// 给指定员工发送钉钉消息(支持图文,文件,图片等格式)
        /// </summary>
        /// <param name="departmentName">部门名称</param>
        /// <param name="employeeName">人员姓名</param>
        /// <param name="mediaContent">消息内容 eg: "msgtype": "voice","voice": {"media_id": "MEDIA_ID","duration": "10" } 
        /// 格式说明请看钉钉官网文档 https://ding-doc.dingtalk.com/doc#/serverapi2/ye8tup </param>
        /// <param name="sourceUrl"></param>
        /// <returns></returns>
        [HttpGet]
        [HttpPost]
        public ApiResult SendDingTalkMediaMessage(string departmentName, string employeeName, string mediaContent, string sourceUrl = "http://www.cquni.com")
        {
            var result = new ApiResult
            {
                Success = false,
                ResponseDatetime = DateTime.Now.ToString(),
                ResultMessage = "操作失败!",
                ResultObject = null
            };
            var deptment = GetDepartmentInfo().department;
            if (deptment != null && deptment.Count > 0)
            {
                var currDept = deptment.Where(d => d.name.Contains(departmentName)).FirstOrDefault();
                if (currDept == null)
                {
                    result.ResultMessage = "获取人员的部门信息出错,输入部门名称:" + departmentName;
                }
                else
                {
                    var employeeList = GetDepartmentEmployeeList(currDept).userlist;
                    if (employeeList != null && employeeList.Count > 0)
                    {
                        var currentEmp = employeeList.Where(e => e.name.Contains(employeeName)).FirstOrDefault();
                        try
                        {
                            var rs = SendMediaMessageToEmployee(currentEmp.userid, mediaContent, sourceUrl);
                            return rs;
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex.Message, new object[]
                            {
                                ex,
                                ex.InnerException
                            });
                        }
                    }
                    else
                    {
                        result.ResultMessage = string.Format("很奇怪,这个部门''{0}''一个人也没有!", departmentName);
                    }
                }
            }
            else
            {
                result.ResultMessage = "获取公司部门信息出错!";
            }
            return result;
        }

 

 

 

Docker 最全教程 —— 从理论到实战(二)

Docker 最全教程 —— 从理论到实战(二)

上篇内容链接: https://www.cnblogs.com/codelove/p/10030439.html

Docker ASP.NET Core

Docker 正在逐渐成为容器行业的事实标准,受到 Windows Linux 生态系统领域最重要供应商的支持。 (Microsoft 是支持 Docker 的主要云供应商之一。)现在Docker 基本上已经各大云或本地的任何数据中心普及

如何将.NET 程序托管到 Docker 之中,相信这是广大.NET 开发者的一个疑问。事实上,.NET Framework 支持在 Docker 中运行,但是仅能在 windows 容器中运行,这并不符合我们的预期,因此,本篇我们只侧重于讨论 ASP.NET Core Docker

在使用之前,笔者还是有必要介绍下 ASP.NET Core。如果您对此非常熟悉和了解或者对此节不感兴趣,可以跳过本节。

 

ASP.NET Core 简介

ASP.NET Core 是一个跨平台的高性能开源框架,用于生成基于云且连接 Internet 的新式应用程序。使用 ASP.NET Core我们可以:

    • 建置 Web 应用程序和服务、IoT 应用和移动后端。

    • 能够在 Windows、macOS 和 Linux 上进行开发和运行。部署到云或本地。

    • 在 .NET Core 或 .NET Framework 上运行。

    • 能够在 IIS、Nginx、Apache、Docker 上进行托管或在自己的进程中进行自托管我们的应用。

 

 

性能是.NET Core 的一个关键特性,这里有必要介绍下。在这块,我们摘取了一份社区的测试汇总统计,仅供参考:

 

具体过程大家可以访问此链接来查看详情:https://www.cnblogs.com/savorboard/archive/2016/10/17/dotnet-benchmarks.html

 

ASP.NET Core Docker

 

刚才说了这么多,我们回到主题。.NET Core 天生就为跨平台设计,并且和 Docker 搭配非常友好,而且微软官方在这块提供了很多支持。比如说:

 

  • 轻量
  • 跨平台,天生对 Linux 友好
  • 模块化
  • 提供了轻量型容器镜像高性能(领先于 Java servletsGo node.js

 

 

 

接下来,我们一起来了解官方镜像。ASP.NET Core 的官方镜像名称为 microsoft/aspnetcore,微软针对 Docker 上的 ASP.NET Core 应用进行了优化,因此容器可以更快启动。为开发人员生成 Docker 镜像时,Microsoft 侧重于提供了以下主要方案:

 

  1. 用于开发和生成 .NET Core 应用的镜像
  2. 用于运行 .NET Core 应用的镜像

 

例如.NET Core 2.1,官方提供的镜像:

为什么是多个镜像?因为在开发、生成和运行容器化应用程序时,通常具有不同的优先级。 通过为这些单独的任务提供不同的镜像,有助于独立优化开发、生成和部署应用程序的过程。在开发期间,我们侧重的是开发更改的速度以及调试的能力。在生产环境,我们侧重的是应用部署和容器启动的速度和效率。

 

这里我们顺便提下我们基于.NET Core 2.1 开发的免费开源框架 ——Magicodes.Admin,其 demo 现在已经完全托管在 Docker 之中,部署在腾讯云的容器服务之中,大家可以点击访问测试下速度和稳定性,启动速度这点没得说。推荐访问 Https 地址,因域名在备案之中,http 域名可能无法访问。

Magicodes.Admin 开源库地址:https://gitee.com/xl_wenqiang/Magicodes.Admin.Core

 

Demo 地址:https://demoadmin.xin-lai.com

Admin

123456abcD

 

在本篇 Docker 教程中,我们会结合 Magicodes.Admin 的实践进行讲解,同时我们也会尽量提供一些实践案例分享给大家,比如 Magicodes.Admin demo、Magicodes 云服务、小程序商城(即将开源)、爱车 APP 等 Docker 完整托管案例,以便大家更易于理解和使用 Docker。在 Magicodes.Admin 框架中,接口服务使用.NET Core 2.1 开发,在 docker 上基于 microsoft/dotnet:2.1-aspnetcore-runtime 镜像使用 Kestrel web 服务器,后台前端使用 Angular 开发,在 docker 上基于 nginx 镜像使用 nginx 服务器进行托管,并启用了 HTTPS 支持和 GZIP 压缩。

我们回过来继续。.NET 镜像 (microsoft/dotnet) 同样适用于基于 .NET Core 的控制台应用。使用 Docker 和 .NET Core 非常适用于生产部署和托管,主要有以下几点:

  • 无需本地安装 —— 可以直接使用 .NET Framework,而无需本地安装。只下载相关的 Docker 镜像,其中包含 .NET Framework。

  • 在容器中开发 —— 你可以在一致的环境中开发,使开发和生产环境类似(可避免一些问题,例如开发人员计算机上的全局状态)。 通过 VS 的一些扩展插件,我们甚至可以直接从 Visual Studio 启动容器。

  • 容器中测试 —— 可以在容器中测试,减少由于环境配置不当或上次测试遗留的其他更改而导致的故障。

  • 在容器中生成 —— 可以在容器中生成代码。

  • 在所有环境中部署 —— 可以通过你的所有环境部署镜像。 这种方法减少了配置差异导致的故障,通常通过外部配置(例如,注入的环境变量)改变镜像行为。

注意:

Docker 镜像容器可以在 Linux 和 Windows 上本机运行。 但是,Windows 镜像仅能在 Windows 主机上运行,Linux 镜像可以在 Linux 主机和 Windows 主机上运行(到目前为止,使用 Hyper-V Linux VM),其中主机是指服务器或 VM。

注意:

.NET Framework 也可以使用 Docker 进行托管,不过仅能托管到 windows 容器之中。

在具体应用和实践之前,我们有必要了解以下内容。

 

Kestrel

Kestrel 是一个基于 libuv 的跨平台 ASP.NET Core web 服务器,libuv 是一个跨平台的异步 I/O 库。ASP.NET Core 模板项目使用 Kestrel 作为默认的 web 服务器。

Kestrel 支持以下功能:

  • HTTPS

  • 用于启用不透明升级的 WebSockets

  • 位于 Nginx 之后的高性能 Unix sockets

Kestrel 被.NET Core 支持的所有平台和版本所支持。Kestrel 可以单独使用,也可以与反向代理服务器(如 IIS、Nginx 或 Apache)一起使用。 反向代理服务器接收到来自 Internet 的 HTTP 请求,并在进行一些初步处理后将这些请求转发到 Kestrel。

在没有 Kestrel 或自定义服务器实现的情况下,不能使用 IIS、Nginx 和 Apache。 ASP.NET Core 设计为在其自己的进程中运行,以实现跨平台统一操作。 IIS、Nginx 和 Apache 规定自己的启动过程和环境。 若要直接使用这些服务器技术,ASP.NET Core 必须满足每个服务器的需求。 使用 Kestrel 等 Web 服务器实现时,ASP.NET Core 可以控制托管在不同服务器技术上的启动过程和环境。

注意:

Kestrel 可以单独使用,也可以与反向代理服务器(如 IIS、Nginx 或 Apache)一起使用。在 docker 容器中,我们推荐使用 Kestrel。

在大部分情况下,我们推荐使用反向代理服务器。主要是有以下好处:

  • 可以限制所承载的应用中的公开的公共外围应用。

  • 可以提供额外的配置和防护层。

  • 可以更好地与现有基础结构集成。

  • 可以简化负载均衡和 SSL 配置。 仅反向代理服务器需要 SSL 证书,并且该服务器可使用普通 HTTP 在内部网络上与应用服务器通信。

说了这么多,总归还是 “纸上得来终觉浅,绝知此事要躬行”。我们来一起实践:

首先我们需要安装以下包:

Install-Package Microsoft.AspNetCore.Server.Kestrel -Version 2.1.3

然后就可以编写启动代码:

在上面的代码中,我们通过了配置文件来配置 Kestrel,我们也推荐大家使用配置文件来配置 Kestrel。相关配置 Demo 如下:

当然,我们也可以通过代码来配置 kestrel:

 

按环境加载配置

ASP.NET Core 基于使用环境变量的运行时环境配置应用行为。ASP.NET Core 在应用启动时读取环境变量 ASPNETCORE_ENVIRONMENT,并将该值存储在 IHostingEnvironment.EnvironmentName 中。 ASPNETCORE_ENVIRONMENT 可设置为任意值,但框架支持三个值:Development、Staging 和 Production。 如果未设置 ASPNETCORE_ENVIRONMENT,则默认为 Production。

注意:

在 Docker 容器中,我们经常会修改 ASPNETCORE_ENVIRONMENT 环境变量来模拟开发、测试和生产环境。

因此在代码中,我们可以根据环境变量来启用或关闭相应的功能,其中场景最广泛的一点是 —— 根据不同的环境加载不同的配置。同时,内置的环境变量配置提供程序(EnvironmentVariablesConfigurationProvider)还可以在运行时从环境变量键值对加载配置。具体见以下代码:

 

内置的日志记录提供程序

ASP.NET Core 提供以下内置日志记录提供程序,在很多情况下,对我们会很有帮助:

  • 控制台日志提供程序

  • 调试日志提供程序

  • EventSource 日志提供程序

  • EventLog 日志提供程序

 

控制台日志提供程序

在 Docker 环境下,为了便于排错,我们推荐启用此日志提供程序。在平常的情况下,我们通过控制台运行程序(比如通过 dotnet run 运行)也会输出控制台日志。在使用之前,需要安装以下包:

Install-Package Microsoft.Extensions.Logging.Console -Version 2.1.1

然后我们可以在代码中通过以下代码启用:

logging.AddConsole();

完整代码如图所示:

添加了之后,我们在云端的容器服务的日志中,就可以看到控制台日志了。下面以腾讯云容器服务为例。首先打开腾讯云【容器服务】的【服务】页面,如图所示:

我们可以点击【日志】操作按钮的图标来查看日志:

 

我们也可以点击具体的某个实例来查看相关日志,这里就不多写了。

注意:

通过控制台日志,我们可以输出一些启动信息以用来做启动诊断,同时我们也可以根据控制台日志来查看请求状况和运行状况。

 

调试日志提供程序

和控制台日志一样,也需要安装相关依赖包:

Install-Package Microsoft.Extensions.Logging.Debug -Version 2.1.1

该包使用 System.Diagnostics.Debug 类(Debug.WriteLine 方法调用)来写入日志输出。注意,在 Linux 中,此提供程序将日志写入 /var/log/message

代码启用方式如下所示:

logging.AddDebug();

 

EventSource 日志提供程序

包依赖关系如下:

Install-Package Microsoft.Extensions.Logging.EventSource -Version 2.1.1

该提供程序可实现事件跟踪。不过值得注意的是,该提供程序尚无支持 Linux 或 macOS 的事件集合和显示工具。期待官方提供相关工具。

而在 windows server,可以通过开源工具 https://github.com/Microsoft/perfview 来收集和查看日志,如下图所示:

 

EventLog 日志提供程序

需要添加包:Microsoft.Extensions.Logging.EventLog。

主要用于向 Windows 事件日志发送日志输出。

 

关于 ASP.NET Core 的相关内容,我们先介绍到这里。接下来我们主要是围绕 Docker 开发工作流程在进行讲解。

 

搭建并使用 Docker

Docker 的安装非常简单,我们这里仅以 windows 10 操作系统(推荐)为例进行讲解。

 

安装 Docker

这里以 Docker for windows 为例,其他环境请参考官网教程。

注意:

不推荐使用 Docker Toolbox,Docker Toolbox 适用于较旧的 Mac 和 Windows 系统。

要安装 Docker,请先查看用于 Windows 的 Docker:安装须知了解相关信息。

安装须知链接:https://docs.docker.com/docker-for-windows/install/#what-to-know-before-you-install

注意:

使用 Docker for windows 需要启用 Hyper-V 功能。以下是系统要求:

  • Windows 10 64 位:Pro,Enterprise 或 Education(Build 14393 或更高版本)。

  • 在 BIOS 中启用虚拟化。通常,默认情况下启用虚拟化。这与启用 Hyper-V 不同。

  • 支持 CPU SLAT 的功能。

  • 至少 4GB 的 RAM。

Docker for Windows 安装包括:安装提供 Docker Engine,Docker CLI 客户端,Docker Compose,Docker Machine 和 Kitematic。

安装包下载链接:https://store.docker.com/editions/community/docker-ce-desktop-windows

参考:https://docs.docker.com/docker-for-windows/

安装完后,会提示点击重启电脑。重启后会自动启动 Docker 程序,如果弹出下图所示提示,则需要在 Windows 功能中启用 Hyper-V 功能和 在 BIOS CPU 配置中打开 “虚拟化配置”,打开之后,如下图所示,虚拟化会显示已启用。反之安装成功。

注意虚拟化已启用,如下图所示(这里秀一把我 NB 的台式机,是不是比你们的服务器都高端 N 个档次):

以上配置完成后我们推荐将 docker 容器切换到 Linux 环境,选择右下角 Docker 图标右键选择” Switch to Linux containers” 进行切换,如果显示” Switch to Windows containers” 则已处于 Linux 容器。

这是我们可以测试 Docker 环境是否正常,打开命令行,输入 docker –version:

注意:

我们推荐使用 Linux 容器服务,因为目前主流的容器系统是 Linux,并且从资源的利用来说,Linux 可以让资源得到更大的利用。

 

关于 docker 的安装和配置,这里不再细说,大家可以关注我们的公众号 “magiccodes“来查阅相关的教程以及录屏。

 

配置 Docker 本地环境

安装完成并且启动后,右下角有个小图标:

右键打开设置。

Docker for Windows 中的共享驱动器必须配置为支持卷映射和调试。右键单击系统托盘中的 Docker 图标,单击 “设置”,然后选择 “共享驱动器”。 选择 Docker 存储文件的驱动器。 单击 “应用”。

其他的配置我们这里就不多说了,具体见公众号 “magiccodes” 中提供的录屏教程。

 

运行一个简单的 demo

我们先运行官方的 Hello world 示例:

docker run hello-world

我们也可以简单运行一个 web 示例,比如:

docker run --name aspnetcore_sample --rm -it -p 8000:80 microsoft/dotnet-samples:aspnetapp

应用程序启动后,使用浏览器打开 http://localhost:8000,即可看到以下界面:

Docker 的安装和配置在 Windows 10 操作系统下非常简单,我们也极力推荐大家使用此环境。毕竟,一个好的开发环境可以大大提高大家的使用和开发效率。

 

今天关于Docker最全教程之使用.NET Core推送钉钉消息十九的分享就到这里,希望大家有所收获,若想了解更多关于ASP.NET Core基于Socket实现消息推送实战演练、C#实现推送钉钉消息的方法示例、DingTalk 钉钉消息推送(.net core 3 WebApi 尝鲜记)、Docker 最全教程 —— 从理论到实战(二)等相关知识,可以在本站进行查询。

本文标签: