Disclaimer:A lot of articles have been written on this topic and, as you, of course, guessed, this is another one. You may learn something new from it, but nothing top-secret that you couldn’t google yourself is described here. Only notes from personal experience.
Introduction
We will only consider the situation when there is a third-party web service and the task is to establish data exchange.
The structure of the service is described in the file WSDL(English Web Services Description Language)
The file is most often available via a link where the entry point to the web service itself is located. I wrote “most often” because there are exceptions. For example, a SAP-based Web service does not publish wsdl and can only be obtained by unloading it from the application itself.
And so, we have a description of the web service, login, password. Let's connect.
// Define the settings of the ServiceNameSpace URL = "http://Somesite.ru"; UserName = "TestUser"; Password = "q1w2e3"; LocationWSDL = "https://Somesite.ru/WebService/Some?wsdl"; ServiceName = "SomeServiceName"; ConnectionPointName = "SomeService_Port"; // Create an SSL connection = New SecureConnectionOpenSSL(); WSDefinition = New WSDefinition(WSDLLocation,SSL); WSProxy = New WSProxy(WSDefinition, ServiceNameSpaceURL, ServiceName, ConnectionPointName, SSL); WSProxy.User = UserName; WSProxy.Password = Password;
Great! We have connected to the web service! In theory, this is the basis of any exchange option, as it allows you to create data structure object based on wsdl, and working with such an object is a pleasure.
Let's look at the XML that SoapUI gives us
Now let's describe it programmatically
// Create an object and fill it with data Own FactoryXDTO = WS Definition. FactoryXDTO; RootType = OwnFactoryXDTO.Type(URLServiceNameSpace, "SUBMISSION"); RootObject = OwnFactoryXDTO.Create(RootType); RootObject.ID = "4356"; ClientType = OwnFactoryXDTO.Type(URLServiceNameSpace, "CUSTOMER"); ClientObject = OwnFactoryXDTO.Create(ClientType); ClientObject.CLIENT_ID = "121212"; ClientObject.SEX = "M"; // F - female, M - male ClientObject.CLIENT_BIRTHDAY = "19900111"; // Client cars AutoType = OwnFactoryXDTO.Type(URLServiceNameSpace, "CARS"); AutoObject = OwnFactoryXDTO.Create(AutoType); AutoObject.CLASS = "Mercedes"; AutoObject.MODEL = "GLS"; ClientObject.CARS.Add(AutoObject); AutoObject = OwnFactoryXDTO.Create(AutoType); AutoObject.CLASS = "Audi"; AutoObject.MODEL = "TT"; ClientObject.CARS.Add(AutoObject); RootObject.CUSTOMER.Add(CustomerObject);
The data has been successfully filled in. Now we need to send them.
At this very moment, many nuances arise. Let's try to look at each one.
Recipe 1. Send the entire XDTO object
Result = WSProxy.AddCustomers(RootObject);
All that remains is to process the result that the service returned to us and that’s all. Agree that this is very convenient!
But in practice this is not always the case. For example, 1C does not get along with the prefixation of certain tags inside xml, when the namespace of the root tag differs from the space of the child tags. In such cases, you have to collect the soap manually. I also had to deal with web services that expect pure xml as a parameter. It's insanity, but it's still not too difficult to do.
Recipe 2. Send pure xml as a parameter
XMLRecordParameters = NewXMLRecordParameters("UTF-8", "1.0", True); MyXML = NewXMLRecord; MyXML.SetString(XMLRecordParameters); MyXML.WriteXMLDeclaration(); OwnFactoryXDTO.WriteXML(MyXML, RootObject); StringXML = MyXML.Close(); If RemoveNameSpaceDescription Then TryFirstTagInRow = StrGetRow(XMLString,2); RootTagName = RootObject.Type().Name; XMLString = StrReplace(XMLString, FirstTagInString, "<"+ИмяКорневогоТэга+">"); Exception //ErrorDescription() EndAttempt; EndIf; Result = WSProxy.AddCustomers(XML String);
If you do not delete the namespace that 1c adds by default, then there are only 5 more lines of code. Most often I wrap the xml transformation in a function since we usually call more than one method.
Recipe 3. Send via native HTTPRequest.
String SOAP = "In this option, we will have to assemble the soap manually. Essentially, we simply wrap the xml from recipe 2 into a soap wrapper, where, depending on the requirements of the web service, we can change our soap as we please.
Next, we describe the headers according to the documentation. Some services will easily process our request even without headers; here we need to look at the specific case. If you don’t know what headers to write, then the easiest way is to look at the request in SoapUI by switching to the RAW tab.
The function for getting a Base64 string looks like this (I spied it):
Function GetBase64AuthorizationHeader(UserName, Password)FileEncoding = TextEncoding.UTF8; TemporaryFile = GetTemporaryFileName(); Entry = NewTextEntry(TemporaryFile, FileEncoding); Record.Record(UserName+":"+Password); Record.Close(); DvData = new BinaryData(TemporaryFile); Result = Base64String(DvData); DeleteFiles(TemporaryFile); Result = Avg(Result,5); Return Result; EndFunction
Eat important point. When working with an HTTP connection, specify the address without specifying the “http://” and “https://” protocols, otherwise you risk wasting time searching for an unobvious error.
Recipe 4. Send via WinHttpRequest
WinHttp = New COMObject("WinHttp.WinHttpRequest.5.1"); WinHttp.Option(2,"UTF-8"); WinHttp.Option(4, 13056); //intSslErrorIgnoreFlag WinHttp.Option(6, true); //blnEnableRedirects WinHttp.Option(12, true); //blnEnableHttpsToHttpRedirects WinHttp.Open("POST", "https://Somesite.ru/WebService/Some/GetCustomer", 0); WinHttp.SetRequestHeader("Content-type", "text/xml"); WinHttp.SetCredentials(UserName, Password, 0); WinHttp.Send(StringSOAP); WinHttp.WaitForResponse(15); XMLResponse = WinHttp.ResponseText();This is essentially the same as in the previous version, but we are working with a COM object. We indicate the connection string in full, along with the protocol. Special attention should be paid only to the flags for ignoring SSL certificate errors. They are needed if we work via SSL, but without a specific certificate, since it is not possible to create a new secure connection in this option (or I don’t know how). The rest of the mechanism is similar to the previous one.
Also, in addition to “WinHttp.WinHttpRequest.5.1”, you can use “Microsoft.XMLHTTP”, “Msxml2.XMLHTTP”, “Msxml2.XMLHTTP.3.0”, “Msxml2.XMLHTTP.6.0”, if suddenly it does not take off on WinHttp. The methods are almost the same, only the number of parameters is different. I suspect that one of these options is embedded inside the 1c HTTPRequest object.
On this moment These are all the recipes I have. If I come across new ones, I will definitely add to the article.
Processing the result
In Recipe 1, we most often get a ready-made XDTO object and work with it as a structure. In all other cases, you can convert the xml response to XDTO
If Result.StatusCode = 200 Then ReadXML = New ReadXML; ReadXML.SetString(Result.GetBodyAsString()); ObjectResponse = OwnFactoryXDTO.ReadXML(ReadXML); Report(ObjectResponse.Body.Response.RESPONSE_ID); Report(ObjectResponse.Body.Response.RESPONSE_TEXT); endIf;
Everything is simple here.
Instead of a conclusion
1. Start working with web services with the SoapUI program. It is intended for such work and will allow you to quickly understand how a particular service works. There is an article for mastering
2. If you are exchanging with a service over an unsecured http channel and the question arises about what exactly 1c is sending in its messages, then you can use traffic sniffers such as Wireshark, Fiddler, and others. The problem will only arise if you are using an SSL connection.
3. If, nevertheless, the web service communicates via https, then we install an Nginx server on a remote machine (any machine, most importantly not on our own), which we will contact, and it, in turn, will pack everything in https and forward it where needed ( reverse proxy ) and add to the standard config:
Server ( listen 0.0.0.0:8080; server_name MyServer; location ~ .* ( proxy_pass https://Somesite.ru:8001; proxy_set_header Host $host; proxy_set_header Authorization "Basic
5. If authentication involves use of cookies, then the next one was found
P.S. If you have questions, suggestions for improving the code, have your own recipes that differ from those described, you found errors or think that the author is “incorrect” and “has no place in 1C”, then write comments and we will discuss everything.
- Tutorial
Hi all!
It so happened that recently I began to develop web services. But today the topic is not about me, but about how we can write our own XML Web Service based on the SOAP 1.2 protocol.
I hope that after reading the topic you will be able to:
- write your own server implementation of a web application;
- write your own client implementation of a web application;
- write your own web service description (WSDL);
- send the client arrays of the same type of data to the server.
1 Problem statement
1.1 Boundaries
At the beginning, I propose to deal with the result that we will achieve at the end of the topic. As announced above, we will write a service for sending SMS messages, and more precisely, we will receive messages from different sources via the SOAP protocol. After which, we will consider in what form they come to the server. The process of queuing messages for further sending to the provider, unfortunately, is beyond the scope of this post for many reasons.1.2 What data will we change?
Great, we have decided on the boundaries! Next step What needs to be done is to decide what data we will exchange between the server and the client. On this topic, I suggest not to split hairs for too long and immediately answer the main questions for yourself:- What minimum data must be sent to the server in order to send an SMS message to a subscriber?
- What minimum data must be sent from the server to satisfy the client's needs?
- number mobile phone, and
- text of the SMS message.
- date of sending the SMS message.
- Message type.
And yet, I forgot something! If we reflect a little more, it is worth noting that the client can send either one SMS message or a number of them to the server at a time. In other words, one data packet can contain from one to infinity messages.
As a result, we get that to send an SMS message we need the following data:
- Mobile phone number,
- SMS message text,
- time of sending the SMS message to the subscriber,
- message type.
We have answered the first question, now we need to answer the second question. And perhaps I’ll allow myself to mess around a little. Therefore, from the server we will send only Boolean data, the meaning of which has the following meaning:
- TRUE – the packet successfully reached the server, passed authentication and queued for sending to the SMS provider
- FALSE – in all other cases
This concludes the description of the problem statement! And finally, let's get down to the fun part - let's figure out what kind of strange beast this SOAP is!
2 What is SOAP?
In general, initially I did not plan to write anything about what SOAP is and wanted to limit myself to links to the w3.org website with the necessary specifications, as well as links to Wikipedia. But at the very end I decided to write a short note about this protocol.And I will begin my story with the fact that this data exchange protocol belongs to a subset of protocols based on the so-called RPC (Remote Procedure Call) paradigm, the antipode of which is REST (Representational State Transfer). You can read more about this on Wikipedia; links to articles are at the very end of the topic. From these articles we need to understand the following: “The RPC approach allows the use of a small number of network resources with a large number of methods and a complex protocol. With the REST approach, the number of methods and protocol complexity are strictly limited, which means the number of individual resources can be large.” That is, in relation to us, this means that in the case of the RPC approach on the site there will always be one input (link) to the service and what procedure to call to process incoming data we transfer along with the data, while with the REST approach in our The site has many inputs (links), each of which accepts and processes only certain data. If anyone reading knows how to explain the difference in these approaches even more simply, be sure to write in the comments!
The next thing we need to know about SOAP is that this protocol uses the same XML as a transport, which on the one hand is very good, because immediately our arsenal receives the full power of a stack of technologies based on given language markup, namely XML-Schema - a language for describing the structure of an XML document (thanks Wikipedia!), which allows automatic validation of data received by the server from clients.
And so, now we know that SOAP is a protocol used to implement remote procedure calls and it uses XML as a transport! If you read the article on Wikipedia, you can also learn from there that it can be used over any application-level protocol, and not just in combination with HTTP (unfortunately, in this topic we will only consider SOAP over HTTP). And you know what I like most about all this? If there are no guesses, then I’ll give a hint - SOAP!... Still no guesses?... Are you sure you read the article on Wikipedia?... In general, I won’t torture you further. Therefore, I’ll go straight to the answer: “SOAP (from the English Simple Object Access Protocol - simple protocol access to objects; up to specification 1.2)". The most remarkable thing about this line is in italics! I don’t know what conclusions you drew from all this, but I see the following - since this protocol cannot in any way be called “simple” (and apparently even w3 agrees with this), then from version 1.2 it stopped being decrypted somehow! And it became known as SOAP, just SOAP, period.
Well, okay, please excuse me, I got a little sidetracked. As I wrote earlier, XML is used as transport, and the packets that travel between the client and server are called SOAP envelopes. If you consider the general structure of the envelope, it will seem very familiar to you, because... resembles the structure of an HTML page. It has a main section - Envelop, which includes sections Header And Body, or Fault. IN Body data is transmitted and it is a mandatory section of the envelope, while Header is optional. IN Header authorization or any other data that is not directly related to the input data of the web service procedures may be transmitted. About Fault there is nothing special to tell, except that it comes to the client from the server in case of any errors.
This is where my review story about the SOAP protocol ends (we will look at the envelopes themselves and their structure in more detail when our client and server finally learn to run them at each other) and a new one begins - about the SOAP companion called WSDL(Web Services Description Language). Yes, yes, this is the very thing that scares away most of us from even trying to take and implement our API on this protocol. As a result, we usually reinvent our wheel with JSON as transport. So what is WSDL? WSDL is a language for describing web services and accessing them, based on the XML language (c) Wikipedia. If this definition does not make clear to you the entire sacred meaning of this technology, then I will try to describe it in my own words!
WSDL is designed to allow our clients to communicate normally with the server. To do this, the file with the extension “*.wsdl” describes the following information:
- What namespaces were used?
- What data schemas were used?
- What types of messages does the web service expect from clients?
- Which data belongs to which web service procedures,
- What procedures does the web service contain?
- How should the client call the web service procedures,
- To which address should customer calls be sent?
3 Introduction to XML-Schema
Now we know a lot about what SOAP is, what is inside it, and have an overview of the technology stack that surrounds it. Since, first of all, SOAP is a way of interaction between a client and a server, and XML markup language is used as a transport for it, then in this section We’ll take a little look at how automatic data validation occurs using XML schemas.The main task of the diagram is to describe the structure of the data that we are going to process. All data in XML schemas is divided into simple(scalar) and complex(structures) types. Simple types include the following types:
- line,
- number,
- boolean value,
- date of.
I suggest not going far and writing an XML schema for our SMS message! Below is the xml description of the SMS message:
Our complex type diagram will look like this:
This entry reads as follows: We have a variable " message" type " Message" and there is a complex type called " Message", which consists of a sequential set of elements " phone" type string, « text" type string, « date" type dateTime, « type" type decimal. These types are simple and are already defined in the schema description. Congratulations! We just wrote our first XML Schema!
I think that the meaning of the elements " element" And " complexType"Everything has become more or less clear to you, so we won’t focus on them any more and let’s switch straight to the composer element" sequence" When we use the composer element " sequence“We inform you that the elements included in it must always be located in the sequence specified in the diagram, and all of them are mandatory. But don't despair! There are two more composer elements in XML schemas: " choice" And " all" Composer " choice" announces that there must be one of the elements listed in it, and the composer " all» – any combination of the listed elements.
As you remember, in the first section of the topic we agreed that from one to infinity SMS messages can be transmitted in a package. Therefore, I propose to understand how such data is declared in the XML schema. The general package structure might look like this:
The diagram for such a complex type will look like this:
The first block contains the familiar declaration of the complex type “ Message" If you noticed, then in each simple type included in " Message", new clarifying attributes have been added " minOccurs" And " maxOccurs" As you might guess from the name, the first ( minOccurs) indicates that this sequence must contain at least one element of type " phone», « text», « date" And " type", while the next one ( maxOccurs) attribute declares to us that there is at most one such element in our sequence. As a result, when we write our own schemas for any data, we are given the widest choice in how to configure them!
The second block of the diagram declares the element " messageList" type " MessageList" It's clear that " MessageList" is a complex type that contains at least one element " message", But maximum number There is no limit to such elements!
4 Write your WSDL
Do you remember that WSDL is our web service? I hope you remember! As we write it, our little web service will run on it. Therefore, I suggest not to mess around.In general, in order for everything to work correctly for us, we need to transfer a WSDL file with the correct MIME type to the client. To do this, you need to configure your web server accordingly, namely, set the MIME type for files with the “*.wsdl” extension to the following line:
Application/wsdl+xml
But in practice, I usually sent the HTTP header via PHP " text/xml»:
Header("Content-Type: text/xml; charset=utf-8");
and everything worked great!
I want to warn you right away that our simple web service will have a rather impressive description, so don’t be alarmed, because... Most of the text is obligatory water and, having written it once, you can constantly copy it from one web service to another!
Since WSDL is XML, you need to write about this directly in the very first line. The root element of the file should always be called " definitions»:
Typically, WSDL consists of 4-5 main blocks. The very first block is the definition of a web service or, in other words, the entry point.
It says here that we have a service called - “ SmsService" In principle, all the names in the WSDL file can be changed by you to whatever you want, because they play absolutely no role.
After this we announce that in our web service " SmsService" there is an entry point ("port") called " SmsServicePort" It is to this entry point that all requests from clients to the server will be sent. And indicate in the element “ address» link to the handler file that will accept requests.
Once we have defined the web service and specified the entry point for it, we need to bind supported procedures to it:
To do this, it lists which operations and in what form they will be called. Those. for port " SmsServicePort" a binding is defined under the name " SmsServiceBinding", which has a call type " rpc"and HTTP is used as the transmission protocol. Thus, we indicated here that we will make an RPC call over HTTP. After this we describe which procedures ( operation) are supported in the web service. We will support only one procedure – “ sendSms" Through this procedure our wonderful messages will be sent to the server! After the procedure has been declared, it is necessary to indicate in what form the data will be transmitted. In this case, it is indicated that standard SOAP envelopes will be used.
After that, we need to bind the procedure to messages:
To do this, we specify that our binding is of type " SmsServicePortType" and in the element " portType"with the name of the same type, we indicate the binding of procedures to messages. So, incoming message(from client to server) will be called " sendSmsRequest", and outgoing (from server to client) " sendSmsResponse" Like all names in WSDL, the names of incoming and outgoing messages are arbitrary.
Now we need to describe the messages themselves, i.e. incoming and outgoing:
To do this we add the elements " message" with names " sendSmsRequest" And " sendSmsResponse" respectively. In them we indicate that the input should be an envelope whose structure corresponds to the data type " Request" After which an envelope is returned from the server containing the data type - “ Response».
Now we need to do just a little - add a description of these types to our WSDL file! And how do you think the WSDL describes incoming and outgoing data? I think that you have already understood everything a long time ago and told yourself that using XML schemas! And you will be absolutely right!
You can congratulate us! Our first WSDL has been written! And we are one step closer to achieving our goal.
Next, we'll look at what PHP provides us with for developing our own distributed applications.
5 Our first SOAP server
Earlier I wrote that to create a SOAP server in PHP we will use the built-in SoapServer class. In order for all further actions to happen the same way as for me, you will need to tweak your PHP a little. To be even more precise, you need to make sure that you have the “php-soap” extension installed. It is best to read how to install it on your web server on the official PHP website (see the list of references).After everything has been installed and configured, we will need to create a file in the root folder of your hosting “ smsservice.php» with the following content:
setClass("SoapSmsGateWay"); //Start the server $server->handle();
I hope there is no need to explain what is above the line with the “ini_set” function. Because there it is determined which HTTP headers we will send from the server to the client and the environment is configured. In the line with “ini_set” we disable caching of the WSDL file so that our changes in it immediately take effect on the client.
Now we come to the server! As you can see, the entire SOAP server takes only three lines! On the first line, we create a new instance of the SoapServer object and pass the address of our WSDL description of the web service to its constructor. Now we know that it will be located in the root of the hosting in a file with the self-explanatory name “ smsservice.wsdl.php" In the second line, we tell the SOAP server which class needs to be pulled in order to process the envelope received from the client and return the envelope with the response. As you might have guessed, it is in this class that our only method will be described sendSms. On the third line we start the server! That's it, our server is ready! With which I congratulate us all!
Now we need to create the WSDL file. To do this, you can either simply copy its contents from the previous section, or take liberties and “template” it a little:
";
?>
At this stage, we should be completely satisfied with the resulting server, because We can log the envelopes coming to it and then calmly analyze the incoming data. In order for us to receive anything on the server, we need a client. So let's get to it!
6 SOAP client on the way
First of all, we need to create a file in which we will write the client. As usual, we will create it in the root of the host and call it " client.php", and inside we will write the following: messageList = new MessageList(); $req->messageList->message = new Message(); $req->messageList->message->phone = "79871234567"; $req->messageList->message->text = "Test message 1"; $req->messageList->message->date = "2013-07-21T15:00:00.26"; $req->messageList->message->type = 15; $client = new SoapClient("http://($_SERVER["HTTP_HOST"])/smsservice.wsdl.php", array("soap_version" => SOAP_1_2)); var_dump($client->sendSms($req));
Let's describe our objects. When we wrote the WSDL, it described three entities for the envelope incoming to the server: Request, MessageList And Message. Accordingly classes Request, MessageList And Message are reflections of these entities in our PHP script.
Once we have defined the objects, we need to create an object ( $req), which we will send to the server. After which come the two most cherished lines for us! Our SOAP client! Believe it or not, this is enough for our server to start receiving messages from the client, as well as for our server to successfully receive and process them! In the first of them, we create an instance of the SoapClient class and pass the address of the location of the WSDL file to its constructor, and in the parameters we explicitly indicate that we will work using the SOAP protocol version 1.2. On the next line we call the method sendSms object $client and immediately display the result in the browser.
Let's run it and see what we finally got!
The following object was returned to me from the server:
Object(stdClass) public "status" => boolean true
And this is great, because... Now we know for sure that our server is working and not only works, but can also return some values to the client!
Now let's look at the log that we prudently keep on the server side! In its first part we see the raw data that arrived on the server:
This is the envelope. Now you know what it looks like! But it’s unlikely that we’ll be interested in looking at it all the time, so let’s deserialize the object from the log file and see if everything is fine:
Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1 " (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length=2)
As you can see, the object was deserialized correctly, for which I want to congratulate us all! Something more interesting awaits us next! Namely, we will send the client to the server not just one SMS message, but a whole pack (to be more precise, three)!
7 Sending complex objects
Let's think about how we can transfer a whole bunch of messages to the server in one packet? Probably the most in a simple way there will be an array organization inside the messageList element! Let's do this:// create an object to send to the server $req = new Request(); $req->messageList = new MessageList(); $msg1 = new Message(); $msg1->phone = "79871234567"; $msg1->text = "Test message 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = new Message(); $msg2->phone = "79871234567"; $msg2->text = "Test message 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = new Message(); $msg3->phone = "79871234567"; $msg3->text = "Test message 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList->message = $msg1; $req->messageList->message = $msg2; $req->messageList->message = $msg3;
Our logs indicate that the following packet was received from the client:
What nonsense, you say? And you will be right in a sense, because... As soon as we learned that an object left the client, it came to our server in absolutely the same form in the form of an envelope. True, SMS messages were not serialized in XML in the way we needed - they had to be wrapped in elements message, not in Struct. Now let's see in what form such an object comes to the method sendSms:
Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "Struct" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length= 37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone " => string "79871234567" (length=11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length= 19) public "type" => string "17" (length=2)
What does this knowledge give us? Only that the path we have chosen is not correct and we have not received an answer to the question - “How can we get on the server correct structure data? But I suggest not to despair and try to convert our array to the type an object:
$req->messageList->message = (object)$req->messageList->message;
In this case, we will receive another envelope:
Came into the method sendSms the object has the following structure:
Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length= 37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone " => string "79871234567" (length=11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length= 19) public "type" => string "17" (length=2)
As for me, “the sum does not change from changing the places of the terms” (c). What BOGUS, What Struct– we have not yet achieved our goal! And to achieve it, we need to make sure that instead of these incomprehensible names our native one is displayed message. But the author does not yet know how to achieve this. Therefore, the only thing we can do is get rid of the extra container. In other words, we will now make sure that instead of message became BOGUS! To do this, change the object as follows:
// create an object to send to the server $req = new Request(); $msg1 = new Message(); $msg1->phone = "79871234567"; $msg1->text = "Test message 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = new Message(); $msg2->phone = "79871234567"; $msg2->text = "Test message 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = new Message(); $msg3->phone = "79871234567"; $msg3->text = "Test message 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList = $msg1; $req->messageList = $msg2; $req->messageList = $msg3; $req->messageList = (object)$req->messageList;
What if we get lucky and the correct name comes up from the diagram? To do this, let's look at the envelope that arrived:
Yes, a miracle did not happen! BOGUS– we won’t win! Came to sendSms the object in this case will look like this:
Object(stdClass) public "messageList" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public " text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length =2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length=37) public "date" => string " 2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone" => string "79871234567" (length= 11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string " 17" (length=2)
As they say – “Almost”! On this (slightly sad) note, I propose to slowly wrap things up and draw some conclusions for ourselves.
8 Conclusion
Finally we got here! Let's figure out what you can do now:- you can write the WSDL file necessary for your web service;
- you can easily write your own client that can communicate with the server via SOAP;
- you can write your own server that communicates with the outside world via SOAP;
- you can send arrays of the same type of objects to the server from your client (with some restrictions).
- the native SoapClient class does not correctly serialize data structures of the same type in XML;
- when serializing an array to XML it creates an extra element called Struct;
- when serializing an object to XML it creates an extra element called BOGUS;
- BOGUS less evil than Struct due to the fact that the envelope is more compact (extra namespaces are not added to the XML header of the envelope);
- Unfortunately, the SoapServer class does not automatically validate the envelope data with our XML schema (perhaps other servers do not do this either).
Alexey Boyko
SOAP and XML web services on the .Net platform
XML Web services offer a level of compatibility and interoperability across operating systems that
platforms and languages that were previously simply unavailable.
Andrew Troelsen (MVP (Most Valuable Professional in Microsoft))
If you haven't worked with XML web services before, you've probably heard the word "SOAP". It's time to understand these concepts.
Intro
If you're interested in the Internet or smaller networks, you'll likely come across XML web services sooner or later. An XML web service is not just a web application that can output information to a browser. Rather, it is a remoting technology that allows you to call methods and properties of an object on the network using standard HTTP requests.
In practice, this means that clients for such a service can be written in different languages and for different operating systems.
HTTP methods GET or POST can be used as information “transport” between the service and the client.
Or you can “overlay” another protocol on top - SOAP (Simple Object Access Protocol). This is usually done, since in this case it is possible to pass complex types (including user ones). But the classic GET and POST methods only support lists, simple arrays and strings.
SOAP Interop Example
A SOAP message is an XML document placed in the body of an HTTP request.
Listing 1. SOAP message structure
The interaction between the client and the service occurs as follows:
- the client generates a SOAP request and sends it to the service;
- service on remote computer executes the procedure and sends a SOAP response.
For example, this is what a SOAP request calling the HelloWorld() method of a remote XML web service might look like:
Listing 2. Example SOAP request
The HelloWorld() method, as expected, returns the string “Hello, world!”:
Listing 3. Example SOAP response
Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Creating an XML Web Service on the .NET 2.0 Platform
You can create a service different ways, we will use Visual Studio 2005. Click “File -> New -> Web Site”, in the window that opens, select “ASP.NET web Service”. At the address specified during creation, you will find the following files and directories (see Fig. 1).
In principle, a service can contain only one single file with the *.asmx extension. (The extension *.asmx is used to denote .Net web services.) In this case, this is not the case, look at the contents of the Service.asmx file:
Listing 4. Service.asmx defined external file support
<%@ WebService Language="C#" CodeBehind="~/App_Code/Service.cs" class="Service" %>
The CodeBehind attribute specifies an external file located in the App_Code folder that contains the program code that implements the HelloWorld() method:
Listing 5. Service.cs file implementing the HelloWorld() method
using System;
using System.Web;
using System.Web.Services;
Public Service() (
Return "Hello World";
It is possible to create a single Service.asmx file without support code that has the same functionality:
Listing 6. Service.asmx without external support code
<%@ WebService Language="C#" class="Service" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
public class Service: System.Web.Services.WebService
Public Service() (
Public string HelloWorld() (
Return "Hello World";
This is of no use to us, and we will not do this.
As you can see, the only method in our web service is marked with the attribute, which informs the ASP.NET runtime that this method is available for incoming HTTP requests. Members not marked with this attribute will not be accessible to client programs.
Such a simple service is quite suitable for our experiments; all that remains is to publish it.
Publishing an XML Web Service using IIS
We are not talking about publishing on the Internet, but about creating conditions for testing our service on a local computer.
First of all, install IIS (Internet Information Server). To do this, open the “Add or Remove Programs” window and select “Install Windows components" (Some Windows versions don't assume installing IIS, for example Windows XP Home Edition.)
Note: It is better to install the IIS server before the .Net Framework, otherwise you will have to configure IIS to support .Net applications by running the utility command line aspnet_regiis.exe (with the /i flag).
Create a virtual directory. If you are using Windows XP Pro, go to "Control Panel -> Administrative Tools -> Internet Information Services". In the window that opens, select “Action -> Create -> Virtual Directory”.
The Virtual Directory Creation Wizard will launch. Specify Soap1 as the alias and set the path to the directory where you want to place the service, for example C:\Soap1. Now copy the contents of our web service there.
Dial in address bar browser http://localhost/soap1/Service.asmx and you should see the service testing page (see Figure 2).
Viewing SOAP Messages
The testing page does not allow you to send or read SOAP messages. For this reason, you will have to use third-party developments; I recommend using soapUI. (This is a free product available at http://www.soapui.org.)
After installing soapUI, create a new project called soap1, leaving the Initial WSDL field empty (see Figure 3).
Right-click on the newly created project and select “Add WSDL from URL”. In the dialog box that opens, enter http://localhost/soap1/Service.asmx?wsdl. We now have the ability to send SOAP requests to our service and view the responses received. (Requests will be generated automatically by soapUI.)
What is this WSDL? A WSDL document describes how clients can interact with a web service. It describes which service methods are available for external call, what parameters they accept and what they return, as well as other information necessary for remote interaction. Such a document can be created manually, or you can entrust its generation to the server; to do this, just add the ?wsdl suffix to the URL pointing to the *.asmx file.
To view the WSDL document of our service, enter http://localhost/soap1/Service.asmx?wsdl in your browser. SoapUI uses the information from this document to automatically generate SOAP requests.
SOAP Extensions
As you've probably noticed, to create an XML web service (as well as a client), you don't necessarily need to care about the type of SOAP messages. It is enough to mark the necessary methods with the attribute, and the ASP.NET runtime itself will compose packages of the required format.
In Fig. Figure 4 shows the web service request and response received using the soapUI program.
Let's repeat it again. The request is generated by soapUI - when creating real clients for the service, you also do not need to manually format SOAP packets. We also did not directly participate in creating the service response. All this happens automatically.
However, it is likely that you will need to modify these packages yourself. For example, compress or encrypt the transmitted data. This is the purpose of SOAP Extensions.
SOAP Extensions is a mechanism that allows you to customize the received and sent SOAP messages.
"Path" of a SOAP message
To begin programming, you need to consider the path that a SOAP message takes before it is received and processed by the appropriate method (see Figure 5).
A SOAP message can be thought of as an XML document that describes an object being transmitted over a network. Before using the object passed in this way, it must be restored (or, if you prefer, assembled) from this description. An XML serializer serves this purpose.
Incoming packets undergo deserialization (recovery of an object from an XML description), and sent packets undergo serialization (creation of an XML description of an object).
In Fig. Figure 5 shows four points (BeforeSerialize, AfterDeserialize, BeforeDeserialize, AfterSerialize) at which we, using SOAP Extensions, can intercept a SOAP message. Modify it and send it further.
Implementing SOAP Extension
First, let's define the task: let's say we want to change the SOAP packets sent by the web service as shown in Listing 7:
Listing 7. Old and new XML web service responses
Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> Ciphertext
Action plan for implementing SOAP Extension:
- We create a dll with a class inherited from SoapExtension.
- We add a bin folder to our web service and put the created dll there.
- We add the web.config file to the service and make the necessary changes to it.
We'll look at the role of the bin folder and the web.config file later.
Creating a DLL with SOAP Extension
Create a new "Class Library" project called SoapExtensionLib. In this project, we only need to implement one class that will perform the SOAP package modifications we need. This class must inherit from the SoapExtension class.
Listing 8. Creating a class that inherits from SoapExtension
using System;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.IO;
using System.Net;
using System.Xml;
Each SOAP Extension receives as a parameter a stream containing the object being transferred over the network (before or after serialization). And it must return the stream.
A SOAP Extension can be thought of as a “box” that can be placed at one or all of the four points (BeforeSerialize, AfterDeserialize, BeforeDeserialize, AfterSerialize) shown in Fig. 5. At each point there can be any number of such “insets” (see Fig. 6).
To obtain these streams, the ChainStream method is used.
Listing 9. Implementation of the ChainStream method
public class TraceExtension: SoapExtension
Stream wireStream;
Stream appStream;
// method as input parameter
// receives a stream containing the passed object
Public override Stream ChainStream(Stream stream)
WireStream = stream;
AppStream = new MemoryStream();
Return appStream;
…
At the BeforeDeserialize point, the wireStream contains the SOAP request received from the network. This SOAP request needs to be passed to the application stream (appStream).
And at the AfterSerialize point, you need to pass the SOAP response sent to the network to the wireStream stream, which will be located in appStream.
To work with threads at each of the four points, you need to implement the ProcessMessage method.
Listing 10. Implementation of the ProcessMessage method that does not modify SOAP messages
// ProcessMessage performing mandatory copying
// threads at two points (BeforeDeserialize and AfterSerialize)
Switch (message.Stage)
// at the BeforeDeserialize point you must pass
// SOAP request from a network stream (wireStream)
// to the application stream (appStream)
Case SoapMessageStage.BeforeDeserialize:
Copy(wireStream, appStream);
AppStream.Position = 0;
Break;
// at the AfterSerialize point you need to pass
// SOAP response from application thread to network thread
AppStream.Position = 0;
Break;
void Copy(Stream from, Stream to)
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
Writer.WriteLine(reader.ReadToEnd());
Writer.Flush();
Listing 10 can be taken as a blank for further experiments. This implementation of the ProcessMessage method makes no sense - the outgoing SOAP response is not modified in any way. Let's fix this:
Listing 11. Implementation of the ProcessMessage method that modifies a SOAP response
public override void ProcessMessage(SoapMessage message)
Switch (message.Stage)
Case SoapMessageStage.AfterSerialize:
WriteOutput(message);
Break;
// part of the code has been cut to save space
// rewrite the SOAP response
public void WriteOutput(SoapMessage message)
AppStream.Position = 0;
// create an XML document from the stream
XmlDocument document = new XmlDocument();
Document.Load(appStream);
// To use XPath you need to define
// NamespaceManager
XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);
Nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
XmlNode ResultNode = document.SelectSingleNode("//soap:Body", nsmgr);
// replace the contents of the node
ResultNode.InnerText = "ciphertext";
// clear the stream and write a new SOAP response to it
AppStream.SetLength(0);
AppStream.Position = 0;
Document.Save(appStream);
// REQUIRED ACTION
// send a SOAP response from the application stream (appStream)
// to the network stream (wireStream)
AppStream.Position = 0;
Copy(appStream, wireStream);
Next, we need to define two methods (one of which is overloaded, i.e., can be called with different sets of parameters), which in our case are not needed. However, we must define them according to the rules of inheritance from the SoapExtension class.
Listing 12. Other mandatory methods
// According to the rules of inheritance, we must
// define these methods, but we don't use them in any way
public override object ?
GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
Return null;
public override object GetInitializer(Type WebServiceType)
Return null;
public override void Initialize(object initializer)
Return;
That's it, let's compile the project. Finally we got a dll with SOAP Extension. The full listing of SoapExtensionLib.dll is on the magazine's website in the "Source Code" section.
Configuring a web service to work with SOAP Extension
Again, open our XML Web Service project using Visual Studio. Click "WebSite -> Add Reference" and select the SoapExtensionLib.dll you created earlier.
The Bin folder will be automatically added to the project. The application automatically links to *.dll files located in the Bin folder.
Now put the following Web.Config file in the web service directory:
Listing 13. Web.Config file
Priority="1" Group="0" />
Now the structure of our service looks like shown in Fig. 7. Using the Web.Config file, we inform the ASP.NET environment that we have added an XML Soap Extension to the web service, implemented in the TraceExtension class which is located in the SoapExtensionLi.dll file. Listing 14. The webServices section in the Web.Config file Priority="1" Group="0" />
As you already know, you can make multiple SOAP Extensions, and the stream carrying the passed object (before or after serialization) will pass through each of them. The order in which a flow traverses different SOAP Extensions is specified using the priority and group attributes. It is worth noting that by configuring Web.Config in this way, we inform the environment that our SOAP Extension will be called for each service method marked with the attribute. It is possible to create your own attribute and mark with it only those methods for which you need to call the SOAP Extension. Listing 15. Example of using a custom attribute public string HelloWorld() ( Return "Hello World"; To do this, you need to add a class inherited from SoapExtensionAttribute to SoapExtensionLi.dll (see Figure 8). Conclusion This article reflects the main points of the construction and operation of XML web services on the .Net platform. I hope that the material presented will be sufficient so that, if necessary, you can engage in a more in-depth study of the topic. In contact with In general, today there are standard XML data exchange protocols: SOAP (service oriented architecture, a set of loosely coupled services interacting with each other) is based on RPC. The main advantage of RPC is the small number of network resources (entry points) and the many methods involved. Despite this advantage, RPC is an outdated protocol that has a number of disadvantages: All these shortcomings were solved in XML Schema. This is the industry standard for describing an XML document. Those. it is a way to model arbitrary data. An XML schema can describe a model (relationships between elements and attributes, and their structure), data types (characterizes data types) and a dictionary (names of elements and attributes). Based on all the shortcomings of XML-RPC, the SOAP protocol was created. SOAP(Simle Object Access Protocol) - access protocol to an object (to the entry point). Today it is the main industry standard for building distributed applications. It represents extensions to the XML-RPC language. Those. it is built on the principle: 1 entry point and any methods. The protocol itself in terms of transport (how to transfer data) gives a wide choice: SMTP, FTP, HTTP, MSMQ. SOAP underlies the implementation of XML web services (XML web services). The disadvantage of SOAP is that it is difficult to learn. SOAP is based on the exchange of messages between a client and a server (synchronously and asynchronously). Each message carries information about the data (what data is transmitted and received). SOAP describes in advance the entire structure of a message using XML schemas: what should be in the message, how it will be transmitted. This makes it possible, without knowing the server, to understand what is happening there, and allows the server to check whether this message is for it. The purpose of a schema is to describe the structure of the data, i.e. what we have. All data is divided into simple and complex types (scalars and structures). A simple type (string, number, boolean, date) will never contain anything inside. And a structure (object) can contain properties. SOAP message structure: WSDL(Web Services Description Language) - language for describing web services. Used in SOAP. This is a kind of document that describes everything: what namespaces were used, what data schemes were used, what types of messages the server expects from the client, what envelopes belong to what method, what methods exist, what address to send to, etc. Actually, WSDL is a web service. It is enough for the client to study the contents of this document; he already knows everything about the server. Any server must publish WSDL. WSDL consists of blocks: Lyrical part. Imagine that you have implemented or are implementing a certain system that should be accessible from the outside. Those. there is a certain server with which you need to communicate. For example a web server. This server can perform many actions, work with the database, perform some third-party requests to other servers, do some calculations, etc. live and possibly develop according to the scenario known to him (i.e. according to the developers’ scenario). It is not interesting for a person to communicate with such a server, because he may not be able/want to provide beautiful pages with pictures and other user-friendly content. It is written and works to work and provide data when asked to it, without worrying that it is human readable, the client will deal with it himself. Other systems, accessing this server, can already dispose of the data received from this server at their own discretion - process, accumulate, issue to their clients, etc. Well, one of the options for communicating with such servers is SOAP. SOAP xml message exchange protocol. Practical part. A web service (this is the name of what the server provides and what clients use) makes it possible to communicate with the server with clearly structured messages. The fact is that the web service does not accept any data. The web service will respond with an error to any message that does not comply with the rules. The error, by the way, will also be in xml form with a clear structure (which is not true about the text of the message). WSDL (Web Services Description Language). The rules by which messages are composed for the web service are also described using xml and also have a clear structure. Those. If a web service provides the ability to call a method, it must allow clients to know what parameters are used for this method. If the web service expects a string for Method1 as a parameter and the string should be named Param1, then these rules will be specified in the web service description. Not only simple types, but also objects and collections of objects can be passed as parameters. The description of an object comes down to a description of each component of the object. If an object consists of several fields, then each field is described, its type, name (what are the possible values). Fields can also be of a complex type, and so on until the description of the types ends with simple ones - string, boolean, number, date... However, some specific types may turn out to be simple, it is important that clients can understand what values they may contain. For clients, it is enough to know the url of the web service; the wsdl will always be nearby, from which you can get an idea of the methods and their parameters that this web service provides. What are the advantages of all these bells and whistles: The description, which has a clear structure, is readable by any soap client. Those. whatever the web service, the client will understand what data the web service receives. Using this description, the client can build its own internal structure of object classes, the so-called. binding" and. As a result, the programmer using the web service has to write something like (pseudocode): NewUser:=TSoapUser.Create("Vasya","Pupkin","admin"); soap.AddUser(NewUser); Automatic validation. There are also a lot of disadvantages: As an example, there is an open web service belavia: You can manually create and send a request like: POST /TimeTable/Service.asmx HTTP/1.1 Host: 86.57.245.235 Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://webservices.belavia.by/GetAirportsList"
the answer will come: HTTP/1.1 200 OK Date: Mon, 30 Sep 2013 00:06:44 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 4.0.30319 Cache-Control: private, max -age=0 Content-Type: text/xml; charset=utf-8 Content-Length: 2940
PS Previously, the Aeroflot web service was opened, but after 1C added soap support to 8ku, a bunch of 1C beta testers successfully installed it. Now something has changed there (I don’t know the address, you can look it up if you’re interested). XML schema
Basic SOAP Operations
WSDL
ZZY Disclaimer. He spoke at the everyday level. You can kick.