
Создание информационного блока, в который будут добавляться новости:
Для того чтобы начать что-то добавлять, нужно определиться куда мы будем это делать.
В нашем случае необходим информационный блок с некоторыми свойствами. Для простоты возьмем уже готовый информационный блок "Новости магазина" из демо-версии "Бизнеса" 6.5. Запомним что его ID #33.
Создание компонента веб-сервиса для добавления новостей:
Теперь необходимо приступать непосредственно к созданию самого веб-сервиса.
При установке модуля "Веб-сервисов" создается новый компонент bitrix:webservice.server. Он предназначен для простого создания, тестирования и вывода в читабельном виде информации о ваших веб-сервисах. Для нашего веб-сервиса он будет являться "сервером".
Сначала создадим свой новый компонент. Для этого создадим новую папку в /bitrix/components/demo, назовем ее webservice.addnews. Как и любой другой компонент 2.0, наш компонент веб-сервиса должен содержать стандартные файлы описаний:
Файл .description.php:
<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
$arComponentDescription = array(
"NAME" => "Веб сервис добавления новостей",
"DESCRIPTION" => "Веб сервис добавления новостей",
"CACHE_PATH" => "Y",
"PATH" => array(
"ID" => "service",
"CHILD" => array(
"ID" => "webservice",
"NAME" => "Веб-сервис добавления новостей."
)
),
);
?> |
Файл .parameters.php:
<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
$arComponentParameters = array(
"GROUPS" => array(),
"PARAMETERS" => array(),
);
?> |
И исполняемый файл component.php. Создадим первоначально его в следующем виде:
<?
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
if(!CModule::IncludeModule("webservice") || !CModule::IncludeModule("iblock"))
return;
// наш новый класс наследуется от базового IWebService
class CAddNewsWS extends IWebService
{
// метод GetWebServiceDesc возвращает описание сервиса и его методов
function GetWebServiceDesc()
{
$wsdesc = new CWebServiceDesc();
$wsdesc->wsname = "bitrix.webservice.addnews"; // название сервиса
$wsdesc->wsclassname = "CAddNewsWS"; // название класса
$wsdesc->wsdlauto = true;
$wsdesc->wsendpoint = CWebService::GetDefaultEndpoint();
$wsdesc->wstargetns = CWebService::GetDefaultTargetNS();
$wsdesc->classTypes = array();
$wsdesc->structTypes = Array();
$wsdesc->classes = array();
return $wsdesc;
}
}
$arParams["WEBSERVICE_NAME"] = "bitrix.webservice.addnews";
$arParams["WEBSERVICE_CLASS"] = "CAddNewsWS";
$arParams["WEBSERVICE_MODULE"] = "";
// передаем в компонент описание веб-сервиса
$APPLICATION->IncludeComponent(
"bitrix:webservice.server",
"",
$arParams
);
die();
?> |
Это минимальное содержимое для определения веб-сервиса. Как видно он содержит наследованный от IWebService класс CAddNewsWS, переопределенный метод GetWebServiceDesc, возвращающий описание сервиса в формате CWebServiceDesc и вызов компонента bitrix:webservice.server, которому в качестве параметров передается описание нашего зарождающегося веб-сервиса.
Самое время посмотреть - работает или нет? Для этого создадим новую страницу, разместим наш новый компонент на нее и сохраним, например, под именем /ws_addnews.php:

Откроем ее на сайте:

