之前一直用FineUICore做框架,系统登录,人员 字典 菜单 权限管理啥的,公司也一直在用,但是框架分散在各项目不好维护,所以个给组件化了,在项目中引用,并且打包放在了公司的服务器上,这里做个积累

1. 组件化

之前一直不知道MVC(带Controller)的项目怎么像dll一样给另一个项目引用并加载视图,直到学习了从零开始实现ASP.NET Core MVC的插件式开发

只要跟着文章一点点试就能出来,这里要注意使用框架项目和实例项目要使用同样的包引用和.net版本否则编译不了

最后像这样 (HD_System 就是编译好的组件)

 var assembly = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "HD_System.Web.dll");
 
services.AddControllers(option =>
{
    option.Filters.Add(typeof(GlobalExceptionsFilter));
}).AddNewtonsoftJson(opt =>
{
    //忽略循环引用
    opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    //不改变字段大小
    opt.SerializerSettings.ContractResolver = new DefaultContractResolver();
    //不改变字段大小
    //opt.SerializerSettings.ContractResolver = new CustomContractResolver();
})
.AddApplicationPart(assembly);

这里带来的问题是 每次框架项目(HDSystem)修改都要复制dll到各实例项目,要复制一堆,前期我写了个 bat 的脚本,在项目编译前复制文件到项目的 bin 目录下,但是每个项目都在本地写脚本对于多人异地开发带来不便,这里就用到 Nuget 包管理

2. 打包管理

2.1 安装Nuget私服

由于只供本地使用,所以搭建本地的Nuget服务器 BaGet ,官网了搭建流程非常详细,这里不做说明;把发布的包下下来,摁到服务器上发布就行了,这个项目也是用.net写的,直接 dotnet BaGet.dll 就行了;

然后再VS2022中配置私服地址,可以看这里 基于 BaGet 搭建 Nuget 服务器

在Baget的配置(appsettings.json)中,我只修改了一个配置 "AllowPackageOverwrites": true,允许包覆盖 因为可能上传的版本老是修改 懒的改版本号;

2.2 打包发布命令

我还学习研究了官方的 Nuget命令 ;看的不老懂的

这里我还是使用了git钩子,由于源码传到Linux服务器(CentOS7),这里上传后直接触发脚本打包并发布到Nuget私服

通过脚本进行项目的打包 即 dotnet pack 命令,注意要 cd 到项目目录下,如:


echo '-------------开始打包---------------'

#打包后地址
PackagePath='/home/HD_System/NugetPackage'

#运行打包
cd /home/HD_System/HD_System/HD.Commons

#dotnet pack 项目文件 --output 地址
dotnet pack HD.Commons.csproj --output $PackagePath

最后推送到服务器

echo '-------------开始推送-------------'
cd $PackagePath
dotnet nuget push "*.nupkg" -s http://127.0.0.1:9090/v3/index.json --skip-duplicate

3. 问题

正常到这里项目就能拉到了,一安装就可以用了,然后问题就来了;

3.1 版本号

遇到的第一个问题是版本号,由于框架项目也是多一个项目(.csproj,比如 公共库 业务 UI扩展 Web项目)组成
,互相引用,每个项目都单独发包了(解耦),这里要注意 底层项目的版本号变更,上层的也要变更,否则上层项目打包之后 会提示 找不到版本(他会找旧的库),

因为 dotnet pack 时如果当前项目的版本号没有更新,它是不重新编译的,只会把缓存直接拿出来告诉你打包完了,其实包没变,所以引用的还是旧版的基础包;

关于版本号,只要在vs中双击项目,直接修改就行了

<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <Authors>没想好</Authors>
	    <Title>HD_System 框架基础文件</Title>
        <Version>1.0.1.24</Version>
    </PropertyGroup>
</Project>

3.2 静态文件打包

微软官方的教程里 说 dotnet pack 不能打包Web项目,只能打包类库,但是我一开始就要解决的是 Web项目组件化 ,实例项目读取的是动态的 dll 文件 ,而不是引用该dll

 var assembly = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "HD_System.Web.dll");

所以Web项目生成的dll文件,只作为静态文件就可以了,在实例项目运行时将文件复制到发布目录即可;同样 js css 图片文件(FineUI环境)也是静态文件,这些文件要复制到项目的wwwroot下,并且要保持路径;(这两个需求我测试70多个版本,终于成功了)

思路是原框架项目在服务编译发布(不是打包),得到 dll 和 wwwroot ;将静态文件 复制到一个空项目下,由该空项目执行打包,读取的配置文件是.nuspec,执行的规则是.targets

首先新建 文件夹 WebNuspec,包含文件如下

build
    ∟--HD_System.Web.dll        --静态dll
    ∟--HD_System.Web.targets    --规则
    ∟--wwwroot                  --静态文件
        ∟--res...               --js等
