- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
一般我们构建传统的NuGet包,都是打包和分发dll程序集文件.
至于打包和分发C#源代码文件的做法,比较少见.
那么这种打包源代码文件的做法,有什么优点和缺点呢?
优点:
缺点:
经验:
正文:
接下来,我们一起看看如何制作仅打包C#源代码文件,不打包dll程序集文件的C#源代码组件NuGet包.
首先是创建 AllenCai.BuildingBlocks 项目,目录结构如下:
.
├── build
└── src
├── AllenCai.BuildingBlocks
│ ├── AllenCai.BuildingBlocks.csproj
│ ├── Properties
│ │ ├── PackageInfo.cs
│ ├── Assets
│ │ ├── build
│ │ │ └── AllenCai.BuildingBlocks.targets
│ │ └── buildMultiTargeting
│ │ └── AllenCai.BuildingBlocks.targets
│ ├── Collections
│ │ ├── ArrayBuilder.cs
│ │ ├── other...
│ ├── Functional
│ │ ├── Result.cs
│ │ ├── other...
│ ├── ObjectPooling
│ │ ├── DictionaryPool.cs
│ │ ├── other...
│ ├── Text
│ │ ├── StringBuffer.cs
│ │ ├── other...
│ ├── Threading
│ │ ├── ValueTaskEx.cs
│ │ ├── other...
│ ├── bin
│ │ ├── Release
│ │ │ └── other...
│ │ ├── Debug
│ │ │ └── other...
│ └── obj
│ │ ├── other...
│ ├── icon.png
│ ├── other...
├── AllenCai.BuildingBlocks.sln
└── Directory.Build.targets
├── .gitattributes
├── .gitignore
├── README.md
其中 Directory.Build.targets 文件,用来生成描述源代码组件包版本信息的C#源代码文件,输出文件路径为:Properties\PackageInfo.cs.
之所以输出到 Properties 目录,是因为 PackageInfo.cs 的作用其实和以前 .NET Framework 时代每个项目都会包含的 AssemblyInfo.cs 相同.
那么,为什么需要生成这个 PackageInfo.cs 文件呢?
git commit sha-1
。Directory.Build.targets 文件代码如下所示:
<Project>
<!--
将代码版本信息输出到C#文件中,使用者在项目中引入本组件源码,能够看到版本信息。
且在使用者项目编译为程序集文件后,也能够保留本组件版本信息。
-->
<Target Name="GeneratePackageInfoToFile" BeforeTargets="PreBuildEvent" Condition="'$(Configuration)' == 'Release'">
<PropertyGroup>
<SharedPackageInfoFile>$(ProjectDir)Properties\PackageInfo.cs</SharedPackageInfoFile>
</PropertyGroup>
<ItemGroup>
<AssemblyAttributes Include="AssemblyMetadata">
<_Parameter1>PackageVersion</_Parameter1>
<_Parameter2>$(Version)</_Parameter2>
</AssemblyAttributes>
<AssemblyAttributes Include="AssemblyMetadata">
<_Parameter1>PackageBuildDate</_Parameter1>
<_Parameter2>$([System.DateTime]::Now.ToString("yyyy-MM-dd HH:mm:ss"))</_Parameter2>
</AssemblyAttributes>
<AssemblyAttributes Include="AssemblyMetadata" Condition="'$(SourceRevisionId)' != ''">
<_Parameter1>PackageSourceRevisionId</_Parameter1>
<_Parameter2>$(SourceRevisionId)</_Parameter2>
</AssemblyAttributes>
</ItemGroup>
<MakeDir Directories="$(ProjectDir)Properties"/>
<WriteCodeFragment Language="C#" OutputFile="$(SharedPackageInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
<Message Importance="high" Text="SharedPackageInfoFile --> $(SharedPackageInfoFile)" />
<ItemGroup>
<Compile Include="$(SharedPackageInfoFile)" Pack="true" BuildAction="Compile" />
</ItemGroup>
</Target>
</Project>
而 AllenCai.BuildingBlocks.targets 文件,将会被打包到NuGet包.
当这个包被添加引用到目标项目中,MsBuild 将会自动调用它,执行一系列由你定义的动作.
那么,又为什么需要这个 AllenCai.BuildingBlocks.targets 文件呢?
它其实是非必须的,根据项目实际情况而定,没有这个 targets 文件也是可以的.
但这样的话,可能引用这个源代码组件包的开发者会在刚引入时遇到一系列问题,导致这个源代码组件包对开发者不友好.
比如源代码文件中使用了不安全代码,而目标项目的<AllowUnsafeBlocks>属性值是 false,那么目标项目在编译时就会报错.
因此需要这个 targets 文件来检查和自动设置为 true.
如以下示例代码(build\AllenCai.BuildingBlocks.targets):
<Project>
<Target Name="UpdateLangVersionAndAllowUnsafeBlocks" BeforeTargets="BeforeCompile">
<PropertyGroup>
<OldAllowUnsafeBlocks>$(AllowUnsafeBlocks)</OldAllowUnsafeBlocks>
<AllowUnsafeBlocks Condition=" '$(AllowUnsafeBlocks)' == '' or $([System.String]::Equals('$(AllowUnsafeBlocks)','false','StringComparison.InvariantCultureIgnoreCase')) ">True</AllowUnsafeBlocks>
</PropertyGroup>
<!--当属性项被修改时,在Build控制台输出提示-->
<Message Importance="high" Condition=" '$(AllowUnsafeBlocks)' != '$(OldAllowUnsafeBlocks)' " Text="Update AllowUnsafeBlocks to $(AllowUnsafeBlocks)" />
</Target>
</Project>
以及 buildMultiTargeting\AllenCai.BuildingBlocks.targets 文件代码如下所示:
<Project>
<Import Project="..\build\AllenCai.BuildingBlocks.targets" />
</Project>
需要注意的是,这个 targets 文件需要与 ProjectName 或 PackageId 保持一致.
最后 AllenCai.BuildingBlocks.csproj 文件代码如下所示:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<LangVersion>default</LangVersion>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ImplicitUsings>disable</ImplicitUsings>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<Version>0.0.1</Version>
</PropertyGroup>
<!--一些与NuGet包相关的属性项-->
<PropertyGroup>
<Title>AllenCai BuildingBlocks</Title>
<Description>提供一组最常用的通用软件模块,以文件链接的方式被包含到引用项目中。</Description>
<Authors>Allen.Cai</Authors>
<Copyright>Copyright © Allen.Cai 2015-$([System.DateTime]::Now.Year) All Rights Reserved</Copyright>
<ContentTargetFolders>contentFiles\cs\any\AllenCai.BuildingBlocks;content\cs\any\AllenCai.BuildingBlocks</ContentTargetFolders>
<!--该属性项声明了仅在开发期间依赖,并且不传递其自身的依赖项,这将导致目标项目需要主动引入间接依赖项-->
<DevelopmentDependency>true</DevelopmentDependency>
<!--打包时不包含编译输出的文件-->
<IncludeBuildOutput>false</IncludeBuildOutput>
<!--该属性项仅用于源生成器(SourceGenerator)项目,从 Visual Studio 2022 v16.10及以上版本开始支持-->
<!--<IsRoslynComponent>true</IsRoslynComponent>-->
<!--跳过包分析-->
<NoPackageAnalysis>true</NoPackageAnalysis>
<PackageProjectUrl>http://192.168.1.88:5555/allen/allencai.buildingblocks/</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>http://192.168.1.88:5555/allen/allencai.buildingblocks.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>
<ItemGroup>
<!-- <PackageReference Include="System.Reactive" Version="5.0.0" /> -->
<None Include="icon.png" Pack="true" PackagePath="\" />
<None Include="..\..\README.md" Link="README.md" Pack="true" PackagePath="\" />
<Content Include="**\*.cs" Exclude="obj\**\*.cs" Pack="true" BuildAction="Compile" />
</ItemGroup>
</Project>
其中三个属性比较重要,DevelopmentDependency 和 IncludeBuildOutput 以及 ContentTargetFolders.
DevelopmentDependency
设置为 true
,表示这个 NuGet 包仅在开发期间依赖。IncludeBuildOutput
设置为 false
,表示打包时不包含编译输出的 dll 文件。ContentTargetFolders
,将会改变这些源代码文件在目标项目中的虚拟文件系统布局。如有不明白,欢迎留言,互相探讨.
截止本文,我刚搜到有 MVP大佬-吕毅 也写了类似教程,大家也可以参考:从零开始制作 NuGet 源代码包(全面支持 .NET Core / .NET Framework / WPF 项目) - walterlv 。
最后此篇关于如何使用csproj构建C#源代码组件NuGet包?的文章就讲到这里了,如果你想了解更多关于如何使用csproj构建C#源代码组件NuGet包?的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我错过了什么,我已完成 的安装指南中要求的所有步骤 native 脚本 运行 tns doctor 给我以下输出... C:\abc\xyz>tns doctor √ Getting environm
尝试从 {addToCart(book)}}/>}> 传递数据至}> 问题: 购物车 ( render={()=> ) 收到 null,但没有收到我尝试发送的对象 已放置“console.log...
这是 _app.tsx 的外观: function MyApp({ Component, pageProps }: AppProps) { return } 我在构建项目时遇到了这个错误: Ty
我的 Laravel Vue 组件收到以下警告: [Vue warn]: Avoid mutating a prop directly since the value will be overwrit
根据这个example更详细this one我刚刚遇到了一件奇怪的事情...... 如果我使用方法作为 addTab(title,icon,component) 并且下一步想使用 setTabComp
目前我有一个捕获登录数据的表单,一个带有 TIWDBGrid 的表单,它应该返回与我从我的 mysql 数据库登录时创建的 user_id 关联的任何主机,以及一个共享数据模块。 下面是我的登录页面代
在我的react-native应用程序中,我目前有一个本地Android View (用java编写)正确渲染。当我尝试将我的react-native javascript 组件之一放入其中时,出现以
我为作业编写了简单的代码。我引用了文档和几个 youtube 视频教程系列。我的 react 代码是正确的我在运行代码时没有收到任何错误。但是这些 react-boostrap 元素没有渲染。此代码仅
几周前我刚刚开始使用 Flow,从一周前开始我就遇到了 Flow 错误,我不知道如何修复。 代码如下: // @flow import React, { Component } from "react
我想在同一个 View 中加载不同的 web2py 组件,但不是同时加载。我有 5 个 .load 文件,它们具有用于不同场景的表单字段,这些文件由 onchange 选择脚本动态调用。 web2py
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 6年前关闭。 Improve t
Blazor 有 InputNumber将输入限制为数字的组件。然而,这呈现了一个 firefox 不尊重(它允许任何文本)。 所以我尝试创建一个过滤输入的自定义组件: @inherits Inpu
我在学习 AngularDART 组件时编写了以下简单代码,但没有显示任何内容,任何人都可以帮助我知道我犯了什么错误: 我的 html 主文件:
我想在初始安装组件时或之后为 div 设置动画(淡入)。动画完成后,div 不应消失。我正在尝试使用 CSSTransition 组件并查看 reactcommunity.org 上的示例,但我根本无
我需要一个 JSF 组件来表示甘特图。是否有任何组件库(如 RichFaces)包含这样的组件? 最佳答案 JFreeChart有甘特图和PrimeFaces有一个图像组件,允许您动态地流式传输内容。
从软件工程的角度来看,组件、模块和子系统之间有什么区别? 提前致谢! 最佳答案 以下是 UML 2.5 的一些发现: 组件:该子句指定一组结构,可用于定义任意大小和复杂性的软件系统。特别是,它将组件指
我有使用非托管程序集(名为 unmanaged.dll)的托管应用程序(名为 managed.exe)。到目前为止,我们已经创建了 Interop.unmanaged.dll,managed.exe
我有一个跨多个应用程序复制的 DAL(我知道它的设计很糟糕,但现在忽略它),我想做的是这个...... 创建一个将通过所有桌面应用程序访问的 WCF DAL 组件。任何人都可以分享他们对关注的想法吗?
我有一个 ComboBox 的集合声明如下。 val cmbAll = for (i /** action here **/ } 所有这些都放在一个 TabbedPane 中。我想这不是问题。那么我
使用 VB6 创建一个 VB 应用程序。应用程序的一部分显示内部的闪存。 当我使用 printform它只是打印整个应用程序。我不知道如何单独打印闪光部分。任何帮助,将不胜感激!.. 谢谢。 最佳答案
我是一名优秀的程序员,十分优秀!