[英]Publishing a standalone exe file with .Net Core 3.0 and using an app.config
I have a.Net Core 3.0 project and wanted to take advantage of the new option to publish the project as a single.exe file.我有一个 .Net Core 3.0 项目,并希望利用新选项将项目发布为单个 .exe 文件。
I use the command我使用命令dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true
This, sure enough, produces a single.exe file but the problem is I have an app.config file in my project that the users should modify and I am not sure if it gets packaged in the.exe, as well.果然,这会产生一个单一的.exe文件,但问题是我的项目中有一个app.config文件,用户应该修改它,我不确定它是否也被打包在.exe中。 When I tested the produced.exe it reads the values I have initially put in the app.config.当我测试produced.exe 时,它会读取我最初放入app.config 的值。
I have tried setting the "Copy to Output Directory" option to "Copy always" but that didn't change anything.我尝试将“复制到 Output 目录”选项设置为“始终复制”,但这并没有改变任何内容。 The "Build action" is set to "None". “构建操作”设置为“无”。
How can I set it so that everything EXCEPT the app.config is packaged inside that.exe file, so that the user can change values?如何设置它,以便除 app.config 之外的所有内容都打包在 that.exe 文件中,以便用户可以更改值?
Short version精简版
.NET Core doesn't use app.config
, you'll have to upgrade to the new config system or manually manage the files. .NET Core 不使用app.config
,您必须升级到新的配置系统或手动管理文件。
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
to the App1.config
file to keep it out of the bundle.将<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
添加到App1.config
文件以将其排除在包之外。MyApp.exe.config
file with the production settings and add <CopyToPublishDirectory>Always</CopyToPublishDirectory>
to have it published to the Publish
directory.手动添加带有生产设置的MyApp.exe.config
文件并添加<CopyToPublishDirectory>Always</CopyToPublishDirectory>
以将其发布到Publish
目录。 Transformations won't run, so make sure it contains everything that's needed.转换不会运行,因此请确保它包含所需的一切。var hostFile=Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
ConfigurationManager.OpenExeConfiguration(hostFile+".config");
To load the published file, as if it were any other file加载已发布的文件,就像它是任何其他文件一样
.NET Core 3, even for Windows Forms, doesn't use app.config
. .NET Core 3,即使对于 Windows Forms,也不使用app.config
。 .NET Core's configuration system is described in Configuration in ASP.NET Core and despite the name, applies to every .NET Core application. .NET 内核的配置系统在ASP.NET 内核的配置中进行了描述,尽管名称如此,但它适用于每个 .NET 内核应用程序。 It's far more powerful too, loading configuration from multiple sources, including files (even INI), databases, Azure or AWS setting stores etc.它也更强大,从多个来源加载配置,包括文件(甚至 INI)、数据库、Azure 或 AWS 设置存储等。
Adding an Application Configuration File
to a new Windows Forms project, both in VS 2019 and the command line creates an App1.config
file with no special meaning as far as VS or .NET Core are concerned.将Application Configuration File
添加到新的 Windows Forms 项目中,无论是在 VS 2019 中还是在命令行中,都会创建一个App1.config
文件,就 VS 或 Z303CB0EF9EDB90872D61BBBE5825D9 而言没有特殊意义。 Creating an AppName.exe.config
requires actually creating a new AppName.exe.config
file with the production settings.创建AppName.exe.config
实际上需要使用生产设置创建一个新的AppName.exe.config
文件。
The only way to read an Old-style .config
file is to explicitly load it with ConfigurationManager.OpenExeConfiguration .读取旧式.config
文件的唯一方法是使用ConfigurationManager.OpenExeConfiguration显式加载它。 This simply loads the file and parses it.这只是加载文件并解析它。 One could pass any file path, or specify a ConfigurationUserLevel which simply resolves to a file location based on the executable's base directory.可以传递任何文件路径,或者指定一个 ConfigurationUserLevel,它只是根据可执行文件的基目录解析到文件位置。
And here's where the trouble starts.这就是麻烦开始的地方。 There's a bug.有一个错误。
With Single-file executables, all files are bundled in a single host file with the .exe
extension.使用单文件可执行文件,所有文件都捆绑在一个扩展名为.exe
的主机文件中。 When that file runs for the first time, it unpacks its contents to AppData\Local\Temp\.net\
, in a new folder named for the application.当该文件第一次运行时,它会将其内容解压缩到AppData\Local\Temp\.net\
中,位于为应用程序命名的新文件夹中。 By design , the application's base directory should be the host's path, where the single.exe is. 按照设计,应用程序的基目录应该是主机的路径,即 single.exe 所在的位置。 Unfortunately, there's a bug and the base directory remains the location of the bundle and the .dll
that's actually run by the host.不幸的是,有一个错误,基本目录仍然是包的位置和主机实际运行的.dll
。
That's why这就是为什么
System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None).FilePath
returns C:\Users\myUser~1\AppData\Local\Temp\.net\ConsoleApp_NetCore\nk5sdmz5.ym1\ConsoleApp_NetCore.dll.config
and I'd bet AppContext.BaseDirectory
returns C:\Users\myUser~1\AppData\Local\Temp\.net\ConsoleApp_NetCore\nk5sdmz5.ym1\
returns C:\Users\myUser~1\AppData\Local\Temp\.net\ConsoleApp_NetCore\nk5sdmz5.ym1\ConsoleApp_NetCore.dll.config
and I'd bet AppContext.BaseDirectory
returns C:\Users\myUser~1\AppData\Local\Temp\.net\ConsoleApp_NetCore\nk5sdmz5.ym1\
The workaround for this is to retrieve the host's path and load the settings file explicitly.解决方法是检索主机的路径并显式加载设置文件。 This means we can now use any file name.这意味着我们现在可以使用任何文件名。 If we keep the old convention of naming the file appname.exe.config
, we can just append .config
to the host's full path:如果我们保持命名文件appname.exe.config
的旧约定,我们可以只 append .config
到主机的完整路径:
var hostFile=Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
ConfigurationManager.OpenExeConfiguration(hostFile+".config");
This has to be done with the .NET Core File provider too.这也必须通过 .NET 核心文件提供程序来完成。
You should mark the file as <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
in the project settings.您应该在项目设置中将该文件标记为<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
。
https://github.com/dotnet/core-setup/issues/7738 https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md#build-system-interface https://github.com/dotnet/core-setup/issues/7738 https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md#build-system-interface
This works for me for a standalone exe.这对我来说适用于独立的 exe。 In my.csproj file I added this which created the myProgramName.dll.config upon build.在 my.csproj 文件中,我添加了这个,它在构建时创建了 myProgramName.dll.config。
<ItemGroup>
<None Update="App.config">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</None>
</ItemGroup>
And in my C# console app code (dot net core 3.1.0) I added this.在我的 C# 控制台应用程序代码(dot net core 3.1.0)中,我添加了这个。
// requires using System.Configuration;
string programName = "myProgramName";
var sourceHostFile = Directory.GetCurrentDirectory() + @"\" + programName + @".dll.config";
Console.WriteLine("sourceHostFile is: " + sourceHostFile);
// to load yourProgram.dll.config
// With Single-file executables, all files are bundled in a single host file with the .exe extension.
// When that file runs for the first time, it unpacks its contents to AppData\Local\Temp\.net\, in a new folder named for the application
var targetHostFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
// ignore when in debug mode in vs ide
if (sourceHostFile != targetHostFile)
{
File.Copy(sourceHostFile, targetHostFile, true);
}
Console.WriteLine("targetHostFile is: " + targetHostFile);
string password = ConfigurationManager.AppSettings["password"];
Console.WriteLine("password from config is: " + password);
// end of poc
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.