<?xml version="1.0" encoding="utf-16"?><feed xmlns="http://www.w3.org/2005/Atom"><title>HueiFeng</title><subtitle>冯辉,HueiFeng,.NET,.NET Core,Docker,k8s</subtitle><rights>(c) {year} Moonglade</rights><updated>2026-04-07T19:57:24Z</updated><generator uri="https://hueifeng.azurewebsites.net">Moonglade v11.2-preview</generator><entry><id>C1B5F49D-A33A-405D-B2A9-E6F2665927D3</id><title>把 Kubernetes 的调度思想带入 .NET：开源分布式任务框架 KubeJob 正式发布！</title><updated>2026-03-07T10:31:10Z</updated><published>2026-03-07T10:31:10Z</published><link href="https://hueifeng.azurewebsites.net/post/2026/3/7/bringing-kubernetes-scheduling-to-dotnet-with-kubejob" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><category term="C#" /><content>背景与痛点：我们为什么又造了一个“轮子”？
在 .NET 生态中，提到后台任务调度，我们通常会想到 Quartz.NET、Hangfire 或者是 ASP.NET Core 自带的 BackgroundService。它们都非常优秀，但在现代云原生和微服务架构下，我们有时会面临一些新的挑战：
原生定时器的局限：简单的 Timer 或 IHostedService 缺乏分布式协调能力，多实例部署时容易导致任务重复执行，且没有可视化界面监控状态。
传统框架的厚重：某些成熟的调度框架与特定存储或设计模式深度绑定，对于只需要轻量级分布式调度和可视化管理的团队来说，接入成本较高。
缺乏现代化的调度策略：在集群环境中，我们往往希望任务能像 Kubernetes 调度 Pod 一样，具有“节点标签选择 (Node Selector)”、“广播执行 (Broadcast)”、“分片执行 (Sharded) …</content></entry><entry><id>8D903473-C3B6-49F2-B1CA-96762D184F2C</id><title>.NET解决方案格式升级：SLN与SLNX</title><updated>2025-03-22T15:01:44Z</updated><published>2025-03-22T15:01:44Z</published><link href="https://hueifeng.azurewebsites.net/post/2025/3/22/dotnet-solution-format-upgrade-sln-vs-slnx" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><content>在.NET开发中，解决方案文件（.sln）长期扮演着工程管理的核心角色。但随着项目复杂度提升，传统文本格式的局限性逐渐显现。微软推出的新一代SLNX格式，以XML为基础重构了解决方案的表示方式，我们通过一个简单示例观察其改进。
原‌Sln
以下是一个包含一个csproj的传统解决方案文件片段：
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.35906.104 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project({FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}) = ConsoleApp1, ConsoleApp1\ …</content></entry><entry><id>56123997-33D1-4F2D-BC49-FCC63B29986C</id><title>Visual Studio项目文件中的SCC配置属性</title><updated>2025-03-21T08:52:19Z</updated><published>2025-03-21T08:52:19Z</published><link href="https://hueifeng.azurewebsites.net/post/2025/3/21/visual-studioscc-560ba2e3" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><content>Visual Studio 项目文件 SCC 属性配置指南
一、SCC 属性概述
在传统的 .csproj/.vbproj 项目文件中，&lt;PropertyGroup Label="Globals"&gt; 节点下的 ‌SCC 属性‌用于定义项目与源代码控制系统（如 TFS、SVN、VSS 等）的集成配置。这些属性常见于旧版 Visual Studio（2010-2017）创建的项目，对团队协作开发至关重要。
二、核心属性详解
1. &lt;SccProjectName&gt;
▫️ 作用
定义项目在源代码控制系统中的‌唯一标识名称‌，对应服务端存储路径的映射标识。
▫️ 典型值
SccProjectNameMyProject/Trunk/Source/SccProjectName
当值为 SAK（Should Already Know）时，表示 IDE 应自动识别绑定关系。
2. &lt;SccProvider&gt; …</content></entry><entry><id>CF239415-18C6-4F58-8316-2568E1207954</id><title>理解并掌握C#的Channel：从使用案例到源码解读（一）</title><updated>2023-09-24T15:33:35Z</updated><published>2023-09-24T15:33:35Z</published><link href="https://hueifeng.azurewebsites.net/post/2023/9/24/mastering-csharp-channels-part-one" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><content>引言
在C#的并发编程中，Channel是一种非常强大的数据结构，用于在生产者和消费者之间进行通信。本文将首先通过一个实际的使用案例，介绍如何在C#中使用Channel，然后深入到Channel的源码中，解析其内部的实现机制。
使用案例一：文件遍历和过滤
在我们的使用案例中，我们需要遍历一个文件夹及其所有子文件夹，并过滤出具有特定扩展名的文件。在此，我们使用了C#的Channel来实现这个任务。
首先，我们创建了一个名为EnumerateFilesRecursively的方法，这个方法接受一个文件夹路径作为参数，并返回一个ChannelReader&lt;string&gt;。这个方法中，我们创建了一个有界的Channel，然后在一个单独的任务中遍历指定的文件夹及其所有子文件夹，并将找到的每个文件的路径写入Channel。当遍历完成后，我们关闭Channel的写入端。 …</content></entry><entry><id>874735CB-D6B6-4C40-9A8C-0CD9F15E1D5E</id><title>.NET对象的内存布局</title><updated>2023-08-06T14:14:48Z</updated><published>2023-08-06T14:14:48Z</published><link href="https://hueifeng.azurewebsites.net/post/2023/8/6/dotnet-objectmemory-layout" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><category term="C#" /><content>在.NET中，理解对象的内存布局是非常重要的，这将帮助我们更好地理解.NET的运行机制和优化代码，本文将介绍.NET中的对象内存布局。
.NET中的数据类型主要分为两类，值类型和引用类型。值类型包括了基本类型（如int、bool、double、char等）、枚举类型（enum）、结构体类型（struct），它们直接存储值。引用类型则包括了类（class）、接口（interface）、委托（delegate）、数组（array）等，它们存储的是值的引用（数据在内存中的地址）。
值类型的内存布局
值类型的内存布局是顺序的，并且是紧凑的。例如，定义的结构体SampleStruct，其中包含了四个int类型字段，每个字段占用4个字节，因此整个SampleStruct结构体在内存中占用16个字节。
public struct SampleStruct
{
    public int Value1; …</content></entry><entry><id>4CDA38FE-CBD2-4906-B095-E9B6ED245E48</id><title>C#抽象静态方法</title><updated>2023-07-15T14:18:18Z</updated><published>2023-07-15T14:18:18Z</published><link href="https://hueifeng.azurewebsites.net/post/2023/7/15/csharp-static-abstract" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><content> 抽象静态方法
在C# 11中，引入了对抽象静态接口成员的支持。这个特性可以让你在接口中定义静态抽象方法、属性、或事件。具体来说，一个接口可以定义一个或多个抽象静态成员，这些成员没有具体的实现。任何实现该接口的类或结构必须提供这些成员的静态实现。这就像实现普通接口成员一样，只不过是静态的。当然，你也可以基于它来实现一些设计模式，本文将展开介绍。
单例模式：静态抽象成员可以用于实现单例模式。在这种模式中，一个类只能有一个实例，并提供一个全局访问点。
public interface ISingleton
{
    static abstract ISingleton Instance { get; }
}

public class Singleton : ISingleton
{
    private static readonly Singleton _instance = new …</content></entry><entry><id>1E4C7792-92DC-449C-BD24-0F0A8A79C9D4</id><title>.NET Native AOT的静态库与动态库</title><updated>2023-05-16T14:18:48Z</updated><published>2023-05-16T14:18:48Z</published><link href="https://hueifeng.azurewebsites.net/post/2023/5/16/net-native-aot" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><content>.NET不仅可以使用 C静态库与动态库，也可以将.NET实现的函数导出为C静态库与动态库。在没有Native Aot之前，.NET只能通过P/Invoke享受C/C++生态，而在Native Aot之后，不仅可以享受这些生态，还可以开发SDK供其他语言调用。
.NET Native AOT的NativeLib参数用于指定本机库的类型。在.NET 7中，该参数有两个选项：Static和Shared。
Static: 生成静态库，意味着所有依赖项都将被编译到生成的可执行文件中，因此它更适合独立应用程序或需要最小化依赖项的应用程序。
Shared: 生成动态库，意味着依赖项将被编译为单独的本机库，并在运行时动态加载。这种方法可以减少生成文件大小，并且更适合需要共享依赖项的应用程序，所以它也被称为共享库。
使用UnmanagedCallersOnly特性可以将C#函数导出提供给C调用， …</content></entry><entry><id>91EA438E-0A40-4C89-B670-D1ADBC798DFC</id><title>使用dotnet-monitor分析在Kubernetes的应用程序：Sidecar模式</title><updated>2022-08-17T15:32:36Z</updated><published>2022-08-17T15:32:36Z</published><link href="https://hueifeng.azurewebsites.net/post/2022/8/17/dotnetmonitorkubernetessidecar" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><content>dotnet-monitor可以在Kubernetes中作为Sidecar运行，Sidecar是一个容器，它与应用程序在同一个Pod中运行，利用Sidecar模式使我们可以诊断及监控应用程序。
如下图所示，这是我们最终要实现的目标，通过可视化界面查看应用程序的指标信息。
file
应用服务
创建dotnetmonitor.yaml文件，如下所示。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dotnet-monitor-example
spec:
  replicas: 3
  selector:
    matchLabels:
      app: dotnet-monitor-example
  template:
    metadata:
      annotations:
        prometheus. …</content></entry><entry><id>83A2614E-9688-41C8-8C41-C587502BAA4A</id><title>wsl2 内存限制</title><updated>2022-07-27T15:21:00Z</updated><published>2022-07-27T15:21:00Z</published><link href="https://hueifeng.azurewebsites.net/post/2022/7/27/limit-wsl-memory" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term="Docker" /><content>在C:\Users\&lt;UserName&gt;\.wslconfig创建一个文件，配置如下所示。
[wsl2]
memory=4GB
swap=8GB
swap类似于Windows的虚拟内存，从硬盘中划分出一个分区，在物理内存不够时，就会将硬盘空间虚拟成内存使用，用于解决内存不足的情况。
配置格式：
[wsl2]
memory=size              
processors=number       
swap=size                
localhostForwarding=bool
在配置设置完之后，执行wsl --shutdown命令进行关闭，随后执行wsl命令再次启动即可。
memory：限制内存
swap：交换分区
processors：限制核心数
localhostForwarding：关闭默认连接，将WSL2本地主机绑定到Windows本地主机
</content></entry><entry><id>91BCF231-42C7-4C0B-A149-9A957A539874</id><title>利用Windbg分析Magicodes.IE一次错误编写导致内存问题</title><updated>2021-12-11T06:54:45Z</updated><published>2021-12-11T06:54:45Z</published><link href="https://hueifeng.azurewebsites.net/post/2021/12/11/windbgmagicodesie" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><content>由于这近一年时间一直忙于写书和工作，一直没有水文，但是近期有几位朋友使用我们的Magicodes.IE反馈在导出过程中内存暴涨...好吧，不管怎样，不能苦了我们朋友，接下来我们通过windbg来看一下什么原因导致的。
接下来我们先通过address -summary来看一下当前应用内存占用量。
0:000 !address -summary

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free                                    581     7df8`ef0c9000 ( 125.972 TB)           98.42%
unknown                              1678 …</content></entry><entry><id>6B08EC4E-24A5-4BB3-ADF7-F8D07619F5C1</id><title>【Azure DevOps系列】Azure DevOps构建.NET EFCore应用程序</title><updated>2021-05-30T04:46:38Z</updated><published>2021-05-30T04:46:38Z</published><link href="https://hueifeng.azurewebsites.net/post/2021/5/30/azure-devopsazure-devopsnet-efcore" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><category term=".NET5" /><category term="ASP.NET CORE" /><category term="Azure" /><category term="ASP.NET Core 5.0" /><content>本章我们将看到如何通过Azure DevOps使用EFCore CLI工具将我们的EFCore应用程序进行数据库重建，当然这种操作我不建议使用，建议使用CLI生成sql脚本形式进行发布并迁移。
设置代理服务器sdk
- task: UseDotNet@2
  inputs:
    packageType: 'sdk'
    version: '3.x'
安装dotnet-ef
安装Entity Framework Core CLI工具，用于后面对数据库的操作
- task: CmdLine@2
  displayName: 'install dotnet-ef'
  inputs:
    script: 'dotnet tool install -g dotnet-ef'
删除数据库
 dotnet ef database drop --project &lt;path to your …</content></entry><entry><id>41F9E03F-7E43-4184-BA3C-B771401053C4</id><title>.NET RulesEngine（规则引擎）</title><updated>2021-04-29T15:13:59Z</updated><published>2021-04-29T15:13:59Z</published><link href="https://hueifeng.azurewebsites.net/post/2021/4/29/dotnetnet-rulesengine" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><category term=".NET5" /><content>一次偶然的机会，让我拿出RulesEngine去完成一个业务，对于业务来说主要是完成一个可伸缩性（不确定的类型，以及不确定的条件，条件的变动可能是持续增加修改的）的业务判断。比如说完成一个成就系统，管理员可创建，对于成就来说有一次性解锁、日常、周常式，还有随时重置，每次达成都触发的，面对着成就任务的增加，那对于程序员来说，如果每次都去增加修改这些成就任务简直是太头疼了。好了，对此大家应该有一个简单的了解了，那跟着笔者往下走，我们看看如何在.NET中使用非常少的代码去完成一个简单的动态逻辑处理。
RulesEngine 概述
RulesEngine是Microsoft推出的一个规则引擎项目，用于系统中抽象出的业务逻辑/规则/策略。在我们开发的过程中，避免不了的是跟这种反反复复的业务逻辑进行处理，而对于这种动态的规则来说的话，它是比较优雅的一种方式，使用我们减少了对我们代码或者说项目的修改。 …</content></entry><entry><id>A4118DBF-0C7B-4658-9017-F8498E038D60</id><title>在ASP.NET Core中使用ViewComponent</title><updated>2021-04-10T03:40:30Z</updated><published>2021-04-10T03:40:30Z</published><link href="https://hueifeng.azurewebsites.net/post/2021/4/10/using-viewcomponents-in-asp-net-core" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term="ASP.NET MVC" /><category term=".NET" /><category term="ASP.NET CORE MVC" /><category term=".NET5" /><category term="ASP.NET CORE" /><category term="ASP.NET Core 5.0" /><content>前言
在之前的开发过程中，我们对于应用或者说使用一些小的组件，通常使用分布页（partial view），再往前在Web Form中我们会进行应用WEB Control，好吧提及一个关键性代码TagPrefix：TagName，通过这种的标记我们便可以在我们web form中进行引入我们的组件，当然自从.NET MVC之后呢，就已经没有了WebControl，而对于.NET Core后，又多了一个特性ViewComponent。
对于ViewComponent看起来它类似于小的控制器，而对于我们小的组件或者小部分通用型功能，可通过ViewComponent进行实现，比如说留言栏、菜单等等。
ViewComponent是由两部分组成，一部分是类（通常该类集成与ViewComponent），而另外一部分是视图（Razor和普通的View一样），当然ViewComponent同样也支持POCO， …</content></entry><entry><id>88056697-3937-49EA-9257-07B3FEA3F28F</id><title>.NET初探源代码生成（Source Generators）</title><updated>2021-03-16T12:43:48Z</updated><published>2021-03-16T12:43:48Z</published><link href="https://hueifeng.azurewebsites.net/post/2021/3/16/generating-code-in-dotnet" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><category term=".NET5" /><category term="ASP.NET CORE" /><content>前言
Source Generators顾名思义代码生成器，可进行创建编译时代码，也就是所谓的编译时元编程，这可让一些运行时映射的代码改为编译时，同样也加快了速度，我们可避免那种昂贵的开销，这是有价值的。
实现ISourceGenerator
集成ISourceGenerator接口，实现接口用于代码生成策略，它的生命周期由编译器控制，它可以在编译时创建时创建并且添加到编译中的代码，它为我们提供了编译时元编程，从而使我们对C#代码或者非C#源文件进行内部的检查。
    [Generator]
    class CustomGenerator: ISourceGenerator
    {
        public void Initialize(GeneratorInitializationContext context)
        {
            throw …</content></entry><entry><id>7946ECA2-A86C-4CE0-AB9E-0FCC73CBDFA6</id><title>.NET探索模型路由约定实现伪静态</title><updated>2021-02-19T10:49:28Z</updated><published>2021-02-19T10:49:28Z</published><link href="https://hueifeng.azurewebsites.net/post/2021/2/19/dotnet-implement-url-rewrite" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><category term=".NET5" /><category term="ASP.NET CORE" /><category term="ASP.NET Core 5.0" /><content>概述
IPageRouteModelConvention接口用于自定义PageRouteModel，这个对象在Microsoft.AspNetCore.Mvc.ApplicationModels命名空间中，
代表着Razor Page路由设置，换句话说我们可以通过实现该接口覆盖默认的实现。
该接口需要实现一个成员void Apply(PageRouteModel model)。通过这个方法，我们可以访问有关当前路由设置的元数据，并根据需要对其内容进行修改。
下面示例，将解决提供一个伪静态的解决方案，因此我们可以通过index.html about.html....去访问我们的页面，也就是说我们可以从Index-Index.html的支持
    public class HtmlExtensionPageRouteModelConvention : …</content></entry><entry><id>67B3E5EA-90EC-45AD-9266-9A3D0AA8A13E</id><title>.NET中使用DebuggerDisplay轻松定制调试</title><updated>2021-02-12T12:46:59Z</updated><published>2021-02-12T12:46:59Z</published><link href="https://hueifeng.azurewebsites.net/post/2021/2/12/debugging-your-dotnet-application-more" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><category term=".NET5" /><content>前言
对于调试的方式有多种，不过在今天我们将看到的监视窗口对变量的监视，当然在这里我们是定制内部的变量值，或者说变量的显示与计算的内容。
注：监视窗口在调试时可以一次显示多个变量。“快速监视”对话框一次显示一个变量。
file
DebuggerDisplayAttribute
在下面示例中，我们在类上添加DebuggerDisplay，添加字符串：("Name={Name},Age={Age}")：
 class Program
    {
        static void Main(string[] args)
        {
            Student student = new Student()
            {
                Name = Mr.A,
                Age = 18
            }; …</content></entry><entry><id>F7306072-050F-488B-B2B2-39CCF78275FA</id><title>.NET探索平台条件编译</title><updated>2021-01-17T14:36:04Z</updated><published>2021-01-17T14:36:04Z</published><link href="https://hueifeng.azurewebsites.net/post/2021/1/17/dotnet-exploration-platform-condition-compilation" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><content>前言
今天偶然机会，翻了一下大学期间的书籍《C程序设计》，好吧，当我翻着翻着，翻到了符号常量（#define指令）中，是啊，这是一个预处理器指令，记得在Magicodes.IE中针对平台选择不同的库，哈哈，这是一个典型的根据平台进行条件处理，好吧，
根据这些内容，让我感觉在今天，我需要对#define指令以及在.NET中的平台条件处理，以及平台的条件编译进行记录一下。
file
define
我们可通过define来定义符号，然后将符号用在#if指令表达式中，如下所示：
#define PI
通过上面这些内容可能很难去了解这该如何使用，其实#define在我们的编码过程中也是很少去使用的，我们继续往下看。
其实对于预处理器，在我们调试以及运行时的作用是比较大的，比如说对某些代码限制编译，另一方变其实还可以对代码进行环境或者版本的控制，这些都是Ok的，最后我们结合着控制语句#if来看一下: …</content></entry><entry><id>BF6EB13E-F56A-4F9B-AB2E-5F930856FA9E</id><title>【Azure DevOps系列】Azure DevOps EFCore命令式脚本部署到SQL数据库</title><updated>2020-12-09T13:23:52Z</updated><published>2020-12-09T13:23:52Z</published><link href="https://hueifeng.azurewebsites.net/post/2020/12/9/azure-devopsazure-devops-efcoresql" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term="Azure" /><category term="DevOps" /><content>构建迁移脚本
为了构建迁移脚本，我们将需要使用EF Tools for Command Line Interface。这些工具在Microsoft.EntityFrameworkCore.Tools提供。
迁移脚本
现在我们将通过 dotnet ef migrations script –p path to your csproj with migrations -o $(Build.ArtifactStagingDirectory)\migrations\scripts.sql –i来迁移我们的脚本，在如下代码片段中我将脚本进行迁移出来并且输出到指定的路径 -o $(Build.ArtifactStagingDirectory)/migrations/scripts.sql中，	-i代表生成可用于任何迁移的数据库的脚本。
 - task: CmdLine@2 …</content></entry><entry><id>2E963547-9B39-46BD-B93A-8AEC8FFA127D</id><title>探索.NET平台中的SIMD内在函数Vector</title><updated>2020-12-01T02:57:11Z</updated><published>2020-12-01T02:57:11Z</published><link href="https://hueifeng.azurewebsites.net/post/2020/12/1/netsimdvector" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term=".NET" /><category term=".NET5" /><content>概述
Vector（向量）是一种序列式容器，事实上和数组差不多，但它比数组更优越。一般来说数组不能动态拓展，因此在程序运行的时候不是浪费内存，就是造成越界。而Vector刚好弥补了这个缺陷，它的特征是相当于可分配拓展的数组（动态数组），它的随机访问快，在中间插入和删除慢，但在末端插入和删除快。
什么是SIMD？
SIMD是Single Instruction Multiple Data的缩写，通常中文译为单指令多数据流，通俗来讲的话是：对多个数据执行同一个CPU指令，以达到平行运算的目的.
在GPU之前我们会通过CPU来运行该项技术来增加图片的运算速度，例如Intel的MMX、SSE、SSE2、AVX，AMD的3DNow!等等，都是来使用SIMD
为基础的概念，在GPU技术突飞猛进的今天，CPU的SIMD技术很少用在了图片运算方面了，更多的是在资料库或者其他用途上。
SIMD
它适用于机器 …</content></entry><entry><id>82DC7BE7-292B-48F4-9192-82128D27D220</id><title>Vs编译时RazorTagHelper - DOTNET_HOST_PATH is not set</title><updated>2020-11-17T12:26:11Z</updated><published>2020-11-17T12:26:11Z</published><link href="https://hueifeng.azurewebsites.net/post/2020/11/17/vs-razortaghelper-dotnethostpath-is-not-set" /><author><name>HueiFeng</name><email>695979933@qq.com</email></author><category term="ASP.NET CORE MVC" /><category term="ASP.NET CORE" /><content>今天听朋友说遇到一个问题，打开一个aspnetcore2.2的项目工程，发现挺有意思，缺少环境变量DOTNET_HOST_PATH
file
严重性	代码	说明	项目	文件	行	禁止显示状态
错误	MSB4018	“RazorTagHelper”任务意外失败。
System.InvalidOperationException: DOTNET_HOST_PATH is not set
   在 Microsoft.AspNetCore.Razor.Tasks.DotNetToolTask.get_DotNetPath()
   在 Microsoft.AspNetCore.Razor.Tasks.DotNetToolTask.GenerateFullPathToTool()
   在 Microsoft.Build.Utilities.ToolTask.ComputePathToTool() …</content></entry></feed>