Bitrix Site Manager v11.0

How To: Create a Windows Application for Publishing News

How To: Create a Windows Application for Publishing News

The Web Service module has actually been a part of Bitrix products for quite a long time. However, I suspect that since its introduction, rather few users have discovered its existence, let alone benefited from this useful feature.

Aside from being a cool gadget in Vista, this module offers a heap of functions and features, allowing users to employ external applications (even installed on mobile phones) to manage their site or portal.

Let us take a step-by-step tour and see how we can create a simple Windows application capable of adding news to a site. We are going to develop our program using Visual Studio 2008 and .NET Framework 3.5.



An Information Block for Our News

It's hard to disagree that before adding something to something we have to create the original something to which we will add the aforementioned something. In our case, we need an information block with a set of required properties. Let's make our life easier and utilize the existing information block e-Store News from the demo. Its ID is 3; write it down somewhere.



Creating a Custom Web Service Component to Add News

The next preparatory step of our adventure is to create a web service itself.

The installation of the Web Service module creates a new component, bitrix:webservice.server. It serves to create, test and display information about your web services in human readable form. In terms of relationships, it will act as a server for our web service.

First of all, we have to create a new component. Create a new folder in /bitrix/components/demo/ and give it the fabulous name of webservice.addnews. Like any other Component 2.0, our component must contain standard description files:

File .description.php:

Code
<? 
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); 

$arComponentDescription = array( 
   "NAME" => "News creation web service", 
   "DESCRIPTION" => "Simply the best web service for adding news ", 
   "CACHE_PATH" => "Y", 
   "PATH" => array( 
      "ID" => "service", 
      "CHILD" => array( 
         "ID" => "webservice", 
         "NAME" => " News creation web service" 
      )    
   ), 
); 
?>


File .parameters.php:

Code
<? 
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); 

$arComponentParameters = array( 
   "GROUPS" => array( 
   ), 
   "PARAMETERS" => array() 
   ), 
); 
?>


And, of course, we must not forget about the executable file: component.php. The first version of it would look like the following:

Code
<? 
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); 

if(!CModule::IncludeModule("webservice") || !CModule::IncludeModule("iblock")) 
   return; 
    
// inherits from  IWebService 
class CAddNewsWS extends IWebService 
{ 
   // GetWebServiceDesc returns the service description and methods 
   function GetWebServiceDesc() 
   { 
      $wsdesc = new CWebServiceDesc(); 
      $wsdesc->wsname = "bitrix.webservice.addnews"; // service name 
      $wsdesc->wsclassname = "CAddNewsWS"; // class name
      $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"] = ""; 

// pass the web service description to a component 
$APPLICATION->IncludeComponent( 
   "bitrix:webservice.server", 
   "", 
   $arParams 
   ); 

die(); 
?>


The code shown above is the minimum required to sketch a web service. As you can see, it defines a CAddNewsWS class inherited from IWebService. To make the system aware of its existence, the class overrides GetWebServiceDesc that returns a web service description as an instance of CwebServiceDesc, and includes the "bitrix:webservice.server" component, passing the description of our web service as a parameter.

Now it's time to see how it works, isn’t it? Create a new page, add our component to it and save the page as, for example, /ws_addnews.php.

Now open the page in the browser:



As you can see, the page displays a brief outline of our web service. But wait, it does not have a single useful method! Alright, create one. Obviously, we need a method that takes the required news fields as input and returns the news ID or an error descriptor object:

Code
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, // the "e-Store News" information block 
         "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 $result; 

   return new CSOAPFault( 'Server Error', 'Error: '.$ib_element->LAST_ERROR ); 
}


Register the new method in the $wsdesc->classes array:

Code
$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" 
      ), 
   ) 
);


The array contains the name of the class and methods with their input and return parameters.

Voila! Now refresh the page containing the component. It shows a new method (yes, it's the one we have just added) and its fields. But the more exciting thing is that you can test how the component works directly on the page!



Creating a Windows Application

We have experienced the first, "more" exciting impression. Now the time has come for the most exciting one. To get ready for this, we shall create a simple Windows application in Visual Studio. You can utilize any .NET version, even the free Express C# version.

Follow the steps below to create the application.

Create a new project:



Open the "Solution Explorer" tab and add a new web reference:



Specify the URL of the page containing our component and click "Go". The browser pane will open the page and display the painfully familiar smile:) service description. Click the service description link; Visual Studio will read the available methods and offer to create their proxy classes. Change the name to "myws.addnews" and click "Add reference".



Now create the news entry dialog. Create a new form, add the necessary fields and the "Submit" button:



Double-click the button to create the click handler and add the code that will send the news to our site:

Code
private void button1_Click(object sender, EventArgs e) 
{ 
            myws.addnews.bitrixwebserviceaddnews news = new myws.addnews.bitrixwebserviceaddnews();
            news.Credentials = new System.Net.NetworkCredential("admin", "123456");
            try
            {
                string result = news.AddNews(FldName.Text, "", RTBPreview.Text, RTBDetail.Text, FldKeywords.Text, FldSource.Text);
                MessageBox.Show("The news #" + result + " has been added successfully.");
            }
            catch (System.Web.Services.Protocols.SoapHeaderException exception)
            {
                MessageBox.Show("Error adding the news: [" + exception.Message + "]");
      }
}


Compile the application and run it. Fill in the fields and click "Submit":



Open the page to ensure that the news has been actually published:



In this article I have made an attempt to give a very simple example in order not to frighten you to death. Obviously, this web service can be extended by giving it more flexibility: introduce information block selection and support for custom properties, etc. The Windows application can also be enhanced: add more options and fields, allow a user to upload multiple news items at a time etc. The only limitation that I can see is the developer's imagination and time; but the possibilities and functionality are really unlimited.

Component source code: download.
Application source code: download.

PS: Guys, I have created a similar application for my mobile and succeeded: smile:)

Markus Gott
03/15/2010 13:05:58
Anna, thank you for an interesting post! But could you show an example of how a new news item with a picture can be added using a mobile device… let's say a preview image and a full-scaled image in the detailed view of the news? smile8)
Anna Slyshkina
03/15/2010 15:53:35
Hello Markus,

thanks for the question. In order to attach graphics to your news item you have to read the image file in the Windows application we created and convert it using System.Convert.ToBase64String in BASE64

On the component's side you'd have to covert it back using the base64_decode function, then you should save it as a temp file and pass it as one of the arFields() values to the CIBlockElement:Add() method. Besides, we have to show the file type used on the web server, that's why along with the file you have to indicate the original file type as well.
Below I shall give you an example of how this web service class would look inside our component:

Code
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"=>3, // the "e-Sore News" information block  
                "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 );  
    }  
 
    // method GetWebServiceDesc returns the service description and its methods  
    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;  
    }  
} 


And this is how the push button handler used in the Windows application look like (IMAGE is actually a new control inside the form; it has to include the file path on the hard drive):

Code
 
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("Image read error [" + 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("News &#8470;"+result+" has been successfully added.");  
    }  
    catch (System.Web.Services.Protocols.SoapHeaderException exception)  
    {  
        MessageBox.Show("Error adding a news item [" + exception.Message + "]");  
    }  
 
} 
Markus Gott
03/16/2010 11:50:12
Hi Ann,

thanks for your reply and examples. I'll give it a try!

Partner Program
Free Online Training
Subscribe to Bitrix News