2021-10-26 13:11:27.200 +02:00 [ERR] OPC-UA Server - Failed. Exception: System.ArgumentException: The path is empty. (Parameter 'path')
at System.IO.Path.GetFullPath(String path)
at System.IO.FileInfo..ctor(String originalPath, String fullPath, String fileName, Boolean isNormalized)
at UnifiedAutomation.UaServer.ServerSettings..ctor(ApplicationInstanceBase application)
at UnifiedAutomation.UaServer.ServerManager.OnServerStarting(ApplicationInstanceBase application)
at UnifiedAutomation.UaBase.ServerBase.Start(ApplicationInstanceBase application)
at UnifiedAutomation.UaServer.ServerManager.Start(ApplicationInstanceBase application)
at UnifiedAutomation.UaBase.ApplicationInstanceBase.Start(ServerBase server, WaitCallback callback, Object userData, Boolean silent)
The exactly same code published as a normal debug/release works without any issues.
Microsoft has broken some API from Core 3.x to .NET 5. For that reason you can not use self-contained feature in .NET 5 in a similar way you are used to by Core3.x anymore. The API incompatibility within the different .NET Frameworks effects the location and path functions that are typically used to obtain DLL locations.
However, there is a switch (IncludeAllContentForSelfExtract) you can use to retain the behavior of the .NET Core 3.x. With that the "extraction before execution" is enabled again and includes the managed assemblies as well as the native ones.
Note: for security reasons you should limit access rights on the base folder used for extraction, on Linux this typically is done implicitely when extracting to "$HOME/.net", on Windows you should take similar precautions.
Microsoft has broken some API from Core 3.x to .NET 5. For that reason you can not use self-contained feature in .NET 5 in a similar way you are used to by Core3.x anymore. The API incompatibility within the different .NET Frameworks effects the location and path functions that are typically used to obtain DLL locations.
However, there is a switch (IncludeAllContentForSelfExtract) you can use to retain the behavior of the .NET Core 3.x. With that the "extraction before execution" is enabled again and includes the managed assemblies as well as the native ones.
Note: for security reasons you should limit access rights on the base folder used for extraction, on Linux this typically is done implicitely when extracting to "$HOME/.net", on Windows you should take similar precautions.
What about .NET 6? Have you tested this behavior with the current 6.0.100-rc.2?
The issue lies in the constructor of ServerSettings. Microsoft also has in it's documents, that for single file applications, the entry assembly will have an empty string. So it's a missing in the library from my sight. But there is an easy fix that the library could do, taking that into account (also ensuring that it's not crashing on empty strings anymore).
if (serverSettings.BuildDate == DateTime.MinValue)
{
Assembly entryAssembly = PlatformUtils.GetEntryAssembly();
if (entryAssembly != (Assembly)null)
{
var assemblyLocation = entryAssembly.Location;
if (string.IsNullOrEmpty(assemblyLocation))
{
assemblyLocation = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName;
}
if (!string.IsNullOrEmpty(assemblyLocation))
{
FileInfo fileInfo = new FileInfo(entryAssembly.Location);
if (fileInfo.Exists) {
this.BuildDate = fileInfo.LastWriteTimeUtc;
}
}
}
}
This bug can be worked around by setting the BuildDate manually (i.e. using this fix in your own code) to avoid the ctor going into the DateTime.MinValue routine.
The issue lies in the constructor of ServerSettings. Microsoft also has in it's documents, that for single file applications, the entry assembly will have an empty string. So it's a missing in the library from my sight. But there is an easy fix that the library could do, taking that into account (also ensuring that it's not crashing on empty strings anymore).
if (serverSettings.BuildDate == DateTime.MinValue)
{
Assembly entryAssembly = PlatformUtils.GetEntryAssembly();
if (entryAssembly != (Assembly)null)
{
var assemblyLocation = entryAssembly.Location;
if (string.IsNullOrEmpty(assemblyLocation))
{
assemblyLocation = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName;
}
if (!string.IsNullOrEmpty(assemblyLocation))
{
FileInfo fileInfo = new FileInfo(entryAssembly.Location);
if (fileInfo.Exists) {
this.BuildDate = fileInfo.LastWriteTimeUtc;
}
}
}
}
This bug can be worked around by setting the BuildDate manually (i.e. using this fix in your own code) to avoid the ctor going into the DateTime.MinValue routine.
Thanks @bkraemer-jh I've applied your suggestion and now my Server is running completely fine when published as a Self Contained or Single File .NET 5 app.