Как мы видим, появилось описание нашего веб-сервиса. Но у него нет ни одного метода. Значит, приступим к его созданию. Для этого нам потребуется добавить в наш класс новый метод, который принимает на вход в качестве параметров некоторые поля новости, а в качестве результата возвращает ID добавленной новости или ошибку:
function AddNews($NAME, $DATE, $PREVIEW_TEXT, $DETAIL_TEXT, $KEYWORDS, $SOURCE)
{
$iblock_permission = CIBlock::GetPermission(33);
if ($iblock_permission < "W")
{
$GLOBALS["USER"]->RequiredHTTPAuthBasic();
return new CSOAPFault('Server Error', 'Unable to authorize user.');
}
$arFields = Array(
"IBLOCK_ID"=>33, // инфоблок "Новости магазина"
"NAME"=>$NAME,
"DATE_ACTIVE_FROM"=>$DATE,
"PREVIEW_TEXT"=>$PREVIEW_TEXT,
"DETAIL_TEXT"=>$DETAIL_TEXT,
"PROPERTY_VALUES" => Array(
"KEYWORDS"=>$KEYWORDS,
"SOURCE"=>$SOURCE,
)
);
$ib_element = new CIBlockElement();
$result = $ib_element->Add($arFields);
if($result>0)
return Array("id"=>$result);
return new CSOAPFault( 'Server Error', 'Error: '.$ib_element->LAST_ERROR );
} |
Зарегистрируем новый метод в массиве $wsdesc->classes:
$wsdesc->classes = array(
"CAddNewsWS"=> array(
"AddNews" => array(
"type" => "public",
"input" => array(
"NAME" => array("varType" => "string"),
"DATE" => array("varType" => "string"),
"PREVIEW_TEXT" => array("varType" => "string"),
"DETAIL_TEXT" => array("varType" => "string"),
"KEYWORDS" => array("varType" => "string"),
"SOURCE" => array("varType" => "string"),
),
"output" => array(
"id" => array("varType" => "integer")
),
"httpauth" => "Y"
),
)
); |
В массиве содержится название класса и названия методов, с описанием входных и выходных параметров.
Вот и все, теперь если обновить страницу, на которой расположен компонент, то мы сможем увидеть, что появился новый метод и более того, можем протестировать его работу непосредственно из браузера:

Создание приложения:
Теперь можно приступать к завершающему этапу - созданию в Visual Studio простого Windows приложения. Для этого можно скачать и установить одну из бесплатных Express версий, например для C#.
Далее идем по шагам:
Создаем новый проект:

На вкладке Solution Explorer создаем новую "Web reference":

Указываем ссылку на страницу с компонентом, нажимаем "Go". В окне открывается уже знакомая нам страница с описанием сервиса, нажимаем на ней ссылку "описание службы", Visual Studio считывает доступные методы и предлагает нам создать для них прокси-классы, переименовываем название в myws.addnews и нажимаем "Add reference".

Теперь приступаем к созданию непосредственно самого окна ввода новости, для этого разместим на форме необходимые поля и кнопку "Отправить":

Двойным кликом по кнопке открываем обработчик события нажатия на кнопку и размещаем код сохраняющий новость на сайте:
private void button1_Click(object sender, EventArgs e)
{
bitrixwebserviceaddnews news = new bitrixwebserviceaddnews();
news.Credentials = new NetworkCredential("admin", "password");
try
{
string result = news.AddNews(DATE.Text, DETAIL_TEXT.Text, KEYWORDS.Text, NAME.Text, PREVIEW_TEXT.Text, SOURCE.Text);
MessageBox.Show("Новость №"+result+" успешно добавлена.");
}
catch (System.Web.Services.Protocols.SoapHeaderException exception)
{
MessageBox.Show("Ошибка добавления новости [" + exception.Message + "]");
}
} |
Компилируем приложение, запускаем, заполняем поля, нажимаем отправить:

Убедимся, что новость действительно попала к нам на сайт:

В данной статье я показал очень простой пример, чтобы не усложнять первое восприятие
Конечно, данный веб-сервис можно дорабатывать, например, чтобы в параметрах компонента можно было управлять - в какой инфоблок, какую информацию добавлять, поддержку произвольных свойств и т.п. В свою очередь, Windows приложение можно доработать, например, чтобы оно выгружало новости на сайт "пачками", содержало больше полей и настроек. Все ограничено фантазией и временем, но зато, как видим, не ограничено возможностями и инструментами для воплощения их в жизнь. 
Исходный код компонента: .
Исходный код приложения: .
PS: Кстати, попробовал создать аналогичное приложение для своего телефона htc p3300, получилось

