.Net в 1С. Асинхронные HTTP запросы, отправка Post нескольких файлов multipart/form-data, сжатие трафика с использованием gzip, deflate, удобный парсинг сайтов и т.д.

Очень часто нужно при работе с HTTP сервисами или сайтами использовать Асинхронные HTTP запросы, отправку на сервер нескольких файлов, использование сжатия трафика.  Эта статья про то, как этого легко добиться.

Это продолжение статей

Использование классов .Net в 1С для новичков

Использование сборок .NET в 1С 7.x b 8.x. Создание внешних Компонент

1C Messenger для отправки сообщений, файлов и обмена данными между пользователями 1С, вэб страницы, мобильными приложениями а ля Skype, WhatsApp

.NET(C#) для 1С. Динамическая компиляция класса обертки для использования .Net событий в 1С через ДобавитьОбработчик или ОбработкаВнешнегоСобытия

 

Продолжение статьи лежит здесь .Net в 1С. На примере использования HTTPClient,AngleSharp.Удобный парсинг сайтов с помощью библиотеки AngleSharp в том числе с авторизацией аля JQuery с использованием CSS селекторов. Динамическая компиляция

Это статья будет полезна не только 7-кам, но и 8-кам. Да, многое умеет HTTPСоединение и HTTPзапрос. Но многого нет.

Например, нет асинхронных запросов, сжатия трафика, отправки составного содержимого и т.д.

В том числе часто можно найти примеры на C# и иногда быстрее их адаптировать с использованием в 1С HTTPClient.

Про HTTPClient можно почитать здесь

https://msdn.microsoft.com/ru-ru/library/windows/apps/xaml/dn440594.aspx

https://msdn.microsoft.com/ru-ru/library/system.net.http.httpclient(v=vs.118).aspx

Итак, начнем.

Клиент=Врап.СоздатьОбъект(HttpClient);
ДанныеРесурса=Клиент.GetStringAsync("https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx").Result;

Сообщить(Врап.ВСтроку(ДанныеРесурса));

Все очень просто. Но это умеет и HTTPСоединение.

Для начала объявим используемые типы при открытии.

врап=новый COMОбъект("NetObjectToIDispatch45");
HttpClient=Врап.ПолучитьТипИзСборки("System.Net.Http.HttpClient","System.Net.Http.dll");
HttpClientHandler = врап.ПолучитьТип("System.Net.Http.HttpClientHandler");

// Контенты для Post

MultipartFormDataContent=Врап.ПолучитьТип("System.Net.Http.MultipartFormDataContent");
StreamContent  =Врап.ПолучитьТип("System.Net.Http.StreamContent");
StringContent  =Врап.ПолучитьТип("System.Net.Http.StringContent");
ByteArrayContent=Врап.ПолучитьТип("System.Net.Http.ByteArrayContent");
FormUrlEncodedContent =Врап.ПолучитьТип("System.Net.Http.FormUrlEncodedContent");

DecompressionMethods= Врап.ПолучитьТип("System.Net.DecompressionMethods");

ServicePointManager=врап.ПолучитьТип("System.Net.ServicePointManager");
Dictionary=Врап.ПолучитьТип("System.Collections.Generic.Dictionary`2[System.String,System.String]");
StringBuilder=Врап.ПолучитьТип("System.Text.StringBuilder");
String=Врап.ПолучитьТип("System.String");
HttpUtility=Врап.ПолучитьТипИзСборки("System.Web.HttpUtility","System.Web.dll");


// Сборку AngleSharp.dll поместить в каталог программы
//Для использования Scripting Api
КатаогПрограммы=Врап.ПолучитьТип("System.AppDomain").CurrentDomain.BaseDirectory;
ИмяСборкиAngleSharp=Врап.ПолучитьТип("System.IO.Path").Combine(КатаогПрограммы,"AngleSharp.dll");
AngleSharp_Configuration=Врап.ПолучитьТипИзСборки("AngleSharp.Configuration",ИмяСборкиAngleSharp);

IO_File =Врап.ПолучитьТип("System.IO.File");
Encoding=Врап.ПолучитьТип("System.Text.Encoding");

// В релизе нужно отлавливать ошибки
// врап.ВыводитьСообщениеОбОшибке=ложь;

По мере использования я буду пояснять, для чего тот или иной тип.

Начнем с асинхронного программирования. Часто нужно использовать долгие запросы, или нужно одновременно использовать несколько запросов. К сожалению, 1С этого не позволяет. Поэтому в свой разработке я постарался исправить этот недочет.

Выполнитель=Врап.ПолучитьАсинхронныйВыполнитель();
ДобавитьОбработчик Выполнитель.ПриОкончанииВыполненияЗадачи, ПриОкончанииВыполнения;

//Обработчик события выглядит так
Процедура ПриОкончанииВыполнения(Задача,ДанныеКЗадаче)

// Обязательно нужно отлавливать ошибку в 1С
// Иначе она передается в .Net где обрабатывается там
Попытка
Так как задача может завершиться с ошибкой
Мы должны проверить, и если ошибка нужно предпринять какие то действия
Если (Задача.IsFaulted) Тогда  // Ошибка выполнения

Сообщить("Ошибка "+Врап.ВСтроку(Задача.Exception));
Сообщить("Данные к задаче "+Врап.ВСтроку(ДанныеКЗадаче));

иначе
Сообщить("=====Выполнена задача ====");
Сообщить("Данные к задаче "+Врап.ВСтроку(ДанныеКЗадаче));
Сообщить(Врап.ВСтроку(Задача.Result));


КонецЕсли;

Исключение
Сообщить("Ошибка в процедуре");
Сообщить(ОписаниеОшибки());
КонецПопытки

КонецПроцедуры

Вызываем задачу так

    Клиент=Врап.СоздатьОбъект(HttpClient);
Задача=Клиент.GetStringAsync("https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx");
Выполнитель.Выполнить(задача,ТекущаяДата());

 

 Для тестов я сделал тестовый Вэб сервис на ASP.Net

 

Для теста  множества асинхронных запросов сделал функцию

       [HttpGet]
public async Task<string> GetIdAsync(string id)
{
await Task.Delay(1000);
return id;


}

Имитируем задержку в 1 секунду. Например, нам нужно выполнить 100 запросов.

Процедура TestAsyncНажатие(Элемент)
// Вставить содержимое обработчика.

handler = врап.СоздатьОбъект(HttpClientHandler);

Сообщить(ServicePointManager.DefaultConnectionLimit);
ServicePointManager.DefaultConnectionLimit=100;


Клиент = Врап.СоздатьОбъект(HttpClient,handler);
// Использование заголовков не обязательно
// В данном случае это пример их использования
Клиент.DefaultRequestHeaders.Connection.Add("keep-alive");
CacheControl=Врап.СоздатьОбъект("System.Net.Http.Headers.CacheControlHeaderValue");
CacheControl.MaxAge = Врап.ПолучитьТип("System.TimeSpan").Zero;
Клиент.DefaultRequestHeaders.CacheControl = CacheControl;
Клиент.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,*/*");
Клиент.DefaultRequestHeaders.Add("Accept-Language", "ru-Ru");
Клиент.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");

uriSources =ПолучитьСтрокуЗапроса("http://localhost.fiddler:40320/api/values/GetIdAsync/");

Клиент.BaseAddress =Врап.СоздатьОбъект("System.Uri",uriSources);

Выполнитель=Врап.ПолучитьАсинхронныйВыполнитель();
ДобавитьОбработчик Выполнитель.ПриОкончанииВыполненияЗадачи, ПриОкончанииВыполнения;

ВыполненоЗадач=0;
МассивОтветов=новый массив;

stopWatch = Врап.СоздатьОбъект("System.Diagnostics.Stopwatch");
stopWatch.Start();
Для сч=1 По 100 Цикл

Задача=Клиент.GetStringAsync(СокрЛП(сч));

Выполнитель.Выполнить(задача,ТекущаяДата());


КонецЦикла;

КонецПроцедуры

Процедура ВывестиВремя(stopWatch,толькоВремя=ложь)
ts = stopWatch.Elapsed;
String=Врап.ПолучитьТип("System.String");
// Format and display the TimeSpan value.
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10,0);
Сообщить(elapsedTime);
Если толькоВремя Тогда
возврат
КонецЕсли;
Для каждого стр  Из МассивОтветов Цикл

сообщить(стр);

КонецЦикла;
КонецПроцедуры

Процедура ПриОкончанииВыполнения(Задача,ДанныеКЗадаче)

// Обязательно нужно отлавливать ошибку в 1С
// Иначе она передается в .Net где обрабатывается там
ВыполненоЗадач=ВыполненоЗадач+1;



Попытка

Если (Задача.IsFaulted) Тогда  // Ошибка выполнения

Сообщить("Ошибка "+Врап.ВСтроку(Задача.Exception));
Сообщить("Данные к задаче "+Врап.ВСтроку(ДанныеКЗадаче));

иначе
//Сообщить("=====Выполнена задача ====");
//Сообщить("Данные к задаче "+Врап.ВСтроку(ДанныеКЗадаче));
//Сообщить(Врап.ВСтроку(Задача.Result));
МассивОтветов.Добавить(Задача.Result);
                          Если ВыполненоЗадач=100 Тогда

ВывестиВремя(stopWatch)

КонецЕсли; 
  КонецЕсли;

Исключение
Сообщить("Ошибка в процедуре");
Сообщить(ОписаниеОшибки());
КонецПопытки

КонецПроцедуры

Если бы при синхронном выполнении нам понадобилось бы минимум 100 сек, то при асинхронном уходит порядка 1,5 сек.

Отдельно нужно отметить использование ServicePointManager. Более подробно можно посмотреть здесь

Почему одновременно происходит только два соединения с сайтом

Тест сетевой нагрузки


Есть еще вариант дождаться всех запросов

 

лист=Врап.СоздатьОбъект("System.Collections.Generic.List`1[System.Threading.Tasks.Task]");
Для сч=1 по 10 Цикл
Задача=Клиент.GetStringAsync(СокрЛП(сч));
лист.Add(задача);
КонецЦикла;

Task=Врап.ПолучитьТип("System.Threading.Tasks.Task");
      массив=лист.ToArray(); 
      Task.WaitAll(массив);
      Для каждого задача из лист Цикл
Сообщить(задача.Result);
КонецЦикла


Но здесь нужно учитывать, что например в выполнитель испольует контекс синхронизации, что может приводить к блокировкам  https://habrahabr.ru/post/257221/

Проверил асинхронные методы HttpClient не зависят от контекста синхронизации.


Перед тем как перейти к использованию multipart/form-data, покажу примеры отправки Post запросов.

Процедура ЗакрытьРесурс(Ресурс)
Врап.ПолучитьИнтерфейс(Ресурс,"IDisposable").Dispose();
КонецПроцедуры

Функция ПолучитьСтрокуОтвета(стрОриг)

Стр=СтрЗаменить(стрОриг,"""","");
возврат СтрЗаменить(стр,"
",Символы.ПС);


КонецФункции // ПолучитьСтрокуОтвета()

Функция ПолучитьСтрокуЗапроса(uriSources)
Если не ФлИспользоватьФиддлер Тогда
возврат СтрЗаменить(uriSources,".fiddler","");
КонецЕсли;

Возврат uriSources
КонецФункции
Функция ВыполнитьПост(uriSources,Клиент)

//  Контент=Врап.СоздатьОбъект("System.Net.Http.StringContent","Тестовая Строка",Encoding.UTF8,"text/plain");
Контент=Врап.СоздатьОбъект("System.Net.Http.StringContent","Тестовая Строка "+uriSources);
резулт=Клиент.PostAsync(uriSources,Контент).Result;


Сообщить("===================================");

Сообщить(резулт.IsSuccessStatusCode);
Сообщить(Врап.Встроку(резулт.StatusCode));

стр=резулт.Content.ReadAsStringAsync().Result;
Сообщить(ПолучитьСтрокуОтвета(стр));


КонецФункции // ВыполнитьПост()

Процедура TestGetНажатие(Элемент)
// Вставить содержимое обработчика.
HttpClient=Врап.ПолучитьТипИзСборки("System.Net.Http.HttpClient","System.Net.Http.dll");

HttpUtility=Врап.ПолучитьТипИзСборки("System.Web.HttpUtility","System.Web.dll");


Попытка

uriSources =ПолучитьСтрокуЗапроса("http://localhost.fiddler:40320/api/values/");
handler = врап.СоздатьОбъект(HttpClientHandler);

cookieContainer = Врап.СоздатьОбъект("System.Net.CookieContainer");

handler.AutomaticDecompression=Врап.OR(DecompressionMethods.GZip,DecompressionMethods.Deflate);
// Используем cookieContainer для задания куков со стороны клиента. Куки со стороны сервера автоматически сохраняются.
cookieContainer.Add(Врап.СоздатьОбъект("System.Net.Cookie","TestCookie", "TruLyaLya", "/", "localhost"));
handler.CookieContainer=cookieContainer;
handler.UseCookies=истина;

Клиент = Врап.СоздатьОбъект(HttpClient,handler);
DefaultRequestHeaders=Клиент.DefaultRequestHeaders;
DefaultRequestHeaders.Connection.Add("keep-alive");
CacheControl=Врап.СоздатьОбъект("System.Net.Http.Headers.CacheControlHeaderValue");
CacheControl.MaxAge = Врап.ПолучитьТип("System.TimeSpan").Zero;
DefaultRequestHeaders.CacheControl = CacheControl;

DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,*/*");
DefaultRequestHeaders.Add("Accept-Language", "ru-Ru");
DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");


//Использум BaseAddress, что бы в дальнейшем задавать адрес только ресурса
 Клиент.BaseAddress =Врап.СоздатьОбъект("System.Uri",uriSources);
Стр=Клиент.GetStringAsync("GetHeaders").Result;
// В данном случае запрос отправится
//
Сообщить(ПолучитьСтрокуОтвета(стр));

ВыполнитьПост("SendStr",Клиент);
ВыполнитьПост("SendStr2",Клиент);

ЗакрытьРесурс(Клиент);

Исключение
Сообщить(ОписаниеОшибки());

Если Врап.ПоследняяОшибка<>Неопределено Тогда

ПоказатьПредупреждение(,Врап.ПоследняяОшибка.Message);


КонецЕсли;
Врап.ВывестиПоследнююОшибку();

КонецПопытки



КонецПроцедуры

Процедура ПослатьStreamНажатие(Элемент)
// Вставить содержимое обработчика.
uriSources =ПолучитьСтрокуЗапроса("http://localhost.fiddler:40320/api/values/SendStream");



Клиент=Врап.СоздатьОбъект(HttpClient);

// Создаем поток в памяти и записываем в него данные строки в кодировке UTF8
        поток=врап.СоздатьОбъект(MemoryStream,Encoding.UTF8.GetBytes("Отсылаемая строка"));



Контент=Врап.СоздатьОбъект(StreamContent,поток);
резулт=Клиент.PostAsync(uriSources,Контент).Result;


Сообщить("===================================");

Сообщить(резулт.IsSuccessStatusCode);
Сообщить(Врап.Встроку(резулт.StatusCode));

стр=резулт.Content.ReadAsStringAsync().Result;
Сообщить(ПолучитьСтрокуОтвета(стр));

ЗакрытьРесурс(Клиент);

КонецПроцедуры

Иногда нужно не только отправить но и получить куки


 

 // Вставить содержимое обработчика.
cookieContainer = Врап.СоздатьОбъект("System.Net.CookieContainer");

handler=Врап.СоздатьОбъект(HttpClientHandler);
handler.AutomaticDecompression=Врап.OR(DecompressionMethods.GZip,DecompressionMethods.Deflate) ;
handler.CookieContainer=cookieContainer;



Клиент = Врап.СоздатьОбъект(HttpClient,handler);
uriSources ="http://www.telerik.com";
Ури=Врап.СоздатьОбъект("System.Uri",uriSources);
Клиент.BaseAddress =Ури;

Стр=Клиент.GetStringAsync("/UpdateCheck.aspx?isBeta=False").Result;

// Пострим все куки присоединенные по этому аресу
Куки = cookieContainer.GetCookies(Ури);
Для  каждого кук  из Куки Цикл
Сообщить(кук.Name + ": " + кук.Value);
КонецЦикла;

// Можем получить конкретное значение
кук=Куки.get_Item("sid");
Сообщить(кук.Name + ": " + кук.Value);


Отправляемый контекст можно задавать пятью способами

  • MultipartFormDataContent,
  • StreamContent,
  • StringContent,
  • ByteArrayContent,
  • FormUrlEncodedContent

Выбирайте тот, который удобен. FormUrlEncodedContent это аналог отправики данных Form при Post Submit.

Теперь перейдем к отправке multipart/form-data. 

Процедура Multi_PartНажатие(Элемент)
// Вставить содержимое обработчика.
uriSources =ПолучитьСтрокуЗапроса("http://localhost.fiddler:40320");
//uriSources ="http://localhost:40320";
HttpClient=Врап.ПолучитьТипИзСборки("System.Net.Http.HttpClient","System.Net.Http.dll");
MultipartFormDataContent=Врап.ПолучитьТип("System.Net.Http.MultipartFormDataContent");


Клиент = Врап.СоздатьОбъект(HttpClient);
Контент = Врап.СоздатьОбъект(MultipartFormDataContent);
Клиент.BaseAddress =Врап.СоздатьОбъект("System.Uri",uriSources);


// Вариант отправки Ключ-Значение
Значения = Врап.СоздатьОбъект("System.Collections.Generic.Dictionary`2[System.String,System.String]");

Значения.Add("Name", "name");
Значения.Add("id", "id");


//      content.Add(new FormUrlEncodedContent(values));
Для каждого КлючЗначение из Значения Цикл

Контент.Add(Врап.СоздатьОбъект("System.Net.Http.StringContent",КлючЗначение.Value),КлючЗначение.Key);
КонецЦикла;


// Вариант отправки двоичных данных из массива
Encoding=Врап.ПолучитьТип("System.Text.Encoding");

СтроковыйКонтент =Врап.СоздатьОбъект("System.Net.Http.ByteArrayContent",Encoding.UTF8.GetBytes("Тестовая строка"));

ContentDisposition=Врап.СоздатьОбъект("System.Net.Http.Headers.ContentDispositionHeaderValue","form-data");
ContentDisposition.FileName ="ПростоСтрока";
ContentDisposition.Name ="attachment";


СтроковыйКонтент.Headers.ContentDisposition = ContentDisposition;
СтроковыйКонтент.Headers.ContentType = Врап.СоздатьОбъект("System.Net.Http.Headers.MediaTypeHeaderValue","text/plain");
Контент.Add(СтроковыйКонтент);


// Вариант отправки двоичных данных из файла
ИмяФайла ="C:/ТестXML";

ПотокФайла =Врап.ПолучитьТип("System.IO.File").OpenRead(ИмяФайла);
ФайловыйКонтент =Врап.СоздатьОбъект("System.Net.Http.StreamContent",ПотокФайла);
ContentDisposition=Врап.СоздатьОбъект("System.Net.Http.Headers.ContentDispositionHeaderValue","form-data");
ContentDisposition.FileName = Врап.ПолучитьТип("System.IO.Path").GetFileName(ИмяФайла);

ФайловыйКонтент.Headers.ContentDisposition = ContentDisposition;
ФайловыйКонтент.Headers.ContentType = Врап.СоздатьОбъект("System.Net.Http.Headers.MediaTypeHeaderValue","application/octet-stream");
Контент.Add(ФайловыйКонтент);

// Вариант отправки двоичных данных из файла но более краткий
ПотокФайла2 =Врап.ПолучитьТип("System.IO.File").OpenRead(ИмяФайла);
ФайловыйКонтент2 =Врап.СоздатьОбъект("System.Net.Http.StreamContent",ПотокФайла2);
Контент.Add(ФайловыйКонтент2,"attachment","TestXml");

requestUri = "api/values/SendFiles";

Результат = Клиент.PostAsync(requestUri, Контент).Result;
стр = Результат.Content.ReadAsStringAsync().Result;

Сообщить(стр);
ЗакрытьРесурс(Клиент);
ЗакрытьРесурс(Контент);
ЗакрытьРесурс(ПотокФайла);
// Вот как выглядит отправляемый запрос
//POST http://localhost:40320/api/values/SendFiles HTTP/1.1
//Content-Type: multipart/form-data; boundary="9f2d525a-7383-46ab-8fc7-419d73486c02"
//Host: localhost:40320
//Content-Length: 811
//Expect: 100-continue
//Connection: Keep-Alive

//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Type: text/plain; charset=utf-8
//Content-Disposition: form-data; name=Name

//name
//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Type: text/plain; charset=utf-8
//Content-Disposition: form-data; name=id

//id
//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Disposition: form-data; filename="=?utf-8?B?0J/RgNC+0YHRgtC+0KHRgtGA0L7QutCw?="; name=attachment
//Content-Type: text/plain

//Тестовая строка
//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Disposition: form-data; filename="=?utf-8?B?0KLQtdGB0YJYTUw=?="
//Content-Type: application/octet-stream

//12345
//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Disposition: form-data; name=attachment; filename=TestXml; filename*=utf-8''TestXml

//12345
//--9f2d525a-7383-46ab-8fc7-419d73486c02--

КонецПроцедуры


Запрос достаточно просто отправить. Вот как это приходится делать на чистом 1С Передача файлов и данных на веб-сервер средствами 1С:Предприятие 8.X методом POST

multipart/form-data

Стоит отметить использование 

handler.AutomaticDecompression=Врап.OR(DecompressionMethods.GZip,DecompressionMethods.Deflate);
который позволяет хорошо сжимать HTML странцы. Например
uriSources ="https://msdn.microsoft.com/en-us/library/system.net.decompressionmethods(v=vs.110).aspx";

handler = врап.СоздатьОбъект(HttpClientHandler);
handler.AutomaticDecompression=Врап.OR(DecompressionMethods.GZip,DecompressionMethods.Deflate) ;

Клиент=Врап.СоздатьОбъект(HttpClient,handler);
Стр=Клиент.GetStringAsync(uriSources).Result;
 

Сжимает трафик в 5 раз.

Content-Length: 17129 упакованной, против 87 624 неупакованной

К сожалению, объем получился большим. Поэтому  продолжение использования HTTPClient и парсинг сайтов выделю в отдельную статью. Так будет проще разбираться.

22 Comments

  1. Жолтокнижниг

    (0) Я не нашел, какие требования к Framework?

    Reply
  2. Serginio

    (1) 4.6.1

    Reply
  3. bonv

    (0) Перед публикацией могли хотя бы отформатировать код (Alt+Shift+F)

    Reply
  4. Serginio

    (3) bonv,

    Форматировал. Только вот вставка в редактор и редактирование на этом сайте не совсем тривиальная задача

    Reply
  5. Гость

    Спасибо за труды, о великий!

    Reply
  6. Serginio

    Спасибо за оценку трудов моих скромных.

    Reply
  7. Serginio

    Добавлю удобную объектную надстройку к Retst Api Refit: The automatic type-safe REST library for .NET Core, Xamarin and .NET

    Вкратце можно описать интерфейс

    public interface IGitHubApi
    {
    [Get(«/users/{user}»)]
    Task<User> GetUser(string user);
    }

    И использовать

    var gitHubApi = RestService.For<IGitHubApi>(«https://api.github.com»);
    
    var octocat = await gitHubApi.GetUser(«octocat»);
    Reply
  8. Arxxximed

    У меня не получилось провести тест асинхронных httpзапросов на сервере. Это работать будет только на клиенте?

    Reply
  9. Serginio

    Это работает только на клиенте, так как идет привязка к событиям, а на сервере нужно ждать когда событие придет

    Вся беда в том, что на сервере нельзя сделать

    ДобавитьОбработчик Выполнитель.ПриОкончанииВыполненияЗадачи, ПриОкончанииВыполнения

    И ОбработкаВнешнегоСобытия.

    Поэтому асинхронные только на клиенте.

    Reply
  10. Arxxximed

    Извините, возможно плохо искал. А как получить изображение через Стр=Клиент.GetStringAsync(«GetHeaders»).Result; как двоичные данные?

    Допустим во втроенном HTTPОтвет Если метод ПолучитьТелоКакДвоичныеДанные

    Или есть другой метод получения?

    Это в идеале,

    Ну или хотябы как записывать

    Reply
  11. Arxxximed

    Спасибо, методом проб и ошибок нашел одно из решений которое в вдругой ветке предоставили

    UTF8=Врап.ПолучитьТип(«System.Text.Encoding»).GetEncoding(1251);
    Данные=Клиент.GetByteArrayAsync(«http://oursite.ru/data/2016/08/14/1237073852/7427903.jpg»).Result;
    output = UTF8.GetString(Данные);
    двДанные  = ПолучитьДвоичныеДанныеИзСтроки(output,КодировкаТекста.ANSI,);
    двДанные.Записать(«B:ПробаУдалитьТестовоеИзображение.jpg»); ///Можно и записать если нужно
    Reply
  12. Arxxximed

    Если есть Другие более «правильные» варианты подскажите пожалуйста. Вообще не дотнет разработчик

    Reply
  13. Serginio

    Ну в Данные ты получаешь массив байтов.

    Просто

    File=Врап.ПолучитьТип(«System.IO.File»);

    File.WriteAllBytes(«B:ПробаУдалитьТестовоеИзображение.jpg»,Данные);

    Reply
  14. Arxxximed

    Сергей, спасибо за ответ. Только я имел ввиду Как из запроса получить двоичные данные как объект 1С , вот нашел такое решение. Можно конечно попробовать и по другому

    Reply
  15. Arxxximed

    Так же все таки интересуют вопрос ошибок. У меня сложилась ситуация, что когда запрос возвращает ошибку 404 возникает исключительная ситуация в .Net.

    Т.е. я не могу обработать task через wait() или waitall(). Не знаю как правильно решить данный момент. Пока сделал что жду в цикле возвращение True хотя бы одного из свойств;

    Задача.IsCompleted;

    Задача.IsCanceled;

    Задача.IsFaulted;

    Хотя это немного наверное не правильно…

    Reply
  16. Serginio

    (1) Ты можешь смотреть IsFaulted в ПриОкончанииВыполнения к которой подключаешься

    Выполнитель=Врап.ПолучитьАсинхронныйВыполнитель();
    ДобавитьОбработчик Выполнитель.ПриОкончанииВыполненияЗадачи, ПриОкончанииВыполнения;
    
    

    Процедура ПриОкончанииВыполнения(Задача,ДанныеКЗадаче)
    
    // Обязательно нужно отлавливать ошибку в 1С
    // Иначе она передается в .Net где обрабатывается там
    Попытка
    Так как задача может завершиться с ошибкой
    Мы должны проверить, и если ошибка нужно предпринять какие то действия
    Если (Задача.IsFaulted) Тогда  // Ошибка выполнения
    Reply
  17. Arxxximed

    Нет, я тут не пользуюсь Асинхронным выполнителем, посмотрел что для моей задачи это немного «Неудобно». я просто создаю массив заданий. Причем массив как объект 1С. И когда нужно прохожусь по этому массиву.

    Все равно процедура ПриОкончанииВыполнения начнет выполнятся только после завершения формирующей процедуры. Насколько я правильно понимаю

    Reply
  18. Serginio

    Ну можно по аналогии с https://habrahabr.ru/post/307360/

    Вызывать Task.WaitAny(массивЗадач);

    ПриОкончанииВыполнения будет вызываться после завершения Задачи.

     Клиент=Врап.СоздатьОбъект(HttpClient);
    Задача=Клиент.GetStringAsync(«https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx»);
    Выполнитель.Выполнить(задача,ТекущаяДата());
    
    // Вот после этого кода, после завершении Задача
    Reply
  19. Arxxximed

    Немного проверил работу асинхронного выполнителя. Немного не вижу в нем смысла.

    Дело в том, что если мы в Процедуре А() создаем выполнителю множество задач, то результат задач в процедуре-Обработчике мы сможем получить Только!!! После выполнения всей процедуры А. Кроме случаев Когда 1С сама не вызывает «асинхорнные» процедуры , например Вопрос().

    Т.е. По сути я могу получить результаты Работы объектов .NET в конце моей процедуры без вызова Асинхронного выполнителя, при этом объекты .NET Выполняют свою работу параллельно работе 1С, что и требует данная тема.

    Единственное что дает Выполнитель — это гарантированное выполнение задачи (task), но существенно ухудшает читаемость кода.

    Но на выполнение можно сделать проверку в коде 1С циклом как я писал выше

    функция ожидания выполнения

    По поводу WaitAny , не проверил, но думаю дело будет обстоять так же: Если задача из массива задач будет выполнена с ошибкой ( например возврват 404) , то будет вызвано исключение .Net , которое в 1С не отловишь

    Тема очень хороша, спасибо.

    Reply
  20. Serginio

    Ну а ты создавай в Процедуре А только задачи, на это уходит миллисекунды.

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

    Нет в данном случае возвращается Task и у него можно проверить IsFaulted

    Reply
  21. mar82

    Извиняюсь за вопрос, но на Win 10 x64 получаю стабильно ошибку «Неверное имя объекта» на первой строке Врап = Новый COMОбъект

    Нужно ли что-то особенное сделать для Win x64?

    Спасибо

    Reply
  22. Serginio

    Нужно скачать компоненту отсюда https://infostart.ru/public/238584/

    Или если нет денег отсюда

    https://ru.stackoverflow.com/questions/527763/Как-вызвать-метод-из-c-в-1С/527802#527802

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *