суббота, 3 сентября 2011 г.

Работа с 1С 8.х из .Net приложений при помощи dynamic типов

В реалиях нашего рынка превалирующей по количеству внедрений учётной системой является 1C и рано или поздно люди, которые занимаются внедрением CRM систем сталкиваются с задачами интеграции/синхронизации данных между CRM и учётных систем (в частном случае 1C). Вот и передо мной эта задача тоже встала.

1С начиная с версии 8.0 предоставляет более-менее адекватный механизм работы с данными и метаданными системы - COM объект.

В качестве примера кода поставлю задачу создания в 1С контрагента и получения его кода.



Как работа с 1С выглядела до появления .Net Framework 4.0 и типа dynamic:

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Type connector = Type.GetTypeFromProgID("V81.ComConnector");

if (connector == null)
throw new Exception(string.Format("COM Class Object {0} was not created or not registered in the system!", "V81.ComConnector"));

object connectorInstance = Activator.CreateInstance(connector);

if (connectorInstance == null)
throw new Exception(string.Format("Instance of class {0} was not created", "V81.ComConnector"));


//Подключение к базе
object _connection = connectorInstance.GetType().InvokeMember("Connect", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, connectorInstance, new object[] { "File=\"C:\\tmp\";" });

//Получение справочника контрагентов
object _dictionary = _connection.GetType().InvokeMember("NewObject", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, _connection, new object[] { "СправочникМенеджер.Контрагенты" });

//создание новой записи
object _record = _dictionary.GetType().InvokeMember("СоздатьЭлемент", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, _dictionary, null);

//Заполнение поля наименование
_record.GetType().InvokeMember("НаименованиеПолное", BindingFlags.Public | BindingFlags.SetProperty, null, _record, new object[] { "Наша тестовая организация" });

//Сохранение записи
_record.GetType().InvokeMember("Write", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, _record, null);

//Получение кода созданной организации
string code = _record.GetType().InvokeMember("Код", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static, null, _record, new object[] { }) as string;

//Выведение кода на консоль для проверки
Console.WriteLine(code);
Console.ReadKey();
}
}
}


Всё в принципе понятно, но такое количество рефлекссии на строку кода - немного ужасающе...

А теперь посмотрим тот же под, но написанный при помощи типов dynamic:

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Type connector = Type.GetTypeFromProgID("V81.ComConnector");

if (connector == null)
throw new Exception(string.Format("COM Class Object {0} was not created or not registered in the system!", "V81.ComConnector"));

dynamic connectorInstance = Activator.CreateInstance(connector);

if (connectorInstance == null)
throw new Exception(string.Format("Instance of class {0} was not created", "V81.ComConnector"));

//Подключение к базе
dynamic _connection = connectorInstance.Connect("File=\"C:\\tmp\";");

//Получение справочника контрагентов
dynamic _dictionary = _connection.NewObject("СправочникМенеджер.Контрагенты");

//создание новой записи
dynamic _record = _dictionary.СоздатьЭлемент();

//Заполнение поля наименование
_record.НаименованиеПолное = "Наша тестовая организация";

//Сохранение записи
_record.Write();

//Получение кода созданной организации
string code = _record.Код as string;

//Выведение кода на консоль для проверки
Console.WriteLine(code);
Console.ReadKey();
}
}
}


И результаты работы обеих программ:




Комментариев нет:

Отправить комментарий