Как развернуть приложение .NET 9, использующее Microsoft.Office.Interop.Excel, без включения Interop DLL?
Недавно я перенес большой кодовой проект с .NET Framework 4.7.2 на .NET 9. В этом проекте у нас есть несколько проектов C++/CLI, которые ссылаются на пакет NuGet Microsoft.Office.Interop.Excel для создания файлов Excel.
Описание проблемы
При выполнении с локальной компиляции все работает нормально. Однако при развертывании на компьютере клиента мы не включаем office.dll и Microsoft.Office.Interop.Excel.dll, поскольку, как я понимаю, мы не имеем на это юридического права.
В .NET Framework 4.7.2 это работало благодаря GAC (Global Assembly Cache), который позволял приложению находить эти DLL-файлы в установке Office на компьютере клиента. Но теперь, с .NET 9, мы получаем исключение, говорящее, что DLL не найдена:
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.
Что я уже пробовал
-
Внедрение типов взаимодействия в сборку
- Я считаю, что это невозможно с C++/CLI. Поэтому вместо этого я создал проект C#, ссылающийся на пакет с
<EmbedInteropTypes>true</EmbedInteropTypes>, а затем сослался на эту сборку в сборке C++/CLI. - Это не сработало, так как у меня возникли ошибки компиляции, говорящие, что типы не определены.
- Я считаю, что это невозможно с C++/CLI. Поэтому вместо этого я создал проект C#, ссылающийся на пакет с
-
Обновление пакета NuGet
- Это не сработало, так как мы все равно получаем то же исключение во время выполнения (но с новым номером версии).
-
Использование COM-ссылки вместо этого
- В Visual Studio: щелкните правой кнопкой мыши по проекту > Добавить ссылку > COM > Библиотека объектов Microsoft Excel 16.0.
- Это не сработало, так как мы все равно получаем похожее исключение во время выполнения:
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.
Дополнительная информация
Я также рассматривал возможность использования других библиотек, но я не думаю, что в отведенные сроки будет возможно переписать наш код взаимодействия с Excel.
Вопрос
Существует ли способ развернуть приложение .NET 9, использующее взаимодействие с Excel, на компьютере клиента без включения Microsoft.Office.Interop.Excel.dll в установщик?
В .NET 9 вы можете развертывать приложения с использованием Microsoft.Office.Interop.Excel без повторного распространения interop DLL, используя функцию “Embed Interop Types” и обеспечивая правильную установку Office на клиентских машинах. Этот подход устраняет необходимость включать interop сборки в ваше приложение, сохраняя совместимость с разными версиями Office.
Содержание
- Основные требования
- Решение с внедрением типов взаимодействия
- Преодоление ограничений C++/CLI
- Альтернативные подходы к развертыванию
- Зависимости времени выполнения и установка Office
- Лучшие практики для Office Interop в .NET 9
Основные требования
Microsoft.Office.Interop.Excel в первую очередь требует установки Microsoft Office на целевой машине. Как четко указано в результатах исследования, “Вы не можете использовать Microsoft.Office.Interop.Excel без установленного MS Office” [источник]. Это связано с тем, что interop сборки по сути являются .NET-обертками для COM-объектов, которые являются частью установки Office.
При миграции с .NET Framework 4.7.2 на .NET 9 поведение значительно меняется. В эпоху .NET Framework Глобальный кэш сборок (GAC) позволял приложениям находить interop сборки, установленные вместе с Office. Однако .NET 9 не полагается на GAC таким же образом, что объясняет исключение “Не удалось загрузить файл или сборку”.
Ключевое замечание из документации Microsoft заключается в том, что “Дополнительные улучшения возможны при вызове COM-типа, который не требует основной сборки взаимодействия (PIA) во время выполнения. Устранение зависимости от PIA приводит к независимости от версии и упрощению развертывания” [источник].
Решение с внедрением типов взаимодействия
Основным решением для избежания повторного распространения interop DLL в .NET 9 является включение функции “Embed Interop Types” для ваших ссылок на interop. Эта функция была представлена в .NET 4.0 и усовершенствовалась в последующих версиях.
Как включить внедрение типов взаимодействия:
-
Для проектов C#:
- Щелкните правой кнопкой мыши по ссылке на Microsoft.Office.Interop.Excel
- Выберите “Свойства”
- Установите для “Embed Interop Types” значение True
-
Для проектов C++/CLI (Ваша текущая проблема):
xml<ItemGroup> <Reference Include="Microsoft.Office.Interop.Excel"> <EmbedInteropTypes>true</EmbedInteropTypes> </Reference> </ItemGroup>
Согласно исследованиям, “Нет, это больше не необходимо с VS2010 и .NET 4.0. Просто установите свойство Embed Interop Types для ссылки на interop сборку в True” [источник]. Это внедряет информацию о типах взаимодействия непосредственно в вашу сборку, устраняя необходимость в отдельных interop DLL.
Преимущества этого подхода:
- Независимость от версии: Ваше приложение работает с разными версиями Office
- Отсутствие требований к распространяемым компонентам: Не нужно включать interop DLL в установщик
- Упрощенное развертывание: единый пакет развертывания без внешних зависимостей
- Соответствие требованиям лицензирования: Избегает распространения interop сборок Microsoft
Важное замечание: Даже с внедренными типами взаимодействия, Microsoft Office по-прежнему должен быть установлен на целевой машине. Внедренные типы только устраняют необходимость в повторном распространении самих interop сборок.
Преодоление ограничений C++/CLI
Ваша конкретная проблема с проектами C++/CLI хорошо задокументирована в исследованиях. C++/CLI имеет ограничения при работе с внедренными типами взаимодействия, что объясняет, почему вы столкнулись с ошибками компиляции, говорящими о неопределенных типах.
Архитектура решения:
Вот рекомендуемый подход для вашей ситуации с C++/CLI:
-
Создайте проект-обертку на C#:
csharp// Проект на C# с внедренными типами взаимодействия public class ExcelInteropWrapper { public void CreateExcelFile(string filePath) { var excelApp = new Microsoft.Office.Interop.Excel.Application(); // Операции с Excel здесь excelApp.Quit(); } } -
Ссылка из C++/CLI:
cpp// Проект C++/CLI с ссылкой на обертку C# public ref class ExcelManager { public: void CreateExcelFile(String^ filePath) { CSharpWrapper::ExcelInteropWrapper^ wrapper = gcnew CSharpWrapper::ExcelInteropWrapper(); wrapper->CreateExcelFile(filePath); } }; -
Конфигурация проекта:
- Установите
<EmbedInteropTypes>true</EmbedInteropTypes>в проекте на C# - Ссылайтесь на сборку C# из C++/CLI без ссылок на interop
- Установите
Этот подход обеспечивает безопасность типов, сохраняя преимущества внедренных типов взаимодействия.
Альтернативное решение для C++/CLI:
Если вы предпочитаете оставить все в C++/CLI, рассмотрите позднее связывание вместо раннего:
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);
// Используйте динамическое распределение для операций с Excel
excelApp->Visible = true;
// Дополнительные операции с Excel...
excelApp->Quit();
}
};
Позднее связывание полностью устраняет необходимость в ссылках на interop, но требует тщательной обработки и теряет проверку типов времени компиляции.
Альтернативные подходы к развертыванию
1. Установка основных сборок взаимодействия Office (PIA)
Если внедренные типы взаимодействия не подходят для вашей ситуации, вы можете убедиться, что PIA Office установлены на целевых машинах:
- Загрузка: Получите соответствующую PIA с центра загрузки Microsoft
- Развертывание: Включите установщик PIA в пакет развертывания
- Установка: Запустите установщик перед развертыванием вашего приложения
Согласно исследованиям, “Проверьте правильный распространяемый компонент, предназначенный для interop, которые вас интересуют” [источник]. Этот подход обеспечивает полную поддержку interop, но требует дополнительных этапов установки.
2. Подход на основе регистрации COM
Для сценариев, где Office установлен, но PIA отсутствуют:
// Используйте регистрацию COM вместо ссылок на interop
Type excelType = Type::GetTypeFromProgID("Excel.Application");
dynamic excelApp = Activator::CreateInstance(excelType);
Этот подход работает с любой версией Office, имеющей необходимые зарегистрированные COM-компоненты.
3. Framework NetOffice
Рассмотрите использование открытого фреймворка NetOffice:
- Независимость от версии: Работает с разными версиями Office
- Отсутствие зависимостей от interop: Не требует PIA
- Упрощенное развертывание: Развертывание одной DLL
Как упоминалось в исследованиях, “Вместо раннего связывания ссылки, существует проект с открытым исходным кодом под названием NetOffice, который абстрагирует это от вашего проекта, значительно упрощая жизнь” [источник].
Зависимости времени выполнения и установка Office
Совместимость версий Office:
| Версия Office | Версия Interop | Совместимость с .NET |
|---|---|---|
| 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+ |
Контрольный список развертывания:
- Проверьте установку Office: Убедитесь, что на целевых машинах установлена совместимая версия Office
- Проверьте архитектуру: Сопоставьте архитектуру Office (32/64-бит) с вашим приложением
- Установите PIA при необходимости: Для полной поддержки interop
- Проверьте поведение времени выполнения: Проверьте операции interop на целевых машинах
Решение ошибок:
Исключение времени выполнения, с которым вы столкнулись, возникает потому, что .NET 9 не может найти interop сборку. После внедрения типов взаимодействия, если вы все еще видите ошибки:
- Проверьте установку Office: Подтвердите, что Office правильно установлен
- Проверьте архитектуру: Обеспечьте совместимость 32/64-бит
- Зарегистрируйте COM-компоненты: Используйте
regsvr32при необходимости - Обновите среду выполнения: Убедитесь, что установлена среда выполнения .NET 9
Лучшие практики для Office Interop в .NET 9
1. Используйте позднее связывание, когда это возможно
dynamic excelApp = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
excelApp.Visible = true;
excelApp.Workbooks.Add();
excelApp.Cells[1, 1].Value = "Привет, мир";
excelApp.ActiveWorkbook.SaveAs("output.xlsx");
excelApp.Quit();
2. Реализуйте правильное управление ресурсами
Excel.Application excelApp = null;
Excel.Workbook workbook = null;
try
{
excelApp = new Excel.Application();
excelApp.Visible = false;
workbook = excelApp.Workbooks.Add();
// Операции с Excel
workbook.SaveAs("output.xlsx");
}
finally
{
if (workbook != null) workbook.Close();
if (excelApp != null) excelApp.Quit();
// Принудительная сборка мусора
GC.Collect();
GC.WaitForPendingFinalizers();
}
3. Корректно обрабатывайте различия версий
public static Excel.Application GetExcelApplication()
{
try
{
// Попробуйте получить существующий экземпляр
return (Excel.Application)Marshal.GetActiveObject("Excel.Application");
}
catch
{
// Создайте новый экземпляр
return new Excel.Application();
}
}
4. Рассмотрите альтернативные библиотеки для будущего развития
Хотя вам нужно поддерживать текущую кодовую базу, рассмотрите эти альтернативы для новой функциональности:
- EPPlus: Для манипулирования .xlsx файлами без Excel
- NPOI: Открытая .NET-версия POI
- ClosedXML: .NET библиотека для чтения/записи Excel файлов
Эти библиотеки не требуют установки Office и более подходят для серверных сценариев.
Заключение
Развертывание приложений .NET 9 с Office Interop без повторного распространения DLL достижимо с помощью функции “Embed Interop Types”. Вот ключевые выводы:
- Установка Office обязательна: Microsoft.Office.Interop.Excel требует установки Office на целевых машинах
- Внедрение типов взаимодействия: Установите
<EmbedInteropTypes>true</EmbedInteropTypes>для устранения необходимости повторного распространения interop DLL - Обход для C++/CLI: Используйте проект-обертку на C# с внедренными типами взаимодействия, на который ссылаются из C++/CLI
- Независимость от версии: Внедренные типы обеспечивают совместимость между версиями Office
- Альтернативные подходы: Рассмотрите позднее связывание или фреймворки, такие как NetOffice, для сложных сценариев
Для вашей конкретной ситуации я рекомендую реализовать подход с оберткой на C# с внедренными типами взаимодействия, так как он обеспечивает наилучший баланс между безопасностью типов, простотой развертывания и соответствием требованиям лицензирования. Этот подход решит ваши проблемы развертывания, сохраняя функциональность существующей кодовой базы.
Источники
- How to access Office interop objects - C# | Microsoft Learn
- c# - How to reference Microsoft.Office.Interop.Excel dll? - Stack Overflow
- c# - How to use Microsoft.Office.Interop.Excel on a machine without installed MS Office? - Stack Overflow
- c# - Distribution of an application that requires Microsoft.Office.Interop.Excel - Stack Overflow
- Painless Office Interop Using Visual C# - Claudio Bernasconi
- How to use Microsoft.Office.Interop.Excel without installing - C# Corner
- r/csharp on Reddit: Can I use Microsoft.Office.Interop.Excel without having Excel installed?
- c# - Use Office 2003 interop DLLs without installing the redistributable - Stack Overflow
- c# - Export to excel without using third party dll - Stack Overflow
- asp.net - How to deploy my application with Excel Export feature? - Stack Overflow
- How to: Register Primary Interop Assemblies - .NET Framework | Microsoft Learn
- Deploying an Interop Application - .NET Framework | Microsoft Learn
- Build and Deploy a .NET COM Assembly - Simple Talk
- How to install folder Microsoft.NET\Primary Interop Assemblies?? - MSDN Forums
- c# - Should I deploy Interop.x.dll files with .NET application? - Stack Overflow