NeuroAgent

Complete Guide: .NET 9 Excel Interop Deployment

Solve .NET 9 Excel interop deployment issues. Discover how to embed interop types and avoid redistributing DLLs in your application installer.

How to Deploy a .NET 9 Application Using Microsoft.Office.Interop.Excel Without Including Interop DLLs?

I have recently migrated a large code base from .NET Framework 4.7.2 to .NET 9. In this code base, we have a few C++/CLI projects which reference the Microsoft.Office.Interop.Excel Nuget package to create Excel files.

Problem Description

When executing from a local compilation, it works fine. However, when deploying to a client computer, we do not include office.dll and Microsoft.Office.Interop.Excel.dll, as I believe we are not legally allowed to do so.

Back with .NET Framework 4.7.2, it worked because of the GAC (Global Assembly Cache), which allowed the application to locate these DLLs in the Office installation on the client’s computer. But now, with .NET 9, we get an exception saying that the DLL cannot be found:

Could not load file or assembly 'Microsoft.Office.Interop.Excel, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'. The system cannot find the file specified.

What I’ve Tried So Far

  1. Embedding interop types in the assembly

    • I believe this is not possible with C++/CLI. So instead, I created a C# project referencing the package with <EmbedInteropTypes>true</EmbedInteropTypes> and then referenced this assembly in the C++/CLI assembly.
    • This did not work, as I had compilation errors saying the types were undefined.
  2. Updating the Nuget package

    • This did not work, as we still get the same exception at runtime (but with the new version number).
  3. Using a COM reference instead

    • In Visual Studio, right-click project > Add reference > COM > Microsoft Excel 16.0 Object Library.
    • This did not work, as we still get a similar exception at runtime:
    Could not load file or assembly 'Interop.Microsoft.Office.Interop.Excel.1.9, Version=1.9.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
    

Additional Context

I have also considered using other libraries, but I don’t think it’s feasible to re-write our excel interop code in the timeframe we have.

Question

Is there any way to deploy a .NET 9 application using Excel Interop on a client computer without including Microsoft.Office.Interop.Excel.dll in the installer?

NeuroAgent

In .NET 9, you can deploy applications using Microsoft.Office.Interop.Excel without redistributing interop DLLs by leveraging the “Embed Interop Types” feature and ensuring Office is properly installed on client machines. This approach eliminates the need to bundle interop assemblies with your application while maintaining compatibility with different Office versions.

Contents

Understanding the Core Requirements

Microsoft.Office.Interop.Excel fundamentally requires Microsoft Office to be installed on the target machine. As clearly stated in the research findings, “You can’t use Microsoft.Office.Interop.Excel without having MS office installed” [source]. This is because the interop assemblies are essentially .NET wrappers around COM objects that are part of the Office installation.

When you migrate from .NET Framework 4.7.2 to .NET 9, the behavior changes significantly. In the .NET Framework era, the Global Assembly Cache (GAC) allowed applications to locate interop assemblies that were installed with Office. However, .NET 9 doesn’t rely on the GAC in the same way, which is why you’re experiencing the “Could not load file or assembly” exception.

The key insight from Microsoft’s documentation is that “More enhancements are possible when you call a COM type that doesn’t require a primary interop assembly (PIA) at run time. Removing the dependency on PIAs results in version independence and easier deployment” [source].

The Embed Interop Types Solution

The primary solution for avoiding interop DLL redistribution in .NET 9 is to enable “Embed Interop Types” for your interop references. This feature was introduced in .NET 4.0 and has been refined in subsequent versions.

How to Enable Embed Interop Types:

  1. For C# Projects:

    • Right-click on the Microsoft.Office.Interop.Excel reference
    • Select “Properties”
    • Set “Embed Interop Types” to True
  2. For C++/CLI Projects (Your Current Challenge):

    xml
    <ItemGroup>
      <Reference Include="Microsoft.Office.Interop.Excel">
        <EmbedInteropTypes>true</EmbedInteropTypes>
      </Reference>
    </ItemGroup>
    

According to the research, “No, that is not necessary anymore since VS2010 and .NET 4.0. You simply set the Embed Interop Types property of the interop assembly reference to True” [source]. This embeds the interop type information directly into your assembly, eliminating the need for separate interop DLLs.