contentFiles
    ∟--any
        ∟--any
            ∟--wwwroot          --静态文件 同上
                ∟--res...
HD_System.Web.nuspec            --配置
WebNuspec.csproj                --空项目

HD_System.Web.nuspec 文件内容

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
  <metadata>
    <id>HD_System.Web</id>
    <version>1.0.1.24</version>
    <contentFiles>
      <files include="*.dll" buildAction="Build"></files>
      <files include="**/*" buildAction="None"   />
      <files include="HD_System.Web.targets" buildAction="Build"></files>
    </contentFiles>
  </metadata>
</package>
~                    

WebNuspec.csproj 文件内容

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <NoBuild>true</NoBuild>
    <IncludeBuildOutput>false</IncludeBuildOutput>
    <NuspecFile>PATH_TO_NUSPEC_FILE</NuspecFile>
  </PropertyGroup>
</Project>               

HD_System.Web.targets 文件内容

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <!-- 如果是dll 复制到发布文件 -->
        <None Include="$(MSBuildThisFileDirectory)\*.dll">
            <Link>%(Filename)%(Extension)</Link>
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
    </ItemGroup>
     <!-- 这里执行的是wwwroot的复制 -->
    <Target Name="CopyScriptsToProject" BeforeTargets="PrepareForBuild">
        <ItemGroup>
          <SourceScriptFiles Include="$(MSBuildThisFileDirectory)\wwwroot\**\*.*" />
        </ItemGroup>
        <Copy SourceFiles="@(SourceScriptFiles)" DestinationFiles="$(ProjectDir)\wwwroot\%(RecursiveDir)%(Filename)%(Extension)"/>
  </Target>
</Project>
               

打包和复制目录命令

dotnet publish HD_System.Web.csproj -r linux-x64 -p:PublishDir=bin/publish

#复制目录
cp -r 略/wwwroot/* 略/WebNuspec/contentFiles/any/any/wwwroot
#复制文件
cp 略/bin/publish/HD_System.Web.dll 略/WebNuspec/build/HD_System.Web.dll

发布时 cd 到这个目录下,还是执行 dotnet pack

cd /home/HD_System/HD_System/WebNuspec

#执行空项目的打包 但是配置文件读取 HD_System.Web.nuspec
dotnet pack WebNuspec.csproj -p:NuspecFile=HD_System.Web.nuspec --output $PackagePath

问题又来了,使用-p:NuspecFile命令后 版本放不上,读取的是 HD_System.Web.nuspec 文件中的版本号,所以要读取原始项目的版本号将 HD_System.Web.nuspec 文件中的版本号替换,说白就是读取xml,在改变一个xml项,代码如下

#得到版本号
cd /home/HD_System/HD_System/HD.System.Web/
TARGET_XML_FLIE=HD_System.Web.csproj #原项目文件 读取Version字段
Version=`grep -E -o -e '<Version>.+</Version>' $TARGET_XML_FLIE | sed 's/<Version>//g'|sed 's/<\/Version>//g'`
echo $Version

#修改版本号
cd /home/HD_System/HD_System/WebNuspec
function change(){
    if [ $# -eq 3 ]; then
        sed -i 's/<'"$1"\>'.*</<'"$1"'\>'"$2"'</g' $3
    else
        echo error
    fi
}
change version $Version HD_System.Web.nuspec

3.3 动态组件引用(COM组件)

Nuget打包,可以把同样是Nuget安装的文件一块都打包了,实例项目不用引用直接就能还原上,但是对于dll文件的打包,比如FineUICore.dll,在框架项目中引用,在实例项目中我希望自动引用;

在 HD.UIControl.csproj 中加入这句就可以了 (该功能由BingAI提供)

<!--包含在项目中-->
<ItemGroup>
	<Reference Include="FineUICore">
		<HintPath>bin\FineUICore.dll</HintPath>
	</Reference>
</ItemGroup>
<!--输出到打包目录-->
<ItemGroup>
	<None Include="bin\FineUICore.dll" Pack="true" PackagePath="lib\net7.0" />
	<None Include="bin\FineUICore.xml" Pack="true" PackagePath="lib\net7.0" />
</ItemGroup>

其他

本地nuget缓存,
删除缓存版本 C:\Users\shiyu.nuget\packages

libstdc++ 找不到

yum install glibc-static libstdc++-static -y

Nuget一键打包上传以及高级应用

如何为引用的 nuget 包指定输出文件夹?

MSBuild Copy 任务参考


至此所有问题解决,实现了源码和静态文件的包管理,

  • 框架项目修改,更新版本号,提交到Git;
  • 服务器拉-编译-发布\打包-发布到Nuget私服;
  • 实例项目引用\更新包,自动引用 FineUICore.dll,编译时复制 HD_System.Web.dll 到输出目录,复制框架下 wwwroot 文件到项目