FCell allows users to extend built-in functionality and implement a custom mechanism for customization and referenced assemblies delivery.

This is an alternative to embedding customization and referenced assemblies directly in workbooks and XLL files or referencing them via FCell UI.

The extensions use MEF as the underlying technology. Users only need to implement a simple interface as shown below.

Create a custom MEF component for FCell assembly feed

The component is simply an assembly with 1 or more classes which implement IExcelAssemblyFeed or IWorkbookAssemblyFeed (defined in FCell.ManagedXll). These interfaces have only 2 methods:

  • IExcelAssemblyFeed.GetCustomizationTypes() which should return IEnumerable<Type> where each type defines UDFs or a Ribbon

  • IExcelAssemblyFeed.GetReferencedAssembliesBytes() which should return IEnumerable<byte[]> where each byte array represents an assembly referenced by a customization assembly

  • IWorkbookAssemblyFeed.GetCustomizationTypes(workbook : Workbook) which takes as input the workbook which is customized and should return IEnumerable<Type> where each type defines UDFs or a Ribbon

  • IWorkbookAssemblyFeed.GetReferencedAssembliesBytes(workbook : Workbook) which takes as input the workbook which is customized and should return IEnumerable<byte[]> where each byte array represents an assembly referenced by a customization assembly

Note

You can define more than 1 extension assembly with any number of classes implementing IExcelAssemblyFeed or IWorkbookAssemblyFeed. These can also coexist with embedded customization and referenced assemblies.

Note

Referenced assemblies loaded into FCell via AssemblyFeed extension are loaded from bytes via Assembly.Load(asmBytes : byte[]). Each assembly is loaded only once into the domain.

You can preload your assembly from path in AssemblyFeed implementation with FCell AssemblyLoader.loadAssemblyFromPath(path : string). The assembly loader will make sure the assembly is loaded only once into the domain.

The code example below shows a simple implementation:

F# Copy imageCopy
open System
open FCell.ManagedXll
open System.IO
open System.ComponentModel.Composition
open System.Reflection
open NuGet // Nuget.Core
open System.Net
open System.Reflection

//required MEF attribute to export component
[<Export(typeof<IExcelAssemblyFeed>)>]
type ExcelAssemblyFeed() =
    interface IExcelAssemblyFeed with

        //will return extension assembly types as customization types, so you can define UDFs and Ribbons in the same assembly
        //In more complex scenario you could load many assemblies from files or remote web service and then expose their types
        member this.GetCustomizationTypes() = Assembly.GetExecutingAssembly().GetExportedTypes() |> Seq.ofArray

        //will download a nuget package and make it available to customization assemblies 
        member this.GetReferencedAssembliesBytes() =
            let req = WebRequest.Create(Uri("http://packages.nuget.org/api/v2/Package/Fmat/1.0.0.0")) 
            use resp = req.GetResponse() 
            use stream = resp.GetResponseStream() 
            let package = new ZipPackage(stream)
            package.GetLibFiles() |> Seq.filter (fun p -> p.EffectivePath = "Fmat.Numerics.dll") |> Seq.map (fun p -> p.GetStream().ReadAllBytes())

Plug in AssemblyFeed extensions into FCell

IExcelAssemblyFeed extensions customize Excel and IWorkbookAssemblyFeed extensions customize workbooks.

For Excel level customization save your extensions in %FCell folder%/Extensions or embed them in XLL file (see Chapter Customization Deployment)

For workbook level customization embed them in the workbook via Doc .NET AddIn screen:

Workbook Customization With Extension