Дата последнего изменения: 04.06.2024
Рассмотрим, как на основе модуля Веб-сервисы можно сделать простейшее Windows-приложение для добавления новостей при помощи Visual Studio 2012 и .NET Framework 4.5. Для этого можно скачать одну из бесплатных версий Express 2012 for Windows Desktop.
Прежде всего, чтобы иметь возможность добавлять новости, необходимо определить информационный блок, в котором они будут храниться. Для примера будем использовать уже имеющийся у нас на сайте инфоблок с ID=3.
Создание компонента веб-сервиса для добавления новостей
При установке модуля Веб-сервисы создается новый компонент bitrix:webservice.server. Он предназначен для простого создания, тестирования и вывода в читабельном виде информации о ваших веб-сервисах. Для нашего веб-сервиса он будет являться «сервером».
Сначала создадим свой компонент. Для этого создадим новую папку в /bitrix/components/demo, назовем ее webservice.addnews. Как и любой другой компонент 2.0, компонент веб-сервиса должен содержать стандартные файлы описаний: 
<?
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" => "Веб-сервис добавления новостей."
		)
	),
);
?>
<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
$arComponentParameters = array(
	"GROUPS" => array(),
	"PARAMETERS" => array(),
	);
?>
<?
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(3);   
	if ($iblock_permission < "W")
	{
		$GLOBALS["USER"]->RequiredHTTPAuthBasic();
		return new CSOAPFault('Server Error', 'Unable to authorize user.');
	}
		$arFields = Array(
			"IBLOCK_ID"=>3, // инфоблок "Новости магазина"
			"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 2012 for Windows Desktop на C#.


В поле Службы отобразится наш веб-сервис bitrix.webservice.addnews с интерфейсом CAddNewsWSInterface, для которого доступна операция AddNews:

Переименовываем пространство имен в myws.addnews и нажимаем кнопку OK.
<binding name="CAddNewsWSBinding"> <security mode="TransportCredentialOnly"> <transport clientCredentialType="Basic" proxyCredentialType="None" realm="AXIS" /> <message clientCredentialType="UserName" algorithmSuite="Default" /> </security> </binding>


private void button1_Click(object sender, EventArgs e)
	{
		CAddNewsWSInterfaceClient news = new CAddNewsWSInterfaceClient();
		news.ClientCredentials.UserName.UserName = "admin";
		news.ClientCredentials.UserName.Password = "password";
		try
		{
		long result = news.AddNews(NAME.Text, NEWS_DATE.Text, PREVIEW_TEXT.Text, DETAIL_TEXT.Text, KEYWORDS.Text, SOURCE.Text);
		MessageBox.Show("Новость №" + result + " успешно добавлена");
		}
		catch (System.Web.Services.Protocols.SoapHeaderException exception)
		{
			MessageBox.Show("Ошибка добавления новости [" + exception.Message + "]");
		}
	}
 
или асинхронный:
private async void button1_Click(object sender, EventArgs e)
	{
		CAddNewsWSInterfaceClient news = new CAddNewsWSInterfaceClient();
		news.ClientCredentials.UserName.UserName = "admin";
		news.ClientCredentials.UserName.Password = "password";
	try
	{
	AddNewsResponse result = await news.AddNewsAsync(NAME.Text, NEWS_DATE.Text, PREVIEW_TEXT.Text, DETAIL_TEXT.Text, KEYWORDS.Text, SOURCE.Text);
	MessageBox.Show("Новость №" + result.Body.id + " успешно добавлена");
		}
			catch (System.Web.Services.Protocols.SoapHeaderException exception)
				{
					MessageBox.Show("Ошибка добавления новости [" + exception.Message + "]");
				}
	}
 
using System.Net; using WindowsFormsApplication1.myws.addnews;

В данном уроке показан очень простой пример. Конечно, данный веб-сервис можно дорабатывать, например, чтобы в параметрах компонента можно было управлять в какой инфоблок, какую информацию добавлять, поддержку произвольных свойств и т.п. Также можно доработать и 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(3);
		if ($iblock_permission < "W")
		{
			$GLOBALS["USER"]->RequiredHTTPAuthBasic();
			return new CSOAPFault('Server Error', 'Unable to authorize user.');
		}
        
		$arFields = Array(
			"IBLOCK_ID"=>3, // инфоблок "Новости магазина"
			"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;
		}
	}
			CAddNewsWSInterfaceClient news = new CAddNewsWSInterfaceClient();
			news.ClientCredentials.UserName.UserName = "admin";
			news.ClientCredentials.UserName.Password = "password";
			try
			{
			long result = news.AddNews(NAME.Text, NEWS_DATE.Text, PREVIEW_TEXT.Text, DETAIL_TEXT.Text, KEYWORDS.Text, SOURCE.Text, IMAGE_FILE.Text, base64String);
			MessageBox.Show("Новость №" + result + " успешно добавлена");
		}
		catch (System.Web.Services.Protocols.SoapHeaderException exception)
		{
			MessageBox.Show("Ошибка добавления новости [" + exception.Message + "]");
		}
}
