Costura: Confluent.Kafka doesn't get the correct Costura temp path
Please check all of the platforms you are having the issue on (if platform is not listed, it is not supported)
- WPF
- UWP
- iOS
- Android
- .NET Standard
- .NET Core
Component
Costura.Fody
Version of Library
5.3.0
Version of OS(s) listed above with issue
Windows 10
Steps to Reproduce
- Create any app with .NET 4.7;
- Add
Confluent.Kafka; - Add
Costura.Fody; - Edit the
FodyWeavears.xmlto:
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura>
<Unmanaged32Assemblies>
librdkafka
librdkafkacpp
libzstd
msvcp120
msvcr120
zlib
</Unmanaged32Assemblies>
<Unmanaged64Assemblies>
librdkafka
librdkafkacpp
libzstd
msvcp120
msvcr120
zlib
</Unmanaged64Assemblies>
</Costura>
</Weavers>
- Add any library you want, to prove that
Costuraworks; - Call any method of
Confluent.Kafka; - Run, and get you error:
Unhandled Exception: System.InvalidOperationException: Error while loading librdkafka.dll or its dependencies from *current.dir*\librdkafka.dll. Check the directory exists, if not check your deployment process. You can also load the library and its dependencies by yourself before any call to Confluent.Kafka ---> System.ComponentModel.Win32Exception: The specified module could not be found
--- End of inner exception stack trace ---
at Confluent.Kafka.Impl.Librdkafka.LoadNetFrameworkDelegates(String userSpecifiedPath)
at Confluent.Kafka.Impl.Librdkafka.Initialize(String userSpecifiedPath)
at Confluent.Kafka.Producer`2..ctor(ProducerBuilder`2 builder)
at Confluent.Kafka.ProducerBuilder`2.Build()
at ActiveDirectory.Infrastructure.Helpers.QueueHelper.<SendMessage>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
Expected Behavior
I would like that Confluent.Kafka to load correctly the library from the path that Costura changed.
Actual Behavior
Confluent.Kafka doesn’t know how to search in Costura.Fody temp path.
Important: I opened an issue inside Confluent.Kafka to there staff answer some this question too.
I would like to know where is the main problem. If you could, please, read it too: https://github.com/confluentinc/confluent-kafka-dotnet/issues/1660
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 48 (31 by maintainers)
Commits related to this issue
- Just a POC for https://github.com/Fody/Costura/issues/726 — committed to tom-englert/Costura by tom-englert 3 years ago
Stable version is being deployed right now. Please let us know if any other issues arise.
Special thanks to @tom-englert for fixing this!
… and to @0xced for the msbuild part!
I think that we can release this as stable. @tom-englert you agree that we can release this and the other PR you did?
msvc*.dll come with the “Microsoft Visual C++ ??? Redistributable” - so they might not be present always.
I once used this workaround to ensure these get not loaded by Costura if they are already present:
FodyWeavers.xml
Source code:
There are many things at play in this scenario. You can find a working solution for both 32-bit and 64-bit systems in my embed-native-dlls branch. All the native dlls are embedded in the single executable and automatically loaded at runtime by Costura but you still need to call
Confluent.Kafka.Library.Loadwith the path where the nativelibrdkafkadll was extracted.The missing pieces were:
PreloadOrderso that all native dlls are loaded successfullyEmbedLibrdkafkaRedistNativeLibraries) to prevent native dlls from being copied to the output directory and being embedded in virtualcostura32andcostura64directories instead.Confluent.Kafka.Library.Load, this required to configureCreateTemporaryAssemblies="true"so that we can know the directory where native dlls are extracted by Costura withtypeof(Confluent.Kafka.Library).Assembly.GetName().EscapedCodeBase~ (see Tom’s comment below)In addition, I have
<AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>and<GenerateSupportedRuntime>false</GenerateSupportedRuntime>to preventConsoleApp1.exe.configfrom being generated. (Binding redirects are not needed thanks to Costura)<DebugType>embedded</DebugType>to embed the pdb inside the exe instead of having it in a separate file<PlatformTarget>AnyCPU</PlatformTarget>so that the app runs in 64-bit by defaultWhen Costura has already loaded the libraries, no path is needed for
LoadLibrary, just specifying only the file name will simply return the handle of the loaded library.My guess is that the
PreLoadOrderis wrong, and Costura did not load all of the libraries sucessfully,@GeertvanHorrik in Costura
SetDllDirectory+LoadLibraryis used. UsingLoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH)might be the better solution, andPreLoadOrderwould not be required here. Any idea why it was done this way?can you also create a stand alone github repository that contains a minimal repro for this issue