Benefits of This Approach:

  • Version Independence: Your application works with different Office versions
  • No Redistributable Requirements: No need to include interop DLLs in your installer
  • Simplified Deployment: Single deployment package without external dependencies
  • Legal Compliance: Avoids redistributing Microsoft’s interop assemblies

Important Note: Even with embedded interop types, Microsoft Office must still be installed on the target machine. The embedded types only eliminate the need to redistribute the interop assemblies themselves.

Addressing C++/CLI Limitations

Your specific challenge with C++/CLI projects is well-documented in the research. C++/CLI has limitations when it comes to embedded interop types, which explains why you encountered compilation errors saying types were undefined.

Solution Architecture:

Here’s a recommended approach for your C++/CLI scenario:

  1. Create a C# Wrapper Project:

    csharp
    // C# Project with embedded interop types
    public class ExcelInteropWrapper
    {
        public void CreateExcelFile(string filePath)
        {
            var excelApp = new Microsoft.Office.Interop.Excel.Application();
            // Excel operations here
            excelApp.Quit();
        }
    }
    
  2. Reference from C++/CLI:

    cpp
    // C++/CLI Project referencing the C# wrapper
    public ref class ExcelManager
    {
    public:
        void CreateExcelFile(String^ filePath)
        {
            CSharpWrapper::ExcelInteropWrapper^ wrapper = 
                gcnew CSharpWrapper::ExcelInteropWrapper();
            wrapper->CreateExcelFile(filePath);
        }
    };
    
  3. Project Configuration:

    • Set <EmbedInteropTypes>true</EmbedInteropTypes> in the C# project
    • Reference the C# assembly from C++/CLI without interop references

This approach provides type safety while maintaining the benefits of embedded interop types.

Alternative C++/CLI Solution:

If you prefer to keep everything in C++/CLI, consider late binding instead of early binding:

cpp
using namespace System::Runtime::InteropServices;

public ref class ExcelManager
{
public:
    void CreateExcelFile(String^ filePath)
    {
        Type^ excelType = Type::GetTypeFromProgID("Excel.Application");
        dynamic excelApp = Activator::CreateInstance(excelType);
        
        // Use dynamic dispatch for Excel operations
        excelApp->Visible = true;
        // Additional Excel operations...
        
        excelApp->Quit();
    }
};

Late binding eliminates the need for interop references entirely but requires careful handling and loses compile-time type checking.

Alternative Deployment Approaches

1. Office Primary Interop Assemblies (PIA) Installation

If embedded interop types aren’t suitable for your scenario, you can ensure the Office PIAs are installed on target machines:

  • Download: Get the appropriate PIA from Microsoft’s download center
  • Deployment: Include the PIA installer in your deployment package
  • Installation: Run the installer before deploying your application

According to research, “Check into the correct redistributable which targets the interops you are interested in” [source]. This approach provides full interop support but requires additional installation steps.

2. COM Registration Approach

For scenarios where Office is installed but PIAs aren’t:

csharp
// Use COM registration instead of interop references
Type excelType = Type::GetTypeFromProgID("Excel.Application");
dynamic excelApp = Activator::CreateInstance(excelType);

This approach works with any Office version that has the necessary COM components registered.

3. NetOffice Framework

Consider using the NetOffice open-source framework:

  • Version Agnostic: Works with different Office versions
  • No Interop Dependencies: Doesn’t require PIAs
  • Simplified Deployment: Single DLL deployment

As mentioned in the research, “Instead of early binding the reference, there’s an open source project called NetOffice that abstracts this from your project, making life much easier” [source].

Runtime Dependencies and Office Installation

Office Version Compatibility:

Office Version Interop Version .NET Compatibility
Office 2003 11.0.0.0 .NET Framework 2.0+
Office 2007 12.0.0.0 .NET Framework 2.0+
Office 2010 14.0.0.0 .NET Framework 4.0+
Office 2013 15.0.0.0 .NET Framework 4.0+
Office 2016 16.0.0.0 .NET Framework 4.0+
Office 2019 16.0.0.0 .NET Framework 4.0+
Office 365 16.0.0.0 .NET 5.0+

