求助:如何将NuGet Package中的原生文件添加至.NET 8应用输出目录以支持P/Invoke调用
我现在碰到个头疼的问题:想把NuGet包中的原生DLL和.NET 8.0的C#程序集一起部署,这样就能用P/Invoke调用原生DLL里的API了。但目前卡在两点:一是得确定原生DLL相对于使用该包的C#应用的位置,二是要保证它的依赖文件也能被正确找到。
我试过官方文档里提到的runtimes目录结构,把原生文件放到NuGet包的runtimes\net8.0\native目录下,也能看到这些文件在obj\project.assets.json的runtimeTargets节点里被列出来了,但当我编译解决方案的时候,这些文件根本没被复制到输出目录里——结果就是找不到API DLL,连它的依赖也没法加载。
后来我参考了一个Stack Overflow的回答,尝试配置让原生文件复制到C#控制台应用的输出目录,但还没搞定。有没有大佬能指点下正确的配置方式啊?
可行的解决方案
针对.NET 8的NuGet原生文件部署,这里有几个经过验证的方法:
按平台区分runtimes目录
不要把文件放到通用的runtimes\net8.0\native,而是要根据目标平台拆分目录,比如:- Windows x64平台:
runtimes\win-x64\native - Linux x64平台:
runtimes\linux-x64\native - macOS x64平台:
runtimes\osx-x64\native
这样.NET会根据项目的目标运行时,自动把对应平台的原生文件复制到输出目录的runtimes\<platform>\native路径下。之后你可以用System.Runtime.InteropServices.NativeLibrary.Load指定路径加载,或者直接在DllImport中设置正确的文件名,让运行时自动探测。
- Windows x64平台:
用NuGet的.targets文件强制复制
如果你的原生文件是平台无关的,或者需要直接复制到输出根目录,可以在NuGet包的build目录下创建一个和包名同名的.targets文件(比如你的包叫MyNativeLib,就创建MyNativeLib.targets),内容如下:<Project> <ItemGroup> <NativeFile Include="$(MSBuildThisFileDirectory)..\native\**\*"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <Link>%(RecursiveDir)%(Filename)%(Extension)</Link> </NativeFile> </ItemGroup> </Project>同时把所有原生文件放到NuGet包的
native目录下。这样当项目引用该包时,MSBuild会自动执行这个.targets文件,把原生文件复制到输出目录。在项目中手动配置复制规则
如果不想修改NuGet包,也可以在引用该包的C#项目的.csproj文件里添加以下配置:<ItemGroup> <Content Include="$(NuGetPackageRoot)\你的包名\对应版本号\runtimes\net8.0\native\**\*"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup>记得把
你的包名和对应版本号替换成实际的包信息,这样编译时就会把指定路径的原生文件复制到输出目录。
备注:内容来源于stack exchange,提问作者Rob Stewart

