Я уже как-то писал о муках разработки web service (веб сервисов) на C# (.NET) для 1С. Продолжаем разбираться с проблемами.
При разработке веб сервиса на C# под MS Visual Studio для 1С 8.2 столкнулись с невразумительной ошибкой. В качестве сервера — Microsoft-IIS/8.5. Поиск решения занял немало времени. 🙁 Но обо всем по порядку.
Название вызываемого метода веб сервиса — BarcodeFontIsInstalled. В качестве единственного аргумента передается строка. Ошибка выглядит так:
{Форма.Форма.Форма(22)}: Ошибка при вызове метода контекста (BarcodeFontIsInstalled)НоваяСтрока = Прокси.BarcodeFontIsInstalled(WSПараметр);по причине:по причине:Неизвестная ошибка. Ошибка разбора XML: - [1,1]Фатальная ошибка: Extra content at the end of the documentпо причине:Ошибка разбора XML: - [1,1] |
Она ни о чем не говорит, поскольку 1С безбожно переврала то, что вернул IIS.
Обращение из 1С к web service (веб сервису)
Вызов метода из 1С производился как описано в статье. Код веб сервиса в C#:
using System.Web;using System.Web.Services;using System.Xml.Serialization;namespace BarcodeWebService{ [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] public class BarcodeWebService : System.Web.Services.WebService { [WebMethod] public bool BarcodeFontIsInstalled(string fontName) { return BarcodeUtils.IsFontInstalled(fontName); } }} |
Замечу, что вызов проходил через BarcodeWebServiceSoap — т.е. SOAP версии 1.1. BarcodeWebServiceSoap12 — соотвественно для работы через SOAP 1.2. 1C действительно меняет обращение к сервису, если вместо BarcodeWebServiceSoap указать BarcodeWebServiceSoap12, проверено опытным путем. 🙂
Вызов в 1С выглядел таким образом:
//Создаем прокси для обращения к внешнему веб-сервису,// передаем в функцию URI пространства имен, имя сервиса, имя порта.Прокси = WSСсылки.WSBarcodeService.СоздатьWSПрокси(http://tempuri.org/", "BarcodeWebService", "BarcodeWebServiceSoap"); //Получаем тип параметра, который передается в метод BarcodeFontIsInstalled.ТипWSПараметра = Прокси.ФабрикаXDTO.Пакеты.Получить(http://tempuri.org/").Получить("BarcodeFontIsInstalled");//Создаем параметр на основе типа и заполняем значение параметра fontName.WSПараметр = Прокси.ФабрикаXDTO.Создать(ТипWSПараметра);WSПараметр.fontName = "Code 128";//Вызываем метод веб-сервиса, записываем результат в переменную КурсыВалют.НоваяСтрока = Прокси.BarcodeFontIsInstalled(WSПараметр); |
Все делаем «по учебнику» но так не работает. 🙁
Отладка обращений 1С к web service (веб сервису)
Поскольку в 1С не понятно как отлаживать что-то в части работы с веб-сервисами, обращаемся за помощью к Fiddler, который покажет как-же 1С обращается к разработанному на C# web service:
Proxy-Authorization: NTLM TlRMTVNTUAABAAAAt7II4....==User-Agent: 1C+Enterprise/8.2Host: serverAccept: */*Connection: Keep-AliveContent-Type: text/xml; charset=utf-8Content-Length: 427 <soap:Header/> xsi:type="m:BarcodeFontIsInstalled"> <m:fontName>Code 128</m:fontName> </m:fontName></m:BarcodeFontIsInstalled></soap:Body></soap:Envelope> |
Бросается в глаза странный кусок XML:
xsi:type="m:BarcodeFontIsInstalled"> <m:fontName>Code 128</m:fontName> </m:fontName> |
Зачем 1С сгенерировал для такого простого аргумента такую вложенную иерархию fontName не понятно. Ответ веб сервиса (MS IIS) на такую конструкцию:
HTTP/1.1 400 Bad RequestCache-Control: privateContent-Type: text/xml; charset=utf-8Server: Microsoft-IIS/8.5X-AspNet-Version: 4.0.30319X-Powered-By: ASP.NETDate: Wed, 14 Oct 2015 10:19:14 GMTContent-Length: 0 |
Как видно по ответу, ошибка выдаваемая 1С рядом не лежала с тем, что на самом деле вернул IIS, а он вообще не вернул XML, сообщив, что запрос «кривой» (HTTP/1.1 400 Bad Request).
Чтобы узнать какой request должен быть, пишем пару строк на C#:
BarcodeWebService.BarcodeWebService svc = new BarcodeWebService.BarcodeWebService();checkBox1.Checked = svc.BarcodeFontIsInstalled("Code 128"); |
и запустив Fiddler видим какой простой и красивый request получается:
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 4.0.30319.34014)Content-Type: text/xml; charset=utf-8Host: serverContent-Length: 352Expect: 100-continueProxy-Connection: Keep-Alive<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap=http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd=http://www.w3.org/2001/XMLSchema"> <soap:Body> <fontName>Code 128</fontName> </BarcodeFontIsInstalled> </soap:Body></soap:Envelope> |
Расстраиваемся, поскольку ситуация выглядит тупиковой, но пытаемся найти решение.
Перехват обращений из 1С к web service (веб сервису) cbr.ru
Обратимся к исходной статье и посмотрим как выглядит request к web service (веб сервису) www.cbr.ru. Код 1С описан в статье, а request будет таким:
Proxy-Authorization: NTLM TlRMTVNTUAABAAAAt7II4gUA...User-Agent: 1C+Enterprise/8.2Host: www.cbr.ruAccept: */*Connection: Keep-AliveContent-Type: text/xml; charset=utf-8Content-Length: 337 <soap:Header/> <On_date>2015-10-14T14:40:53</On_date></GetCursOnDate></soap:Body></soap:Envelope> |
В данном случае все красиво, как при обращении из кода C#:
CBRWebService.DailyInfo info = new CBRWebService.DailyInfo();DataSet ds = info.GetCursOnDate(DateTime.Now); |
Разбираться в WSDL, который генерирует веб сервис «Центробанка» и разработанный мною на .NET — дело неблагодарное, тем более, что даже поняв ошибку в генерации 1С request к внешнему веб сервису, повлиять на это нельзя, нужно ждать обновления платформы. Чтобы проверить одну мысль я сделал простой метод в веб сервисе:
[WebMethod]public DateTime Checker(DateTime date){ return date;} |
У меня была мысль, что проблема связана с тем, что string аргумент может быть null, соответственно, в WSDL minOccurs=»0″, в отличие от DateTime (который передавался cbr.ru методу GetCursOnDate), для которого minOccurs=»1″ . Однако, даже для такого варианта 1С сформировал столь же «кривой» запрос, т.е. дело не в этом.
Решение
Поиск решения заняло немало времени, как обычно, оно оказалось очень простым. Спасибо моим 1С разработчикам с которыми мы вымучивали столь красивое и столь многострадальное решение. 🙂
Итак, фанфары, рабочий код на 1С при обращении к внешнему веб сервису (web service) написанному на C# (.NET) и работающему под IIS выглядит следующим образом:
//Создаем прокси для обращения к внешнему веб-сервису,// передаем в функцию URI пространства имен, имя сервиса, имя порта.Прокси = WSСсылки.WSBarcodeService.СоздатьWSПрокси(http://tempuri.org/", "BarcodeWebService", "BarcodeWebServiceSoap");//Вызываем метод веб-сервиса, записываем результат в переменную КурсыВалют.Результат = Прокси.BarcodeFontIsInstalled("Code 128"); |
И это всё! 🙂 Предельно кратко и очень похоже на обращение к web service в C#. В этом случае перехваченный Fiddler-ом запрос 1С к веб сервису выглядит следующим образом:
Proxy-Authorization: NTLM TlRMTVNTUAABAAAAt7II4gUABQ...User-Agent: 1C+Enterprise/8.2Host: serverAccept: */*Connection: Keep-AliveContent-Type: text/xml; charset=utf-8Content-Length: 355 <soap:Header/></m:BarcodeFontIsInstalled></soap:Body></soap:Envelope> |
При таком вызове web service (веб сервис) возвращает корректное значение. Ошибка исчезла. В качестве аргумента в метод веб сервиса из 1С передавали бинарные данные (фотографии), массивы, ну и простые типы, вроде даты, строки и пр.
