使用 Cake 推送 NuGet 包到 AzureDevops 的 Artifacts 上

大家好,我最近在想如何提交代码的时候自动的打包 NuGet 然后发布到 AzureDevOps 中的 Artifacts,在这个过程中踩了很多坑,也走了很多弯路,所以这次篇文章就是将我探索的结果和我遇到的一些问题整理分享给大家。

我的上一篇关于 CI/CD 的文章《使用 Gitlab CI/CD 实现自动化发布站点到 IIS》 中是使用脚本的形式实现的,后来有园友在下面评论说可以使用 Cake(C# Make) 这个工具来实现其中的功能,所以本次就不用了脚本了。有时间会使用 Cake 对它进行改造。

整体思路:

  1. 首先介绍下 CakeAzureDevops Pipelines/Artifacts 怎么使用

  2. 接着配置 AzureDevops Pipelines

  3. 创建 AzureDevops Artifacts (NuGet 服务端)

  4. AzureDevops 配置 PAT (Personal Access Tokens) 和 Pipelines 所需的 Variables(变量)

  5. Cake 增加打包、推送 NuGet 包代码。

  6. 最后查看运行结果

使用到的工具及版本:

dotnet core 2.2

cake 0.33.0

PowerShell、NuGet、CredentialProvider

AzureDevops Pipelines 和 AzureDevops Artifacts

  • Cake 的全称是 C# Make,它是一个跨平台的自动化构建系统,基于 C# DSL,所以可以用我们熟悉的 C# 语言来替换掉我们之前使用脚本的构建方式。使用它我们能非常方便的编译代码,复制文件和文件夹,当然还可以运行单元测试以以确保我们的代码没有问题,我们本次的 NuGet 发布到 Artifacts 它占很重要的地位。

  • AzureDevops 的前身是 VSTS,它提供了 Repos、Pipelines、Boards、Test Plans、Artifacts:

    • Repos 提供 Git 存储库,用于代码的源代码控制,你可以直接引入你在 GitHub 上的仓储。

    • Pipelines 提供构建和发布服务,以支持应用程序的持续集成和交付(CI/CD)

    • Boards 提供了一套 Agile 工具,支持使用看板和 Scrum 方法规划和跟踪工作,代码缺陷管理等等,类似的工具有腾讯的 TAPD、阿里的 云效、华为云的 DevCloud 等等。

    • Test Plans 提供了多种测试应用程序的工具,包括手动/探索性测试和持续测试

    • Artifacts 允许团队从公共和私人来源共享 Maven,npm 和 NuGet 包。
      协作工具,包括可自定义的团队仪表板和可配置的小部件,以共享信息,进度和趋势; 用于共享信息的内置 wiki; 可配置的通知等。

  • CredentialProvider 是凭据提供程序,当我们进行 NuGet Push 时需要进行身份验证,只需要将它放在 NuGet 程序的下即可。

本次案例我已经发布到 GitHub 上了:https://github.com/WuMortal/CakePushNuGet.Example

安装:这里我使用 dotnet core 进行演示,cake 还支持 .NET Framework、Mono。首先我们需要安装 cake,借助 dotnet tool 这个命令。

dotnet tool install --global cake.tool --version 0.33.0

安装成功会出现如下提示:

640?wx_fmt=jpeg

cake 的使用方式非常简单,而且还是 C# 语法相信应该是很容易就能理解的。

这里首先定义了一个 target 变量,它里面保存的就是我们将要执行的 Task(任务)的名称。接着可以看到在在代码块中定义了许多的 Task,这里就是具体需要执行的 “任务”,第一个任务是还原项目的依赖,其实核心代码就一行 DotNetCoreRestore(solution);,第二个任务是生成项目,需要说明的是第三个任务其实是将前面两个任务整合到一起。你也可以在中第二个任务 .IsDependentOn ("Restore") 调用第一个任务,当然 var target = Argument ("target", "Demo"); 就需要改为 var target = Argument ("target", "Build"); 了,这个看个人喜好了。

640?wx_fmt=jpeg

var rootPath = "../";var srcPath = rootPath + "src/";var solution = srcPath + "Wigor.CakePushNuGet.Example.sln";var target = Argument ("target", "Demo");Task ("Restore")  .Description ("还原项目依赖")  .Does (() => {        Information ("开始执行还原项目依赖任务");    DotNetCoreRestore (solution);  });Task ("Build")  .Description ("编译项目")  .Does (() => {    Information ("开始执行编译生成项目任务");        DotNetCoreBuild (solution, new DotNetCoreBuildSettings {        NoRestore = true,        Configuration = "Release"    });  });Task ("Demo")  .IsDependentOn ("Restore")  .IsDependentOn ("Build")  .Does (() => {    Information ("所有任务完成");  });RunTarget (target);

cake 编写好后我们就可以尝试运行它,这里我的 cake 路径是 build/build.cake 大家可以根据具体情况更改 ,命令如下:

dotnet cake build/build.cake -verbosity=diagnostic

640?wx_fmt=jpeg

可以看到这里的 cake 已经运行成功了,它会将我们每个任务运行的结果和信息显示在控制台上。

640?wx_fmt=jpeg

到这里相信大家对 cake 是干什么了有点了解吧,有关它跟多的使用方法可以访问官网:https://cakebuild.net/

首先你需要一个 Microsoft 账号或者 GitHub 账号,登录地址为:https://dev.azure.com,登录之后你需要创建一个项目,这里我已经创建好一个项目了,首先我们点击 Pipelines 选择 Builds,之后会出现如下界面,点击 New Pipeline。然后跟着我下面图片的步骤一步一步来就行。

640?wx_fmt=jpeg

如果你的仓储就在 AzureDevops上那么直接选 Azure Repos Git 就行。

640?wx_fmt=jpeg

这里你的账号是 GitHub 授权登录的话会先跳转到授权界面可能会跳转多次,同意即可。

640?wx_fmt=jpeg
640?wx_fmt=jpeg

删除我选中的代码,因为我不打算用 AzureDevops Pipelines 的脚本来执行本次操作,它做的只是提供我们 cake 运行的环境。

640?wx_fmt=jpeg

更换为如下脚本,PowerShell.exe -file ./cake.ps1 是指使用 PowerShell 运行我们的 cake.ps1 文件,关于 cake.ps1 文件后面会介绍,这里我们先这样写,接着点击 Save and run

640?wx_fmt=jpeg

trigger:- masterpool:  vmImage: 'windows-latest'steps:- script: PowerShell.exe -file ./cake.ps1  displayName: 'Push NuGet Package'

可以看到问们管道的运行出现了错误,那是因为我们上面在运行了 cake.ps1 这个脚本,但是我们现在还没有创建这个脚本。

640?wx_fmt=jpeg

回到我们的项目中,将 AzureDevops Pipelines 创建的 azure-pipelines.yml 文件 pull 到我们本地。

640?wx_fmt=jpeg

接着我们编写我们下面缺少的 cake.ps1 文件,它做的事情就是将我们之前手动在 cmd 中运行的命令放入了一个 PowerShell 脚本文件中,Linux 平台的话就编写一个 shell 脚本。

640?wx_fmt=jpeg

dotnet tool install --global cake.tool --version 0.33.0Write-Host "dotnet cake build\build.cake -verbosity=diagnostic" -ForegroundColor GREENdotnet cake build\build.cake -verbosity=diagnostic

尝试项目根目录下运行这个脚本,在 cmd 中执行 powershell .\cake.ps1,下面报了一个错。
640?wx_fmt=jpeg


我们只需要以管理员身份运行 PowerShell 然后执行 set-ExecutionPolicy RemoteSigned 即可

640?wx_fmt=jpeg

640?wx_fmt=jpeg

然后再次运行 powershell .\cake.ps1 或者命令,可以看到正确的输出了

640?wx_fmt=jpeg

OK,这次我们推送(git push)下代码,在到 AzureDevops Pipelines 看看我们执行结果。
640?wx_fmt=jpeg

点进去可以看到整个执行的过程,如果报错了也可以从这里看到出错的信息

640?wx_fmt=png

如果是 powershell 报错 AzureDevops Pipelines 是不会显示执行失败的,如果没得到你想要的结果你就需要点开认真的分析你的脚本了。

前面已经讲过了如果使用 cake 和 在 AzureDevops Pipelines 下执行 cake。下面我们需要创建一个 NuGet Repository,这里我使用 AzureDevops 提供的 Artifacts。

640?wx_fmt=png
640?wx_fmt=jpeg
640?wx_fmt=png

这里面会用的就是 package source URL 和下面命令中的 -ApiKey 中的 AzureDevOps,还有这里我们需要将 NuGet + Credentials Provider 下载到我们的本地,如果你的运行环境是 Linux 或其他可以在 microsoft/artifacts-credprovider 的 GitHub 上获取对应平台的这两个包, 点击查看 GitHub 地址。

上面说过了我们推送 NuGet 包到 Artifacts 时候是需要为两个参数提供指的的 -UserName 和 -Password,这里的 UserName 我们可以随意填,但是 Password 填的的是我们创建的 PAT。

640?wx_fmt=png
640?wx_fmt=jpeg

这是选择我们 PAT 所拥有的权限,需要点击 Show all scopes 找到 Packaging 勾选 Red,wirte,& manage

640?wx_fmt=png

我们可以看到我们的 PAT ,需要注意的是这个 token 只会出现一次,你需要将它保存好,如果忘记了,那么可以点击 Regenerate 重新获取 token。

640?wx_fmt=png

在 上一篇文章 中我说过了为什么需要变量,这里就不重复了,有兴趣的可以看看。下面开始添加我们需要的变量。

640?wx_fmt=png
640?wx_fmt=jpeg

我们需要添加的变量有四个,分别是 NUGET_REPOSITORY_API_URLNUGET_REPOSITORY_API_KEYUSERNAMEPASSWORD

  • NUGET_REPOSITORY_API_URL:就是我们在创建 AzureDevops Artifacts 后出现的 package source URL

  • NUGET_REPOSITORY_API_KEY:就是那个 -ApiKey 参数的值 AzureDevOps

  • USERNAME:这个上面说过了可以随便填。

  • PASSWORD:这个就是之前创建的 PAT。

点击保存(Save & queue)或者 Ctrl + s 保存。

640?wx_fmt=jpeg

这里为已经封装过了的工具类包含了打包和推送方法,地址:NuGet.Tool.cake

using System;using System.Collections.Generic;using System.Linq;using Cake.Common.Tools.DotNetCore;using Cake.Common.Tools.DotNetCore.Pack;using Cake.Common.Tools.NuGet;using Cake.Common.Tools.NuGet.List;using Cake.Core;using NuGet.Packaging;public class NuGetTool {    public ICakeContext CakeContext { get; }    public string RepositoryApiUrl { get; }    public string RepositoryApiKey { get; }    public string UserName { get; set; }    public string Password { get; set; }    private NuGetListSettings ListSettings => new NuGetListSettings {        AllVersions = true,        Source = new string[] { this.RepositoryApiUrl }    };    private DotNetCorePackSettings BuildPackSettings (string packOutputDirectory) => new DotNetCorePackSettings {        Configuration = "Release",        OutputDirectory = packOutputDirectory,        IncludeSource = true,        IncludeSymbols = true,        NoBuild = false    };    private NuGetTool (ICakeContext cakeContext) {        CakeContext = cakeContext;        RepositoryApiUrl = cakeContext.Environment.GetEnvironmentVariable ("NUGET_REPOSITORY_API_URL");        RepositoryApiKey = cakeContext.Environment.GetEnvironmentVariable ("NUGET_REPOSITORY_API_KEY");        UserName = cakeContext.Environment.GetEnvironmentVariable ("USERNAME");        Password = cakeContext.Environment.GetEnvironmentVariable ("PASSWORD");        CakeContext.Information ($"获取所需参数成功:{RepositoryApiUrl}");    }    public static NuGetTool FromCakeContext (ICakeContext cakeContext) {        return new NuGetTool (cakeContext);    }    public void Pack (List<string> projectFilePaths, string packOutputDirectory) {        projectFilePaths.ForEach (_ => CakeContext.DotNetCorePack (_, BuildPackSettings (packOutputDirectory)));    }    public void Push (List<string> packageFilePaths) {        foreach (var packageFilePath in packageFilePaths) {            CakeContext.NuGetAddSource (                "wigor",                this.RepositoryApiUrl,                new NuGetSourcesSettings {                    UserName = this.UserName,                    Password = this.Password                });            CakeContext.NuGetPush (packageFilePath, new NuGetPushSettings {                Source = "wigor",                ApiKey = this.RepositoryApiKey            });        }    }}

在项目的 build/ 下创建 nuget.tool.cake 文件(build/nuget.tool.cake) 拷贝上面的代码。

这里参考了最开始提到的园友的项目,非常感谢它的贡献,GitHub 地址如下:cake.example

在创建 AzureDevops Artifacts 的时候那不是提供了 NuGet + Credentials Provider 的下载地址嘛,现在把它解压到我们项目的 build\tool\ 下。再次说明这里我是 Windows 环境,如果你的运行环境是 Linux 或其他可以在 microsoft/artifacts-credprovider 的 GitHub 上获取对应平台的这两个包, 点击查看 GitHub 地址。

640?wx_fmt=jpeg

修改 cake.ps1,只是增加了 NuGet.exe 的环境变量,因为不加到时候 cake 会找不到 NuGet.exe,或许还有其他办法这里就先这么干,如果各位还有更方便的方法可以在下面留言,感谢!

[string]$SCRIPT = 'build/build.cake'[string]$CAKE_VERSION = '0.33.0'$NUGET_EXE = "build/tool/NuGet.exe"$NUGET_DIRECTORY = Get-ChildItem -Path $NUGET_EXE$NUGET_DIRECTORY_NAME=$NUGET_DIRECTORY.DirectoryName$ENV:Path += ";$NUGET_DIRECTORY_NAME"dotnet tool install --global cake.tool --version $CAKE_VERSION[string]$CAKE_ARGS = "-verbosity=diagnostic"Write-Host "dotnet cake $SCRIPT $CAKE_ARGS $ARGS" -ForegroundColor GREENdotnet cake $SCRIPT $CAKE_ARGS $ARGS

修改 build.cake 文件,看着是多了很多东西其实就多了两个 Task (任务) 分别是: pack(打包) 和 push(推送包),这里需要大家需要修改的就是 solution 和 project 两个变量,将其修改为自己的解决方案名称和需要打包的项目名称。

#reference "NuGet.Packaging"#load nuget.tool.cakevar target = Argument ("target", "PushPack");var rootPath = "../";var srcPath = rootPath + "src/";var solution = srcPath + "Wigor.CakePushNuGet.Example.sln";var project = GetFiles (srcPath + "Wigor.CakePushNuGet.HelloWorld/*.csproj");var nugetPakcageDirectory = $"{srcPath}nugetPackage/";var nugetTool = NuGetTool.FromCakeContext (Context);Task ("Restore")  .Description ("还原项目依赖")  .Does (() => {        Information ("开始执行还原项目依赖任务");    DotNetCoreRestore (solution);  });Task ("Build")  .Description ("编译项目")  .Does (() => {    Information ("开始执行编译生成项目任务");        DotNetCoreBuild (solution, new DotNetCoreBuildSettings {        NoRestore = true,        Configuration = "Release"    });  });Task ("UnitTest")  .Description ("单元测试")  .Does (() => {    Information ("开始执行单元测试任务");        DotNetCoreTest(solution);  });Task ("Pack")  .Description ("Nuget 打包")  .Does (() => {    Information ("开始执行打包任务");        EnsureDirectoryExists (nugetPakcageDirectory);    var packageFilePaths = project.Select (_ => _.FullPath).ToList ();    nugetTool.Pack (packageFilePaths, nugetPakcageDirectory);  });Task ("Push")  .Description ("Nuget 发布")  .Does (() => {    Information ("开始执行 Nuget 包发布任务");    var packageFilePaths = GetFiles ($"{nugetPakcageDirectory}*.symbols.nupkg").Select (_ => _.FullPath).ToList ();    nugetTool.Push(packageFilePaths);  });Task ("PushPack")  .Description ("发布 Nuget 包")  .IsDependentOn ("Restore")  .IsDependentOn ("Build")  .IsDependentOn ("Pack")  .IsDependentOn ("Push")  .Does (() => {    Information ("所有任务完成");  });RunTarget (target);

最后我们推送修改后的代码,查看执行结果看看 NuGet 包是否发布到 AzureDevops Artifacts 上。

640?wx_fmt=png

至此已经实现了 使用 Cake 推送 NuGet 包到 AzureDevops 的 Artifacts 上,你如果不熟悉 AzureDevops Pipelines 你也可以用其他的 CI/CD 工具来执行。

在整个尝试过程中肯定会出现一些问题,不要着急认真分析,看看 AzureDevops Pipelines 上给出的提示,也可以现在本机跑一下看看是否正常。出现问题第一步查看错误信息,看看有没有错误信息(基本都有),然后根据错误信息去分析是我们的那个地方出错了,顺序是 cake.ps1 --> build.cake --> nuget.tool.cake,然后是所需的 PAT 的权限是否勾选,AzureDevops Pipelines 变量是否配置并且是 URL、Key 什么的都是正确,再然后就是 百度、Google。最后你可以在评论区留言(分享你碰到的问题以及解决方法)。

原文地址:https://www.cnblogs.com/AMortal/p/11100669.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/315141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

了解Kubernetes主体架构(二十八)

前言 Kubernetes的教程一直在编写&#xff0c;目前已经初步完成了以下内容&#xff1a;1&#xff09;基础理论2&#xff09;使用Minikube部署本地Kubernetes集群3&#xff09;使用Kubeadm创建集群接下来还会逐步完善本教程&#xff0c;比如Helm、ELK、Windows Serv…

Codeforces Round #632 (Div. 2) F. Kate and imperfection 数论 + 贪心

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; n≤5e5n\le5e5n≤5e5 思路&#xff1a; 首先有个显然的结论&#xff1a;当往集合中加入一个数xxx的时候&#xff0c;如果存在d∣xd|xd∣x且ddd不在集合中&#xff0c;那么加入ddd一定比加入xxx更优。 也就是…

.NET开发框架(二)-框架功能简述

本框架为响应式SPA框架&#xff0c;支持PC与手机端的屏幕自适应。手机展示效果视频在文章末尾查看。框架入口地址&#xff1a;http://letyouknow.net/1、框架登录界面&#xff0c;输入账号与密码&#xff0c;点击立即登录2、框架主界面&#xff0c;左-右结构&#xff0c;左边为…

Codeforces Round #632 (Div. 2) E. Road to 1600 构造好题

传送门 文章目录题意&#xff1a;思路题意&#xff1a; 直接白嫖 思路 首先不难发现&#xff0c;n≤2n\le2n≤2的时候是无解的。 现在我们来构造n3n3n3的情况&#xff0c;通过打表可以发现如下矩阵是符合题目要求的&#xff1a; 179325486\begin{array}{ccc} 1&7&9…

SiteServer CMS 新版本 V6.11(2019年7月1日发布)

欢迎来到 SiteServer CMS V6.11版本&#xff08;.NET CORE V7.0预览版本将推迟至2019年9月1日发布&#xff09;&#xff0c;经过两个月的连续迭代开发&#xff0c;V6.11 版本新增了采集插件以及多项BUG修复&#xff1a;SS.Gather 页面采集插件页面采集插件将在V6.11版本中正式提…

P1020 [NOIP1999 普及组] 导弹拦截 Dilworth定理 + dp

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 对于第一问直接输出最长不严格下降子序列即可&#xff0c;第二问是Dilworth定理&#xff0c;变形比较多&#xff0c;之前也写过类似的&#xff0c;这里贴个证明。 //#pragma GCC optimiz…

参数传递机制之JWT

1. 什么是 JWTJWT 其全称为&#xff1a;JSON Web Token&#xff0c;简单地说就是 JSON 在 Web 上的一种带签名的标记形式。官方的定义如下&#xff1a;JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.…

Codeforces Round #709 (Div. 1) B. Playlist 链表维护 + bfs

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 紧跟刘爷脚步补题。 不难想到用链表维护下一个数是什么&#xff0c;这样就跟以前做过的一个题差不多了&#xff0c;首先将初始的时候删掉的点的前一个点即为题目中的AAA入队&#xff0c;让…

浅谈ASP.NET Core中IOC与DI的理解和使用

说起IOC和DI,使用过ASP.NET Core的人对这两个概念一定不陌生&#xff0c;早前&#xff0c;自己也有尝试过去了解这两个东西&#xff0c;但是一直觉得有点很难去理解&#xff0c;总觉得对其还是模糊不清&#xff0c;所以&#xff0c;趁着今天有空&#xff0c;就去把两个概念捋清…

一个通用数据库操作组件DBUtil(c#)、支持SqlServer、Oracle、Mysql、postgres、SQLITE

这是一个.net下操作数据库(结构数据库)的工具类&#xff0c;支持sqlserver、oracle、mysql、postgres、sqlite、access等常见数据库。注意&#xff1a;它并不是一个orm工具(常见的orm框架如&#xff1a;EF、Dapper等)。2.1 引入DBUtil依赖1. 首先打开vs(推荐vs2019)&#xff0c…

Educational Codeforces Round 37 (Rated for Div. 2) E. Connected Components? 暴力 + 补图的遍历

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; n≤2e5,m≤2e5n\le2e5,m\le2e5n≤2e5,m≤2e5。 思路&#xff1a; 这是题是我上个题的一部分&#xff0c;算是个小知识点&#xff0c;暴力能过。 直接维护一个setsetset&#xff0c;让后遍历所有点&#xff…

初探System.Threading.Channels

。System.Threading.Channels是.Net Core基础类库中实现的一个多线程相关的库&#xff0c;专门处理数据流相关的操作&#xff0c;用来在生产者和订阅者之间传递数据&#xff08;不知道可不可以理解为线程间传递数据&#xff0c;我把它类比成了Go语言中的Channel&#xff09;&am…

Codeforces Round #715 (Div. 1) B. Almost Sorted 找规律

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 找规律yydsyydsyyds。 一看没什么想法&#xff0c;所以打了个表&#xff0c;好家伙&#xff0c;不打不知道&#xff0c;一打不得了&#xff0c;下面是n6n6n6的符合要求的情况&#xff1a; …

SQL Server之索引解析(二)

、堆表堆表通过IAM连接一起&#xff0c;查询时全表扫描。1、1 非聚集索引结构叶子节点数据结构&#xff1a;行数据结构Rid&#xff08;8字节&#xff09;中间节点数据结构&#xff1a; &#xff08;非聚集非唯一索引&#xff09;行数据结构Page&#xff08;4&#xff09;2 Rid&…

纠正一个错误,分布式系统关注点第17篇

这里是Z哥的个人公众号每周五早8点 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「78」篇原创敬上今天来加个餐&#xff0c;紧急纠正一个错误。先和大家说一声抱歉&#xff1a;D昨晚睡觉前&#xff0c;惯例打开「订阅号助手」回复一些留言。有一位小伙伴提了…

【NOI2016】国王饮水记【贪心】【斜率优化】【决策单调性】

传送门 首先比h1h_1h1​小的肯定没用&#xff0c;直接无视 然后考虑合并的顺序 ①在无限制的情况下&#xff0c;合并多个不如一个一个合并 a<b<ca<b<ca<b<c时&#xff0c;ab2c2>abc3{{ab \over 2}c\over 2}>{{abc}\over 3}22ab​c​>3abc​ ②先…

CF946D Timetable 背包dp + 思维转换

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; n,m,k≤500n,m,k\le500n,m,k≤500 思路&#xff1a; 将其转换成背包的模型&#xff0c;就可以想出来一个很明显的dpdpdp状态&#xff1a;f[i][j]f[i][j]f[i][j]表示前iii行花费了jjj的最小代价&#xff0c;…

.NET开发框架(三)-高可用服务器端设计

我们对框架功能作了简述&#xff0c;演示视频请点击 这里查看 &#xff0c;本章节&#xff0c;我们专门讲解一下&#xff0c;如何在Window服务器下&#xff0c;设计高可用的框架。我们的框架设计采用的是Window版本的服务端设计&#xff1a;整体框架图如下&#xff0c;为什么我…

P1537 弹珠 背包可行性dp

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 疯狂水文章。 这个很明显是个背包&#xff0c;我们开一个布尔数组&#xff0c;之后枚举每组的个数&#xff0c;让后枚举1−61-61−6&#xff0c;再枚举容量kkk&#xff0c;注意顺序不能错了…

.NET Core 3.0中的WinForms创建集中式拉取请求中心

Windows 窗体&#xff08;或简称 WinForms&#xff09;&#xff0c;多年来被用于开发具有丰富和交互式界面的基于 Windows 的强大应用程序。各类企业对这些桌面应用程序的投入量非常巨大&#xff0c;每月有大约 240 万开发人员使用 Visual Studio 创建桌面式应用。利用和扩展现…