Нюансы разработки веб сервисов для 1С на C# (.NET)

Я уже как-то писал о муках разработки web service (веб сервисов) на C# (.NET) для . Продолжаем разбираться с проблемами.

При разработке веб сервиса на C# под MS Visual Studio для 1С 8.2 столкнулись с невразумительной ошибкой. В качестве сервера — Microsoft-IIS/8.5. Поиск решения занял немало времени. 🙁 Но обо всем по порядку.

Название вызываемого метода веб сервиса — BarcodeFontIsInstalled. В качестве единственного аргумента передается строка.  Ошибка выглядит так:

{Форма.Форма.Форма(22)}: Ошибка при вызове метода контекста (BarcodeFontIsInstalled)
НоваяСтрока = Прокси.BarcodeFontIsInstalled(WSПараметр);
по причине:
Ошибка вызова операции сервиса: {http://tempuri.org/}:BarcodeWebService:BarcodeFontIsInstalled()
по причине:
Неизвестная ошибка. Ошибка разбора 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
{
    [WebService(Namespace = "http://tempuri.org/")]
    [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);
        }
    }
}

1C_web_service

Замечу, что вызов проходил через 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.2
Host: server
Accept: */*
Connection: Keep-Alive
Content-Type: text/xml; charset=utf-8
Content-Length: 427
 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header/>
    <soap:Body> <m:BarcodeFontIsInstalled xmlns:m="http://tempuri.org/">
    <m:fontName xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:type="m:BarcodeFontIsInstalled">
        <m:fontName>Code 128</m:fontName>
    </m:fontName>
</m:BarcodeFontIsInstalled></soap:Body>
</soap:Envelope>

Бросается в глаза странный кусок XML:

<m:fontName xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:type="m:BarcodeFontIsInstalled">
        <m:fontName>Code 128</m:fontName>
    </m:fontName>

Зачем 1С сгенерировал для такого простого аргумента такую вложенную иерархию fontName не понятно. Ответ веб сервиса (MS IIS) на такую конструкцию:

HTTP/1.1 400 Bad Request
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 14 Oct 2015 10:19:14 GMT
Content-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-8
Host: server
Content-Length: 352
Expect: 100-continue
Proxy-Connection: Keep-Alive
 
<?xml version="1.0" encoding="utf-8"?>
    <soap:Body>
        <BarcodeFontIsInstalled xmlns="http://tempuri.org/">
            <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.2
Host: www.cbr.ru
Accept: */*
Connection: Keep-Alive
Content-Type: text/xml; charset=utf-8
Content-Length: 337
 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header/>
    <soap:Body> <GetCursOnDate xmlns="http://web.cbr.ru/"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <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.2
Host: server
Accept: */*
Connection: Keep-Alive
Content-Type: text/xml; charset=utf-8
Content-Length: 355
 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header/>
    <soap:Body> <m:BarcodeFontIsInstalled xmlns:m="http://tempuri.org/">
    <m:fontName xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Code 128</m:fontName>
</m:BarcodeFontIsInstalled></soap:Body>
</soap:Envelope>

При таком вызове web service (веб сервис) возвращает корректное значение. Ошибка исчезла. В качестве аргумента в метод веб сервиса из 1С передавали бинарные данные (фотографии), массивы, ну и простые типы, вроде даты, строки и пр.

Полезные ссылки

  • Fiddler — перехват http траффика для анализа обмена данными
  • WireShark — мощный сниффер для перехвата и анализа различных протоколов переадчи данных.
Spread the love
Запись опубликована в рубрике IT рецепты с метками , , , , , . Добавьте в закладки постоянную ссылку.

Добавить комментарий

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