Для этого придется на стороне Windows приложения читать файл, конвертировать его при помощи System.Convert.ToBase64String в BASE64, а на стороне компонента конвертировать назад функцией base64_decode, сохранять его во временный файл и передавать на вход методу CIBlockElement:Add(), как одно из полей. Помимо этого, нам необходимо знать на сервере как минимум расширение (тип) файла, поэтому вместе с содержимым будем передавать оригинальное имя файла.
Таким образом вот так будет выглядеть наш класс веб-сервиса в компоненте:
class CAddNewsWS extends IWebService { function AddNews($NAME, $DATE, $PREVIEW_TEXT, $DETAIL_TEXT, $KEYWORDS, $SOURCE, $IMAGE_NAME, $IMAGE_CONTENT) { $iblock_permission = CIBlock::GetPermission(33); if ($iblock_permission < "W") { $GLOBALS["USER"]->RequiredHTTPAuthBasic(); return new CSOAPFault('Server Error', 'Unable to authorize user.'); } $arFields = Array( "IBLOCK_ID"=>33, // инфоблок "Новости магазина" "NAME"=>$NAME, "DATE_ACTIVE_FROM"=>$DATE, "PREVIEW_TEXT"=>$PREVIEW_TEXT, "DETAIL_TEXT"=>$DETAIL_TEXT, "PROPERTY_VALUES" => Array( "KEYWORDS"=>$KEYWORDS, "SOURCE"=>$SOURCE, ) ); if(strlen($IMAGE_NAME)>0 && strlen($IMAGE_CONTENT)>0) { $IMAGE_CONTENT = base64_decode($IMAGE_CONTENT); if(strlen($IMAGE_CONTENT)>0) { $tmp_name = $_SERVER['DOCUMENT_ROOT'].'/bitrix/tmp/'.md5(uniqid(rand(), true)).".tmp"; CheckDirPath($tmp_name); $f = fopen($tmp_name, "wb"); fwrite($f, $IMAGE_CONTENT); fclose($f); $arFields["DETAIL_PICTURE"] = Array("name"=>$IMAGE_NAME, "tmp_name"=>$tmp_name, "size"=>strlen($IMAGE_CONTENT), "type"=>"image/jpeg"); } } $ib_element = new CIBlockElement(); $result = $ib_element->Add($arFields); if($tmp_name) @unlink($tmp_name); if($result>0) return Array("id"=>$result); return new CSOAPFault( 'Server Error', 'Error: '.$ib_element->LAST_ERROR ); } // метод GetWebServiceDesc возвращает описание сервиса и его методов function GetWebServiceDesc() { $wsdesc = new CWebServiceDesc(); $wsdesc->wsname = "bitrix.webservice.addnews"; $wsdesc->wsclassname = "CAddNewsWS"; $wsdesc->wsdlauto = true; $wsdesc->wsendpoint = CWebService::GetDefaultEndpoint(); $wsdesc->wstargetns = CWebService::GetDefaultTargetNS(); $wsdesc->classTypes = array(); $wsdesc->structTypes = Array(); $wsdesc->classes = array( "CAddNewsWS"=> array( "AddNews" => array( "type" => "public", "input" => array( "NAME" => array("varType" => "string"), "DATE" => array("varType" => "string"), "PREVIEW_TEXT" => array("varType" => "string"), "DETAIL_TEXT" => array("varType" => "string"), "KEYWORDS" => array("varType" => "string"), "SOURCE" => array("varType" => "string"), "IMAGE_NAME" => array("varType" => "string"), "IMAGE_CONTENT" => array("varType" => "string"), ), "output" => array( "id" => array("varType" => "integer") ), "httpauth" => "Y" ), ) ); return $wsdesc; } }А вот так обработчик нажатия на кнопку в Windows приложении (IMAGE - это новый контрол на форме, в нем должен быть путь к файлу на диске):
private void button1_Click(object sender, EventArgs e) { Byte[] binaryData; string base64String = ""; if(IMAGE.Text.Length>0) { try { System.IO.FileStream imageFile = new System.IO.FileStream(IMAGE.Text, System.IO.FileMode.Open,System.IO.FileAccess.Read); binaryData = new Byte[imageFile.Length]; imageFile.Read(binaryData, 0, (int)imageFile.Length); imageFile.Close(); base64String = System.Convert.ToBase64String(binaryData, 0, binaryData.Length); } catch (System.Exception exp) { MessageBox.Show("Ошибка чтения картинки [" + exp.Message + "]"); return; } } bitrixwebserviceaddnews news = new bitrixwebserviceaddnews(); news.Credentials = new NetworkCredential("admin", "password"); try { string result = news.AddNews(DATE.Text, DETAIL_TEXT.Text, base64String, IMAGE.Text, KEYWORDS.Text, NAME.Text, PREVIEW_TEXT.Text, SOURCE.Text); MessageBox.Show("Новость №"+result+" успешно добавлена."); } catch (System.Web.Services.Protocols.SoapHeaderException exception) { MessageBox.Show("Ошибка добавления новости [" + exception.Message + "]"); } }The method or operation is not implemented.
и выделение желтым
string result = news.AddNews(
ACTIVE.Text,
DATE_ACTIVE_FROM.Text,
DATE_ACTIVE_TO.Text,
DETAIL_TEXT.Text,
KEYWORDS.Text,
base64String,
IMAGE.Text,
NAME.Text,
PREVIEW_TEXT.Text);
Знает ли кто-нибудь, можно ли создать Web reference в Delphi, C++ Builder?
Конечно можно каждый раз передавать логин и пароль (в чистом или шифрованном виде), но это скорее похоже на костыль, чем на решение.
Я всего лишь хотел показать, как просто создавать приложения для обмена данными и управления сайтом, используя модуль веб-сервисов и .NET. А ситуаций когда это действительно может кому-то пригодиться, я думаю, жизнь преподнесет еще не мало
Очень интересно и полезно!
Полет фантазии о возможностях использования сложно остановить...
Представленная технология очень полезна и перспективна!
У меня уже масса идей в голове по поводу применения всего этого.
Большое спасибо!!!
Error 1 The type or namespace name 'bitrixwebserviceaddnews' could not be found (are you missing a using directive or an assembly reference?)
и т.д
using System.Net;
using WindowsApplication2.myws.addnews;
Просто, когда в Visual Studio вводишь типы из новых пространств, то VS подчеркивает класс красной черточкой и предлагает вставить строки автоматически, поэтому фактически я этих строк и не писал.
событие на кнопку
try { string result = news.AddNews( ACTIVE.Text, DATE_ACTIVE_FROM.Text, DATE_ACTIVE_TO.Text, NAME.Text, PREVIEW_TEXT.Text, DETAIL_TEXT.Text, KEYWORDS.Text); MessageBox.Show("Новость №"+result+" успешно добавлена."); }в компоненте
$wsdesc->classes = array( "CAddNewsWS"=> array( "AddNews" => array( "type" => "public", "input" => array( "NAME" => array("varType" => "string"), "ACTIVE" => array("varType" => "string"), "DATE_ACTIVE_FROM" => array("varType" => "string"), "DATE_ACTIVE_TO" => array("varType" => "string"), "PREVIEW_TEXT" => array("varType" => "string"), "DETAIL_TEXT" => array("varType" => "string"), "KEYWORDS" => array("varType" => "string"), ), "output" => array( "id" => array("varType" => "integer") ), "httpauth" => "Y" ), ) );В итоге получаю ошибку от БУС что не введено название, в какой последовательности передаются данные из приложения в бус ?
Ну или можно попробовать пересортировать параметры в методе вручную.
У меня проблемка с сервисом наоборот. Мне нужен сервис, который отдаст данные приложению.
Написал все так же, как и в статье. Опробовал через Веб-интерфейс. Работает.
Начинаю через приложение - ошибка XML-данных. Пространство имен в ответе пустое, в то время как при коннекте к Веб-сервису оно заполнено.
Приложение MS InfoPath.
Юрий, а можно ли дополнить рецепт добавлением в инфоблок из PDF-формы или формы InfoPath? Или это из другой серии?
З.Ы.: а исходники для коммуникатора есть?
Автору ПИВО! 8)
А как сделать редактирование допустим той же статьи?