Released: Soon... v1.9.0-rc3 is now available on NuGet.
This document provides an overview of the new features and enhancements in Excel-DNA version 1.9.0. This release significantly refactors and extends function registration, including simplified support for optional / default parameters and asynchronous functions, and introduces built-in support for object handles.
Support and SponsorsPublic support for Excel-DNA is provided via the Excel-DNA Google group. If you run into any questions or issues with the update, or have suggestions about future improvement, please feel free to start a discussion.
I also offer more formal corporate maintenance and support agreements for those using the library in a mission-critical setting - please contact me directly for more details.
The easiest way to encourage ongoing development and support of Excel-DNA is to sign up as a GitHub Sponsor. Higher tiers also provide online support sessions, where I am happy to advise or help you get unstuck with your add-in development. Thank you very much to all the existing sponsors!
ThanksThank you very much to Sergey Vlasov for doing an awesome job in producing this update. Please have a look at his great set of Visual Studio extensions here: https://vlasovstudio.com/
Thank you also to the other contributors who submitted changes for this version, or reported bugs or problems along the way.
And to all the Excel-DNA add-in creators around the world - I hope you continue to find the library useful.
Release HighlightsExcel-DNA's extended registration mechanism allows add-ins to define user-defined functions (UDFs) with signatures beyond basic Excel primitives (e.g. to allow optional parameters, params arrays, asynchronous methods), add custom function wrappers (for logging, caching, etc.), and register functions created at runtime.
Changes from Earlier Versions: Integration of ExcelDna.RegistrationIn v1.9, the functionality previously exposed in the separate ExcelDna.Registration library and package has been incorporated directly into the main ExcelDna.Integration library. This integration streamlines development for add-ins requiring extended registration features. While older versions required explicit steps and inclusion of the ExcelDna.Registration package to use these features, v1.9 offers these capabilities out-of-the-box or through more accessible APIs within the core library.
Key changes include:
For compatibility with previous Excel-DNA versions, all public static functions with parameters and return types only having 'primitive' types are registered as Excel UDFs, even if not marked with an [ExcelFunction] attribute. The primitive types are: double, string, DateTime, double[], double[,], bool, int, short, ushort, decimal, long, void, object, object[], object[,]. If an add-in project is marked as <ExcelAddInExplicitExports>true</<ExcelAddInExplicitExports> then registration is only done for those functions marked with [ExcelFunction], preventing other public static functions from being registered by mistake.
Extended Default Registration with [ExcelFunction]From this version, the standard [ExcelFunction] attribute implicitly supports a wider array of method signatures without requiring additional custom registration configurations:
Optional and Default Parameters: Handles C# optional parameters with default values and VB.NET Optional parameters, including for DateTime and nullable types.
params Arrays: Supports functions using params arrays in C# or ParamArray in VB.NET to accept a variable number of arguments.
Functions that have return types Task<T> or IObservable<T> will automatically be registered as an RTD-based async or streaming function. If an async function has a final parameter of type CancellationToken, the token will be signaled if the formula is deleted while the async call is outstanding.
Directly Usable Helper MethodsIn order to customize the async or streaming functions beyond the default wrappers, several utility classes and methods for asynchronous operations and object handling are directly accessible. These allow easy async and streaming function implementations by writing an explicit wrapper.
Async Utilities:
ExcelAsyncUtil.RunTask: Helper for running Task-based operations and integrating them with Excel's async model.
ExcelDna.Integration.AsyncTaskUtil: Utility class for managing Task-based functions.
ExcelDna.Integration.NativeAsyncTaskUtil: For deeper integration with native async capabilities.
ObservableRtdUtil Utility Introduced ObservableRtdUtil for improved handling of real-time data updates using observables. This utility simplifies the integration of IObservable<T> sources with Excel's RTD mechanism.
ExcelAsyncUtil.Observe: Has a new overload that accepts ExcelObservableOptions for more control over observable UDFs.
Explicit registration by retrieving and processing the ExcelFunction list was previously done by extensions in the ExcelDna.Registration library. The relevant types from that library are now included in the ExcelDna.Integration assembly, but the namespaces and type names are not changed. Thus code previously doing explicit registration should still work after the update. (The ExcelDna.Registration NuGet package just becomes obsolete.)
We also provide a simpler approach for including registration extensions in an add-in.
Function Execution Handlers: For common cross-cutting concerns like caching and timing, it can be convenient to add aspect-oriented style function handlers that get woven around the registered functions. We support various ways of registering such handlers:
Language Specific Support
When the Excel-DNA Registration extensions were separate libraries, there were some language-specific extensions for VB.NET and F#.
F#:
For F#, the support for asynchronous workflows (async {}) should now be incorporated in the add-in project by using the FsAsyncUtil helper
Registration Samples
Various examples of extended registration with parameter conversion and function handlers can be found in the Excel-DNA samples Repository.
Two MSBuild project properties in your .csproj file influence how Excel-DNA discovers and registers your functions and commands:
ExcelAddInExplicitExports:
ExcelAddInExplicitRegistration:
The [ExcelHandle] attribute provides a robust mechanism for managing .NET object references passed between your add-in and Excel. This allows complex objects to live in the .NET runtime while Excel manipulates them via handles (e.g., #MyObject!123).
Usage: Apply [ExcelHandle] to:
Requirement for Task<T>/IObservable<T>: Directly supports methods returning Task<T> (for asynchronous UDFs) or IObservable<T> (for streaming UDFs).
Assembly-Level ExcelHandleExternal Attribute: For types defined in other assemblies that you want Excel-DNA to treat as handles, you can use the [assembly: ExcelHandleExternal(typeof(YourExternalType))] attribute.
ObjectHandler Helper Class:
The RTD server's tracking methods have been made virtual, allowing developers to override them in derived classes for custom tracking of notifications and refresh calls. The affected methods are:
The sample project RtdClock-Watchdog (in the Excel-DNA\Samples repository) shows how these methods can be used to add a watchdog to an RTD server that monitors whether the RTD data is being fetched timeously.
Other Changes and EnhancementsSupport for newer .NET VersionsWe now support specifying an exact runtime version (for .NET 5+) by honoring the RuntimeFrameworkVersion project property.
You'll see the version and RollForward option reflected in the generated .runtimeconfig.json file
This is implemented by adding an attribute in the generated .dna file (generated by the build when you don't have a .dna file in your project directory)
Then when loading the add-in, if the matching runtime version cannot be loaded, you should see a clear error message.
You can also use other RollForward options like "LatestPatch" as expected.
-Govert (gov...@dnakode.com)
Hi Govert ,I hope you're all doing well.
I read the sample of AsyncReturnHandler on github and I found there's no tranditional codes like this:
static ParameterConversionConfiguration GetPostAsyncReturnConversionConfig()
{
// This conversion replaces the default #N/A return value of async functions with the #GETTING_DATA value.
var rval = ExcelError.ExcelErrorGettingData;
return new ParameterConversionConfiguration()
.AddReturnConversion((type, customAttributes) => type != typeof(object) ? null : (Expression<Func<object, object>>)
((returnValue) => returnValue.Equals(ExcelError.ExcelErrorNA) ? rval : returnValue));
}
public void AutoOpen()
{
var postAsyncReturnConfig = GetPostAsyncReturnConversionConfig();
ExcelRegistration.GetExcelFunctions()
.ProcessAsyncRegistrations(nativeAsyncIfAvailable: false)
.ProcessParameterConversions(postAsyncReturnConfig)
.ProcessParamsRegistrations()
.RegisterFunctions();
}
However,without these codes,the default return information during calculation will be "#N/A" ,is there any mistake I made?