Текущее время: Ср, дек 13 2017, 09:24

Часовой пояс: UTC + 4 часа


Правила форума


ВНИМАНИЕ!

Вопросы по SAP Query и Quick View - сюда



Начать новую тему Ответить на тему  [ Сообщений: 39 ]  На страницу 1, 2, 3  След.
Автор Сообщение
 Заголовок сообщения: sap .NET connector
СообщениеДобавлено: Пт, мар 25 2016, 10:32 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
Добрый день, коллеги!
никогда не приходилось писать внешние программы для RFC-соединений. но видать пришла пора.

есть такая тема как diadoc.ru (API http://api-docs.diadoc.ru/ru/latest/)
нам нужно сделать саповский интерфейс для управления документами на diadoc.ru.
диадок предоставил нам DLL-ку, которая формирует HTTP-запросы для обмена данными.
так же они нам предоставили тестовый EXE-файл (использует DLL-ку), в котором реализована только одна функция авторизации.
Exe-шник прописывается в RFC-соединении (тип Т) с галкой Start on front-end Work Station. пишем RFC функцию авторизации. все работает.
логика работы: вызываем RFC. вызывается экзешник, который делает HTTP-запрос к диадок, получает ответ, преобразовывает его в формат RFC-параметров и возвращает в RFC.

решили расширять их экзешник для остальных запросов реализованных в DLL. декомпилировали и получили c#-овский исходник.
начали дорабатывать и сразу проблема:
если я вот так объявляю функцию в EXE
Код:
       
        [RfcServerFunction(Name = "ZDDK_LOGIN"),
        RepositoryFunctionParamameter("I_LOGIN", RfcDataType.STRING, RfcDirection.IMPORT),
        RepositoryFunctionParamameter("I_PASSWORD", RfcDataType.STRING, RfcDirection.IMPORT),
        RepositoryFunctionParamameter("O_ORGS", RfcDataType.STRING, RfcDirection.EXPORT),
        RepositoryFunctionParamameter("O_TOKEN", RfcDataType.STRING, RfcDirection.EXPORT)]
        public void diadoc_login(RfcServerContext context, IRfcFunction function)
        {
         .....
        }

то все работает на ура.
но как только хочу чтобы функция возвращала в RFC какую-то таблицу, то сразу перестает срабатывать даже тест соединения из SM59
делаю так
Код:
       
        [RfcServerFunction(Name = "ZDDK_LOGIN"),
        RepositoryFunctionParamameter("I_LOGIN", RfcDataType.STRING, RfcDirection.IMPORT),
        RepositoryFunctionParamameter("I_PASSWORD", RfcDataType.STRING, RfcDirection.IMPORT),
        RepositoryFunctionParamameter("O_ORGS", RfcDataType.STRING, RfcDirection.EXPORT),
        RepositoryFunctionParamameter("O_TOKEN", RfcDataType.STRING, RfcDirection.EXPORT),
        RepositoryFunctionParamameter("O_ORGS_T", RfcDataType.TABLE, RfcDirection.TABLES)]
        public void diadoc_login(RfcServerContext context, IRfcFunction function)
        {
          ....
        }


Собственно в этом и вопрос. Как из Exe возвращать заполненную внутреннюю таблицу в RFC?
хорошо бы примерчик какой-нибудь.

Используем sap nco 3.0 для net 4.0.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пт, мар 25 2016, 11:41 
Гуру-эксперт
Гуру-эксперт
Аватара пользователя

Зарегистрирован:
Ср, ноя 03 2004, 15:51
Сообщения: 1827
Откуда: КраснАдар
Пол: Мужской
А зачем все так сложно делать? Авторизоваться по http Вы можете и из SAP, используя интерфейс IF_HTTP_CLIENT. У нас решение именно так работает уже несколько лет.

Если нужны специфические методы Диадока, то мы используем Diadoc SDK, который устанавливается на пользовательском ПК под управлением Windows (плюс необходимо Microsoft .NET Framework 4 доставить). Дальше все через COM-объект решается.


Принять этот ответ
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пт, мар 25 2016, 12:35 
Специалист
Специалист

Зарегистрирован:
Чт, мар 25 2010, 10:02
Сообщения: 195
Чтобы через IF_HTTP_CLIENT общаться с диадоком (в фоновом режиме) раньше надо было уметь из абапа работать с Protocol Buffers, естественно готовых решений для этого нет. Но теперь, как я посмотрел у них на сайте, они также поддерживают JSON что из абапа сделать гораздо проще, хоть руками конкатенировать, хоть с помощью XSLT, даже классы какие-то были для сериализации\десериализации JSON. Хотя сам Диадок не рекомендует JSON использовать.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пт, мар 25 2016, 13:18 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
забыл написать. у нас 4.6 если что.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пт, мар 25 2016, 15:37 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
Цитата:
Чтобы через IF_HTTP_CLIENT общаться с диадоком (в фоновом режиме) раньше надо было уметь из абапа работать с Protocol Buffers


и таки да...
в DLLке уже ведь все реализовано (PROTOBUF). поэтому и хочется именно ее использовать.

но вопрос не про то что проще или нет...

вопрос про то почему при добавлении RepositoryFunctionParamameter("O_ORGS_T", RfcDataType.TABLE, RfcDirection.TABLES) соединение перестает работать? и как из этого выходить? неужто нужно возвращать в RFC строку и ее потом парсить.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пн, мар 28 2016, 04:59 
Специалист
Специалист

Зарегистрирован:
Чт, мар 25 2010, 10:02
Сообщения: 195
А из системы вы вызываете через TCP/IP RFC в котором указана ид зарегистрированной программы сервера? Обычно в таких случаях внешняя программа имеет собственное соединение в сторону SAP-сервера чтобы считать метаданные ФМ (тип и длины полей). Если такого соединения нет, то вроде как где-то надо явно все детали ФМ описывать (я сужу по SDK для C++).


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пн, мар 28 2016, 12:12 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
Цитата:
А из системы вы вызываете через TCP/IP RFC в котором указана ид зарегистрированной программы сервера?

точно так

Цитата:
Обычно в таких случаях внешняя программа имеет собственное соединение в сторону SAP-сервера чтобы считать метаданные ФМ (тип и длины полей). Если такого соединения нет, то вроде как где-то надо явно все детали ФМ описывать (я сужу по SDK для C++).

все это хорошо, только я не понимаю как объявлять функцию.
Если при объявлении функции я пишу RepositoryFunctionParamameter("O_ORGS_T", RfcDataType.TABLE, RfcDirection.TABLES), то перестает работать тест соединения в SM59 (получаю ошибку "timeout during allocate").
Если не писать этого, то тогда при запуске RFC функции в SE37 получаем дамп с ошибкой "Element O_ORGS_T of container metadata ZDDK_LOGIN unknown"


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пн, мар 28 2016, 12:41 
Гуру-эксперт
Гуру-эксперт
Аватара пользователя

Зарегистрирован:
Ср, ноя 03 2004, 15:51
Сообщения: 1827
Откуда: КраснАдар
Пол: Мужской
Если я правильно понимаю, то RepositoryFunctionParamameter - это некая процедура из библиотеки Диадок, которая обрабатывает метаданные из интерфейса SAP модуля. Возможно, что там проблема и лежит и нужно дергать того, кто Вам ее предоставил.

И еще. Вы не пробовали прогнать O_ORGS_T через EXPORT или CHANGING параметр?


Принять этот ответ
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пн, мар 28 2016, 13:21 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
Цитата:
Если я правильно понимаю, то RepositoryFunctionParamameter - это некая процедура из библиотеки Диадок

Нет. это приблуда SAP CONNECTOR-а.

Цитата:
И еще. Вы не пробовали прогнать O_ORGS_T через EXPORT или CHANGING параметр?

попробовал так RepositoryFunctionParamameter("ET_ORGS", RfcDataType.TABLE, RfcDirection.CHANGING) - тест соединения в SM59 не проходит
не нравится почему-то слово TABLE. Со строками все нормально. можно конечно какой-нить XML в виде строки возвращать. но это же потом в сапе парсить нужно. хотелось схалявить.
попробовал еще так RepositoryFunctionParamameter("ET_ORGS", RfcDataType.UNKNOWN, RfcDirection.CHANGING). результат тот же.

попробую диадоковцам написать. может научат как с этим сап-коннектором работать.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пн, мар 28 2016, 14:33 
Гуру-эксперт
Гуру-эксперт
Аватара пользователя

Зарегистрирован:
Ср, ноя 03 2004, 15:51
Сообщения: 1827
Откуда: КраснАдар
Пол: Мужской
_garycor_ писал(а):
Нет. это приблуда SAP CONNECTOR-а.

Вы под SAP CONNECTOR что конкретно понимаете - SAP .Net Connector или что-то иное? Меня очень смущает два фактора - орфографическая ошибка в названии процедуры и полная неосведомленность Google о ней.

Внутренний голос мне подсказывает, что к решениям SAP такой вызов отношения не имеет, по крайней мере прямого. Если же это все таки стандарт, подскажите, где бы можно было об этом почитать. Вопрос интересный, потому как возникают периодически проблемы с Google Protocol Buffers и хотелось бы с предложенным решением, в будущем, тоже ознакомиться.


Принять этот ответ
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пн, мар 28 2016, 15:01 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
Цитата:
Вы под SAP CONNECTOR что конкретно понимаете - SAP .Net Connector или что-то иное?

да. именно sap .net connector.

Цитата:
Меня очень смущает два фактора - орфографическая ошибка в названии процедуры

что за ошибка? не эта случайно RepositoryFunctionParamameter? это c# при вводе так и предлагает выбрать. внутрях sapnco.dll наверное так и прописано.

Цитата:
Если же это все таки стандарт, подскажите, где бы можно было об этом почитать.

на счет стандарта.... не знаю... я уже не уверен, что нужно писать именно так
Код:
[RfcServerFunction(Name = "ZDDK_LOGIN"),
        RepositoryFunctionParamameter("I_LOGIN", RfcDataType.STRING, RfcDirection.IMPORT),
        RepositoryFunctionParamameter("I_PASSWORD", RfcDataType.STRING, RfcDirection.IMPORT),
        RepositoryFunctionParamameter("O_ORGS", RfcDataType.STRING, RfcDirection.EXPORT),
        RepositoryFunctionParamameter("O_TOKEN", RfcDataType.STRING, RfcDirection.EXPORT)]
        public void diadoc_login(RfcServerContext context, IRfcFunction function)
        {

я в первом посте писал, что этот код выдал декомпилятор.... может тут собака и зарыта. и нужно на самом деле по другому все делать. хотя без таблиц все работает.


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Пн, мар 28 2016, 18:17 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
вот пример из самого сап коннектора
Код:
            [RfcServerFunction(Name = "STFC_CONNECTION")]
            public static void StfcConnection(RfcServerContext serverContext, IRfcFunction function)
            {
                ...
            String requtext = function.GetString("REQUTEXT");
                ...
               function.SetValue("ECHOTEXT", function.GetString("REQUTEXT"));
               function.SetValue("RESPTEXT", "NCO3: Hello world.");
                ...
            }

правда пример я не пытался компилировать

таких строк типа RepositoryFunctionParamameter("I_LOGIN", RfcDataType.STRING, RfcDirection.IMPORT) вообще нет.
у меня если такие строки убираю, то RFCшка при вызове начинает в дамп валиться с ошибкой типа "Element E_ORGS of container metadata ZDDK_DIADOC_TEST unknown"


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Вт, мар 29 2016, 09:46 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
Обманул я на счет RepositoryFunctionParamameter.
это диадоковский класс. Вы правы.
Код:
namespace KonturAPI_SAP
{
    using SAP.Middleware.Connector;
    using System;
    using System.Runtime.CompilerServices;

    [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
    public class RepositoryFunctionParamameter : Attribute
    {
        public RepositoryFunctionParamameter(string name, RfcDataType type, RfcDirection direction)
        {
            this.Name = name;
            this.Type = type;
            this.Direction = direction;
        }

        public RfcDirection Direction { get; set; }

        public string Name { get; set; }

        public RfcDataType Type { get; set; }
    }
}


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Ср, мар 30 2016, 14:48 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
Добрый день, коллеги!
к чему пришел.
как писал AFH, действительно, нужно прописывать хард-кодом репозитарий на стороне сервера.
для этого как раз и создан был класс RepositoryFunctionParamameter.
я от него избавился.
формирую репозитарий руками. делаю так.
Код:
    public class CustomRepository
    {
        public static RfcCustomRepository create()
        {
            RfcCustomRepository repository = new RfcCustomRepository();
            foreach (MethodInfo info in typeof(Handler).GetMethods())
            {
                MethodBase methodFromHandle = MethodBase.GetMethodFromHandle(info.MethodHandle);
                RfcServerFunctionAttribute customAttribute = (RfcServerFunctionAttribute) methodFromHandle.GetCustomAttribute(typeof(RfcServerFunctionAttribute));
                if (customAttribute != null)
                {
                    RfcFunctionMetadata fmd = new RfcFunctionMetadata(customAttribute.Name);
                    switch (fmd.Name)
                    {
                        case "ZDDK_DIADOC_TEST":
                            fmd.AddParameter(new RfcParameterMetadata("I_LOGIN", RfcDataType.STRING, RfcDirection.IMPORT, false));
                            fmd.AddParameter(new RfcParameterMetadata("I_PASSWORD", RfcDataType.STRING, RfcDirection.IMPORT, false));
                            fmd.AddParameter(new RfcParameterMetadata("E_TOKEN", RfcDataType.STRING, RfcDirection.EXPORT, false));
                            fmd.AddParameter(new RfcParameterMetadata("E_ORGS", RfcDataType.STRING, RfcDirection.EXPORT, false));
                           
                            RfcStructureMetadata stru = new RfcStructureMetadata("TLINE");
                            stru.AddField(new RfcFieldMetadata("TDFORMAT", RfcDataType.CHAR, 2, 0, 0, 0));
                            stru.AddField(new RfcFieldMetadata("TDLINE", RfcDataType.CHAR, 132, 0, 0, 0));
                            RfcTableMetadata t = new RfcTableMetadata("ET_ORGS", stru);
                            fmd.AddParameter(new RfcParameterMetadata("ET_ORGS", t, RfcDirection.TABLES, false));
                           
                            break;
                    }
                    repository.AddFunctionMetadata(fmd);
                }
            }
            return repository;
        }
    }

как видно я тут пытаюсь добавить таблицу.

сама функция сервера
Код:
        [RfcServerFunction(Name = "ZDDK_DIADOC_TEST")]
        public void diadoc_login(RfcServerContext context, IRfcFunction function)
        {
            String i_login = function.GetValue("I_LOGIN").ToString();
            String i_password = function.GetValue("I_PASSWORD").ToString();

            IRfcTable tab = function.GetTable("ET_ORGS").Metadata.CreateTable();
            IRfcStructure stru = tab.Metadata.LineType.CreateStructure();
            stru.SetValue("TDFORMAT", "11");
            stru.SetValue("TDLINE", "111111111");
            tab.Append(stru);

            function.SetValue("E_ORGS", "E_ORGS");
            function.SetValue("E_TOKEN", "E_TOKEN");
            function.SetValue("ET_ORGS", tab);
        }

при вызове RFC-функции, получаю ошибку "Индекс находился вне границ массива.".
как только убираю строчку
Код:
            function.SetValue("ET_ORGS", tab);

RFC-функция отрабатывает, но, естественно, не возвращается таблица. только строковые параметры E_ORGS и E_TOKEN.
что я тут не так делаю?


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
 Заголовок сообщения: Re: sap .NET connector
СообщениеДобавлено: Ср, мар 30 2016, 16:01 
Специалист
Специалист

Зарегистрирован:
Вс, янв 11 2009, 12:05
Сообщения: 138
Пол: Мужской
_garycor_ писал(а):
Добрый день, коллеги!
к чему пришел.
как писал AFH, действительно, нужно прописывать хард-кодом репозитарий на стороне сервера.
для этого как раз и создан был класс RepositoryFunctionParamameter.
я от него избавился.
формирую репозитарий руками. делаю так.
Код:
    public class CustomRepository
    {
        public static RfcCustomRepository create()
        {
            RfcCustomRepository repository = new RfcCustomRepository();
            foreach (MethodInfo info in typeof(Handler).GetMethods())
            {
                MethodBase methodFromHandle = MethodBase.GetMethodFromHandle(info.MethodHandle);
                RfcServerFunctionAttribute customAttribute = (RfcServerFunctionAttribute) methodFromHandle.GetCustomAttribute(typeof(RfcServerFunctionAttribute));
                if (customAttribute != null)
                {
                    RfcFunctionMetadata fmd = new RfcFunctionMetadata(customAttribute.Name);
                    switch (fmd.Name)
                    {
                        case "ZDDK_DIADOC_TEST":
                            fmd.AddParameter(new RfcParameterMetadata("I_LOGIN", RfcDataType.STRING, RfcDirection.IMPORT, false));
                            fmd.AddParameter(new RfcParameterMetadata("I_PASSWORD", RfcDataType.STRING, RfcDirection.IMPORT, false));
                            fmd.AddParameter(new RfcParameterMetadata("E_TOKEN", RfcDataType.STRING, RfcDirection.EXPORT, false));
                            fmd.AddParameter(new RfcParameterMetadata("E_ORGS", RfcDataType.STRING, RfcDirection.EXPORT, false));
                           
                            RfcStructureMetadata stru = new RfcStructureMetadata("TLINE");
                            stru.AddField(new RfcFieldMetadata("TDFORMAT", RfcDataType.CHAR, 2, 0, 0, 0));
                            stru.AddField(new RfcFieldMetadata("TDLINE", RfcDataType.CHAR, 132, 0, 0, 0));
                            RfcTableMetadata t = new RfcTableMetadata("ET_ORGS", stru);
                            fmd.AddParameter(new RfcParameterMetadata("ET_ORGS", t, RfcDirection.TABLES, false));
                           
                            break;
                    }
                    repository.AddFunctionMetadata(fmd);
                }
            }
            return repository;
        }
    }

как видно я тут пытаюсь добавить таблицу.

сама функция сервера
Код:
        [RfcServerFunction(Name = "ZDDK_DIADOC_TEST")]
        public void diadoc_login(RfcServerContext context, IRfcFunction function)
        {
            String i_login = function.GetValue("I_LOGIN").ToString();
            String i_password = function.GetValue("I_PASSWORD").ToString();

            IRfcTable tab = function.GetTable("ET_ORGS").Metadata.CreateTable();
            IRfcStructure stru = tab.Metadata.LineType.CreateStructure();
            stru.SetValue("TDFORMAT", "11");
            stru.SetValue("TDLINE", "111111111");
            tab.Append(stru);

            function.SetValue("E_ORGS", "E_ORGS");
            function.SetValue("E_TOKEN", "E_TOKEN");
            function.SetValue("ET_ORGS", tab);
        }

при вызове RFC-функции, получаю ошибку "Индекс находился вне границ массива.".
как только убираю строчку
Код:
            function.SetValue("ET_ORGS", tab);

RFC-функция отрабатывает, но, естественно, не возвращается таблица. только строковые параметры E_ORGS и E_TOKEN.
что я тут не так делаю?


еще попробовал вот так
Код:
        [RfcServerFunction(Name = "ZDDK_DIADOC_TEST")]
        public void diadoc_login(RfcServerContext context, IRfcFunction function)
        {
            String i_login = function.GetValue("I_LOGIN").ToString();
            String i_password = function.GetValue("I_PASSWORD").ToString();

            IRfcTable tab = function.GetTable("ET_ORGS");

            FileStream fs = new FileStream("c:\\1\\1.txt", FileMode.Append);
            StreamWriter sw = new StreamWriter(fs);
           
            sw.WriteLine("---------------------------------------");
            tab.Append();
            tab.SetValue("TDLINE", "dsfsdfsdf");
            sw.WriteLine("GetTable_Append_" + tab.CurrentRow.ToString());
            sw.WriteLine("GetTable_RowCount_" + tab.RowCount.ToString());
            sw.WriteLine("GetTable_FieldCount" + tab.Metadata.LineType.FieldCount.ToString());           

            sw.Close(); fs.Close();
        }

вызываю RFC получаю дамп с той же ошибкой. хотя смотрю сформированный файлик и в нем вижу
Код:
---------------------------------------
GetTable_Append_STRUCTURE TLINE { FIELD TDFORMAT= FIELD TDLINE=dsfsdfsdf }
GetTable_RowCount_1
GetTable_FieldCount2


Принять этот ответ
Вернуться к началу
 Профиль Отправить email  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 39 ]  На страницу 1, 2, 3  След.

Часовой пояс: UTC + 4 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: Bimit, BingBot, RoustR и гости: 24


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB