如何让NuGet包中的Excel-DNA函数在用户Excel会话中自动可见?
看起来你已经走对了方向——用Excel-DNA Registration来自动注册函数,但发布到NuGet后用户看不到,大概率是你的包没有确保用户的Excel加载项正确加载并执行你的注册逻辑。下面是几个你可能遗漏的关键点:
1. 确保你的NuGet包自动向用户项目传递DNA配置
你的包的.dna文件设置了ExplicitRegistration="true",但如果用户的项目没有把你的程序集包含到他们自己的加载项DNA中,你的IExcelAddIn实现永远不会被执行。
解决方法:
在你的NuGet包中添加一个MSBuild构建目标文件(比如MyNugetPackage.targets),自动把你的程序集引用注入到用户的.dna文件里。示例目标文件内容:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Target Name="InjectMyNugetPackageToUserDna" AfterTargets="Build"> <!-- 检查用户的DNA文件是否已包含我们的程序集,没有则添加 --> <XmlPoke Condition="!Exists('$(ProjectDir)*.dna')" XmlInputPath="$(ProjectDir)UserAddIn.dna" Query="/DnaLibrary" Value="$(XmlPokeValue)<ExternalLibrary Path='MyNugetPackageNS.dll' ExplicitRegistration='true' LoadFromBytes='true' />" /> </Target> </Project>
把这个.targets文件放在NuGet包的build目录下,这样用户安装包时,MSBuild会自动执行这个逻辑,无需用户手动修改DNA配置。
2. 确认你的Excel函数是公开可访问的
在F#中,模块里的顶级let绑定默认是internal(仅限当前程序集访问),而Excel-DNA Registration默认只扫描public成员。即使注册代码能通过反射找到internal函数,用户的Excel加载项也可能无法正确识别它们。
解决方法:
给你的函数或模块添加[<Public>]属性,显式标记为公开:
namespace MyNugetPackageNS open ExcelDna.Integration open ExcelDna.Registration type MakeAddInsVisible () = interface IExcelAddIn with member this.AutoOpen () = // 若想兼容internal函数,可添加includeInternal=true参数 ExcelRegistration.GetExcelFunctions(includeInternal=true) |> ExcelRegistration.RegisterFunctions member this.AutoClose () = () [<Public>] // 标记模块为公开,让所有内部函数可被外部访问 module MyNugetModule = open ExcelDna.Integration [<ExcelFunction(Category="Test", Description="Add 1.")>] let plusOne ([<ExcelArgument(Description= "Value.")>] value: double) : obj = value + 1.0 |> box
3. 确保Excel-DNA Registration依赖被正确传递
你的NuGet包必须正确依赖ExcelDna.Registration包,并且设置为自动安装。如果用户安装你的包时没有同时获取到Registration包,你的注册代码会抛出异常,导致函数无法注册。
解决方法:
在你的NuGet包的.nuspec文件中添加依赖声明:
<dependencies> <group targetFramework=".NETFramework4.8"> <dependency id="ExcelDna.Integration" version="1.7.0" /> <dependency id="ExcelDna.Registration" version="1.7.0" /> </group> </dependencies>
或者在Visual Studio的NuGet包管理器中,把这两个包设置为“依赖项”,确保用户安装你的包时自动获取它们。
4. 检查用户的加载项是否正确复制你的程序集
即使你的包配置正确,用户的项目可能没有把你的程序集复制到输出目录。可以让用户检查:
- 在项目引用中,你的NuGet包的“复制本地”属性是否为
True - 输出目录中是否存在
MyNugetPackageNS.dll和ExcelDna.Registration.dll
5. 明确指定Registration的扫描范围
默认情况下,ExcelRegistration.GetExcelFunctions()只会扫描当前程序集的public函数。如果你的函数分布在多个程序集或者是internal,需要明确指定扫描范围:
member this.AutoOpen () = // 扫描当前程序集的所有函数(包括internal) let currentAssembly = System.Reflection.Assembly.GetExecutingAssembly() let functions = ExcelRegistration.GetExcelFunctions(currentAssembly, includeInternal=true) ExcelRegistration.RegisterFunctions(functions)
总结
最可能的原因是用户的加载项没有包含你的程序集到DNA配置中,或者你的函数不是公开的。先检查这两点,再逐步排查依赖和扫描范围的问题。当用户的加载项正确加载你的程序集后,你的MakeAddInsVisible类的AutoOpen方法会自动执行,注册所有标记了[<ExcelFunction>]的函数,无需用户手动包装。
内容的提问来源于stack exchange,提问作者Janthelme

