Тестируя различные API с помощь SoapUI, мы решили, что хотим иметь гибкие и настраиваемые под нас тесты. Для этого мы решили тестировать API не через SoapUI, а писать автоматизированные тесты на C#. Теперь рассмотрим, как отправлять SOAP-запросы и получать ответы в C# и при этом используя минимальное количество строк кода и без подключений «WSDL» к проекту. Про REST API и C# я, возможно, напишу статью позже.
В данной статье будет указан несуществующий API, поэтому не стоит пытаться его проверять.
Допустим у нас есть сервис, у которого есть API, и он доступен по адресу:
https://victorz.ru/soapapi/Transport
У данного сервиса есть ряд методов и один из них «GetInfo», который позволяет запрашивать информацию по транспортному средству передавая идентификатор транспортного средства.
Создаём в C# новый проект. Я создал проект с типом Windows Form. В проект подключим:
using System; using System.IO; using System.Net; using System.Xml; using System.Windows.Forms;
Создадим метод C#, который будет запрашивать информацию и возвращать ответ сервиса:
/// <summary> Метод отправки запроса к SOAP сервису и получения от него ответа </summary> /// <param name="_url">URL SOAP API-сервиса</param> /// <param name="_method">Метод, который вызывается на API сервисе</param> /// <param name="_soapEnvelope">SOAP-конверт (запрос), который будет отправлен к API</param> /// <returns>Метод возвращает ответ SOAP сервиса в виде XML</returns> private string GetResponseSoap(string _url, string _method, string _soapEnvelope) { _url = _url.Trim('/').Trim('\\'); // в конце адреса удалить слэш, если он имеется WebRequest _request = HttpWebRequest.Create(_url); //все эти настройки можно взять со страницы описания веб-сервиса _request.Method = "POST"; _request.ContentType = "text/xml; charset=utf-8"; _request.ContentLength = _soapEnvelope.Length; _request.Headers.Add("SOAPAction", _url + @"/" + _method); // пишем тело StreamWriter _streamWriter = new StreamWriter(_request.GetRequestStream()); _streamWriter.Write(_soapEnvelope); _streamWriter.Close(); // читаем тело WebResponse _response = _request.GetResponse(); StreamReader _streamReader = new StreamReader(_response.GetResponseStream()); string _result = _streamReader.ReadToEnd(); // переменная в которую пишется результат (ответ) сервиса return _result; }
Описывать подробно метод не будем, так как в комментариях достаточно информации.
Далее нам надо вызвать с помощью данного методы сервис и получить от него ответ. К примеру, при нажатии на кнопку «button1» мы выведем ответ сервиса в текстовом поле «textBox1»:
private void button1_Click(object sender, EventArgs e) { textBox1.Text = ""; // очищаем текстовое поле string _url = @"https://victorz.ru/api/Transport"; // URL SOAP API-сервиса string _method = @"GetInfo"; // Метод, который вызывается на API сервисе string _soapEnvelope = File.ReadAllText(@"С:\GetInfo.xml"); // SOAP-конверт (запрос), который будет отправлен к API string _response = GetResponseSoap(_url, _method, _soapEnvelope); // получаем ответ SOAP сервиса в виде XML textBox1.Text = _response; // выводим данные в текстовое поле }
В строке 7 кода вызывается метод и результат пишется в переменную.
Некоторые отправляемый запрос предпочитают указывать в коде. Я делаю код максимально независимым, поэтому у меня в методе считываются данные из файла «GetInfo.xml» (строка 6 кода).
Что из себя представляет данный файл? Это SOAP-конверт, который надо отправить сервису, чтобы получить от него ответ. В нашем случае, если я бы открыл «GetInfo.xml», то в нём мы бы увидели следующее:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://webservices.victorz.ru/"> <soapenv:Header/> <soapenv:Body> <web:Transport> <NumID>975764</NumID> </web:Transport> </soapenv:Body> </soapenv:Envelope>
Что надо отправить вам в адрес вашего сервиса вы должны знать и сохранить эти данные в аналогичном XML-файле.
Отправив запрос сервису, мы получим от него ответ и выведем в текстовое поле:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:TransportResponse xmlns:ns2="http://webservices.victorz.ru/" xmlns:ns3="data.shemas.victorz.ru"> <TransportName>Газель</TransportName> <TransportNumber>р999вд</TransportNumber> <TransportRegion>77</TransportRegion> </ns2:TransportResponse> </S:Body> </S:Envelope>
Далее нам остаётся только распарсить XML ответ и получить требуемые данные из XML.
Как видим всё достаточно просто. У нас SOAP API внутренний и не использует авторизацию, поэтому запрос отправляется без авторизации. Если у вас сервис с авторизацией, то в комментариях можете сообщить читателям, как отправлять данные с авторизацией.
Здравствуйте. Вы всё понятно описали кроме одного: кто\что создаёт xml файл для отправки его на сервер в конверте?
string _soapEnvelope = File.ReadAllText(@»С:\GetInfo.xml»); // SOAP-конверт (запрос), который будет отправлен к API
Этот файл вы сами руками заранее подготовили в xml? Если нет, то опишите подробнее (если не сложно), каким образом и в какой момент появляется «GetInfo.xml» на вашем диске C:\
Добрый день.
У меня задача просто плюнуть шаблонный XML по адресу, без метода. Получается вместо параметра _method ставлю свой шаблон XML?
Нет.
Вам в этом случае надо изменить эту строку:
_request.Headers.Add("SOAPAction", _url + @"/" + _method);
на эту:
_request.Headers.Add("SOAPAction", _url);
А ваш шаблон в этой строке считывается:
string _soapEnvelope = File.ReadAllText(@"С:\GetInfo.xml");
Огромное спасибо за отклик. Небольшое уточнение, я xml не из файла читаю, а формирую программно в C#, подставляя в него значения из класса.
Еще один вопрос, если позволите — на данный момент авторизация в стороннем сервисе не реализована, я могу просто формируя POST запрос не писать в хедере строку с Authorization Basic и здесь логин:пароль в байтарай?
Если авторизации нет, то в хедере не указываем данные для авторизации.
я тут был
Тот же метод
_request.Headers.Add("SOAPAction", _url + @"/" + _method);
argumentException.
Указанное значение содержит недопустимые знаки управления.
Изначально это исключение было создано в этом стеке вызовов:
[Внешний код]
Diploma.Form1.GetResponseSoap(string, string, string) в Form1.cs
Diploma.Form1.button1_Click(object, System.EventArgs) в Form1.cs
[Внешний код]
Diploma.Program.Main() в Program.cs
Привет! Использую данную идею для реализации в дипломной работе. Не могли бы мне помочь разобраться:
Дипломами не занимаюсь. Попросите ребят на спец. формумах.
У меня возникает ошибка в строке
Дальше выполнять не хочет.
Запускайте в дебаге и смотрите, что у вас происходит. Используйте контрольные точки остановки, чтобы на разных этапах понять что и где передаётся/присваивается.