При интеграции приложений на платформе .NET (C#) с «1С:Предприятие» нередко возникает задача выноса специфической логики во внешнюю обработку (файл с расширением .epf). Это особенно актуально, когда используется базовая конфигурация или конфигурация, находящаяся на полной поддержке поставщика, в которую нельзя вносить изменения напрямую.
Однако при попытке инициализировать обработку через менеджер внешних обработок разработчики часто сталкиваются с ошибкой «Ссылка на объект не указывает на экземпляр объекта» (NullReferenceException) непосредственно на этапе выполнения метода ВнешниеОбработки.Создать(). Разберем по шагам, почему возникает эта ошибка, как настроить платформу 1С и как правильно вызывать методы внешней обработки из C#.
Проанализируем типовую ситуацию. Подключение к информационной базе проходит успешно, запросы и выборки по справочникам отрабатывают без нареканий, но следующая строка на C# приводит к падению программы:
dynamic extProcess = com1Cserv.ВнешниеОбработки.Создать(@"D:\1C BASE\OtherExtCodes\SetRegisterRecord.epf", false);
Выясним причину такого поведения. Начиная с версии платформы 8.3.9, в 1С реализован встроенный механизм безопасности — «Защита от опасных действий». При попытке программного или интерактивного открытия внешнего файла платформе требуется запросить у пользователя подтверждение на открытие потенциально опасного содержимого.
В сеансе COM-соединения (объект V83.COMConnector) графический интерфейс пользователя полностью отсутствует. Так как модальное диалоговое окно подтверждения не может быть выведено на экран, среда исполнения 1С прерывает операцию или возвращает пустое значение. В приложении на C# тип dynamic пытается разрешить обращение к несуществующему объекту, из-за чего выбрасывается исключение NullReferenceException.
Рассмотрим первый вариант решения проблемы, который позволяет отключить предупреждения на уровне конфигурационных файлов сервера или локального клиента 1С. Этот подход удобен при разработке и отладке на выделенном рабочем месте.
conf.cfg. Обычно он располагается в каталоге установки платформы (например, C:\Program Files\1cv8\conf\conf.cfg) или в общесистемном каталоге настроек.
DisableUnsafeActionProtection=.*
Более точечный и безопасный метод — отключить защиту для конкретного сервисного пользователя, от имени которого выполняется COM-соединение из C#. Разберем, как это сделать:
Если требуется отключить эту проверку программно из встроенного языка 1С, используем свойство пользователя информационной базы:
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени("ComUser");
ПользовательИБ.ЗащитаОтОпасныхДействий.ПредупреждатьОбОпасныхДействиях = Ложь;
ПользовательИБ.Записать();
Вместо непосредственного вызова метода Создать() можно сначала выполнить регистрацию обработки во внутреннем хранилище сеанса с помощью метода Подключить(), явно передав флаг отключения безопасного режима:
string path = @"D:\1C BASE\OtherExtCodes\SetRegisterRecord.epf";
string extName = com1Cserv.ВнешниеОбработки.Подключить(path, "МояВнешняяОбработка", false);
dynamic extProcess = com1Cserv.ВнешниеОбработки.Создать(extName, false);
Метод Подключить() связывает внешний файл с уникальным именем во временном контексте базы данных, после чего создание объекта по имени происходит штатно.
Посмотрим на пример законченного кода на C#, который подключается к базе, создает экземпляр внешней обработки, выполняет экспортную функцию и корректно освобождает системные ресурсы COM:
using System;
using System.Runtime.InteropServices;
namespace Integration1C
{
class Program
{
static void Main(string[] args)
{
Type comType = Type.GetTypeFromProgID("V83.COMConnector");
dynamic connector = Activator.CreateInstance(comType);
string connectionString = @"File=""D:\1C BASE\BaseRoznica"";Usr=""ComUser"";Pwd=""Password123"";";
dynamic com1Cserv = null;
dynamic extProcess = null;
try
{
com1Cserv = connector.Connect(connectionString);
string path = @"D:\1C BASE\OtherExtCodes\SetRegisterRecord.epf";
// Создаем экземпляр обработки (второй параметр - безопасный режим)
extProcess = com1Cserv.ВнешниеОбработки.Создать(path, false);
// Вызываем экспортную функцию из модуля объекта внешней обработки
dynamic result = extProcess.ВыполнитьДействие();
Console.WriteLine("Результат из 1С: " + result);
}
catch (Exception ex)
{
Console.WriteLine("Ошибка выполнения: " + ex.Message);
}
finally
{
// Обязательно освобождаем COM-объекты для исключения зависания процессов
if (extProcess != null)
{
Marshal.ReleaseComObject(extProcess);
}
if (com1Cserv != null)
{
Marshal.ReleaseComObject(com1Cserv);
}
if (connector != null)
{
Marshal.ReleaseComObject(connector);
}
}
}
}
}
При вызове обработки из внешнего соединения действуют ограничения серверного контекста платформы 1С:
Экспорт:
Функция ВыполнитьДействие() Экспорт
// Серверная логика обработки данных
Возврат "Успешно";
КонецФункции
Предупреждение(), Вопрос(), ОткрытьФорму()) и директивы компиляции &НаКлиенте. Их вызов в контексте COM приведет к аварийной остановке выполнения.Если в конфигурации используется библиотека стандартных подсистем (БСП), как в конфигурации «1С:Розница», не обязательно хранить файл .epf на локальном диске в файловой системе. Обработку можно зарегистрировать непосредственно в справочнике ДополнительныеОтчетыИОбработки через пользовательский интерфейс 1С.
В этом случае логика обработки вызывается через стандартный программный интерфейс БСП:
dynamic refProcessing = com1Cserv.Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("ИнтеграцияСклады");
dynamic objectProcessing = com1Cserv.ДополнительныеОтчетыИОбработки.ОбъектВнешнейОбработки(refProcessing);
objectProcessing.ВыполнитьДействие();
Такой подход упрощает администрирование: обновление логики обработки выполняется непосредственно внутри базы данных без необходимости заменять файлы на сервере или рабочей станции.