Deployment Checklist:

  1. Verify Office Installation: Ensure target machines have compatible Office version
  2. Check Architecture: Match Office (32/64-bit) with your application
  3. Install PIAs if Needed: For full interop support
  4. Test Runtime Behavior: Validate interop operations on target machines

Error Resolution:

The runtime exception you’re encountering occurs because .NET 9 can’t locate the interop assembly. After implementing embedded interop types, if you still see errors:

  1. Verify Office Installation: Confirm Office is properly installed
  2. Check Architecture: Ensure 32/64-bit compatibility
  3. Register COM Components: Use regsvr32 if needed
  4. Update Runtime: Ensure .NET 9 runtime is installed

Best Practices for .NET 9 Office Interop

1. Use Late Binding When Possible

csharp
dynamic excelApp = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
excelApp.Visible = true;
excelApp.Workbooks.Add();
excelApp.Cells[1, 1].Value = "Hello World";
excelApp.ActiveWorkbook.SaveAs("output.xlsx");
excelApp.Quit();

2. Implement Proper Resource Management

csharp
Excel.Application excelApp = null;
Excel.Workbook workbook = null;

try
{
    excelApp = new Excel.Application();
    excelApp.Visible = false;
    workbook = excelApp.Workbooks.Add();
    
    // Excel operations
    workbook.SaveAs("output.xlsx");
}
finally
{
    if (workbook != null) workbook.Close();
    if (excelApp != null) excelApp.Quit();
    
    // Force garbage collection
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

3. Handle Version Differences Gracefully

csharp
public static Excel.Application GetExcelApplication()
{
    try
    {
        // Try to get existing instance
        return (Excel.Application)Marshal.GetActiveObject("Excel.Application");
    }
    catch
    {
        // Create new instance
        return new Excel.Application();
    }
}

4. Consider Alternative Libraries for Future Development

While you need to maintain your current codebase, consider these alternatives for new functionality:

  • EPPlus: For .xlsx file manipulation without Excel
  • NPOI: Open-source .NET version of POI
  • ClosedXML: .NET library for reading/writing Excel files

These libraries don’t require Office installation and are more suitable for server-side scenarios.

Conclusion

Deploying .NET 9 applications with Office Interop without redistributing DLLs is achievable through the “Embed Interop Types” feature. Here are the key takeaways:

  1. Office Installation is Mandatory: Microsoft.Office.Interop.Excel requires Office to be installed on target machines
  2. Embed Interop Types: Set <EmbedInteropTypes>true</EmbedInteropTypes> to eliminate interop DLL redistribution
  3. C++/CLI Workaround: Use a C# wrapper project with embedded interop types referenced from C++/CLI
  4. Version Independence: Embedded types provide compatibility across Office versions
  5. Alternative Approaches: Consider late binding or frameworks like NetOffice for complex scenarios

For your specific situation, I recommend implementing the C# wrapper approach with embedded interop types, as it provides the best balance between type safety, deployment simplicity, and legal compliance. This approach will resolve your deployment issues while maintaining the functionality of your existing codebase.

Sources

  1. How to access Office interop objects - C# | Microsoft Learn
  2. c# - How to reference Microsoft.Office.Interop.Excel dll? - Stack Overflow
  3. c# - How to use Microsoft.Office.Interop.Excel on a machine without installed MS Office? - Stack Overflow
  4. c# - Distribution of an application that requires Microsoft.Office.Interop.Excel - Stack Overflow
  5. Painless Office Interop Using Visual C# - Claudio Bernasconi
  6. How to use Microsoft.Office.Interop.Excel without installing - C# Corner
  7. r/csharp on Reddit: Can I use Microsoft.Office.Interop.Excel without having Excel installed?
  8. c# - Use Office 2003 interop DLLs without installing the redistributable - Stack Overflow
  9. c# - Export to excel without using third party dll - Stack Overflow
  10. asp.net - How to deploy my application with Excel Export feature? - Stack Overflow
  11. How to: Register Primary Interop Assemblies - .NET Framework | Microsoft Learn
  12. Deploying an Interop Application - .NET Framework | Microsoft Learn
  13. Build and Deploy a .NET COM Assembly - Simple Talk
  14. How to install folder Microsoft.NET\Primary Interop Assemblies?? - MSDN Forums
  15. c# - Should I deploy Interop.x.dll files with .NET application? - Stack Overflow