PHP SOAP-Webservice mit NuSOAP für .NET 4.0 WCF Client und WP7

Die Anforderung war, eine Windows Phone 7 App zu bauen, welche über einen SOAP Webservice mit einer PHP Seite kommuniziert.
Für den Webservice habe ich NuSOAP verwendet.
Das funktioniert für .NET 2.0 Webservice Clients auch wunderbar – nur für >.NET2.0 WCF Clients muss man das ein oder andere beachten…

Als erstes muss man wissen, dass sämtliche Kommunikation bei WCF in UTF-8 passiert.
Das ist auch grundsätzlich gut so, denn wenn alle UTF-8 benutzen, haben wir keine Zeichensatz-Probleme mehr 🙂

Außerdem hat NuSoap einen kleinen Fehler in der Reihenfolge der XML-Reigenfolge eines Fehlers, falls dieser ausgegeben werden soll – WCF kommt mit dieser Reigenfolge nicht klar.
Diesen Fehler kann man einfach korrigieren, indem man in der nusoap.php in der Funktion „serialize()“ die Zeilen 1066 und 1067 tauscht.
Die Korrekte Reihenfolge sieht dann so aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?
//...
	function serialize(){
		$ns_string = '';
		foreach($this->namespaces as $k => $v){
			$ns_string .= "\n  xmlns:$k=\"$v\"";
		}
		$return_msg =
			'<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
			'<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
				'<SOAP-ENV:Body>'.
				'<SOAP-ENV:Fault>'.
					$this->serialize_val($this->faultcode, 'faultcode').
					$this->serialize_val($this->faultstring, 'faultstring').
					$this->serialize_val($this->faultactor, 'faultactor').
					$this->serialize_val($this->faultdetail, 'detail').
				'</SOAP-ENV:Fault>'.
				'</SOAP-ENV:Body>'.
			'</SOAP-ENV:Envelope>';
		return $return_msg;
	}
//...
?>

Dann wird in den meisten Foren und Tutorials gesagt das .NET nur document/literal kann.
Diese Meinung unterstütze ich mit meiner gewonnenen Erfahrung nicht.
Standardmäßig verwendet so ein WebService „RPC/Encoded“.
Verucht man jetzt diesen „RPC/Encoded“ WebService als WCF-Dienstverweis in seine Anwendung einzubinden funktioniert dies zwar, aber im Intellisense tauchen die Webservice-Methoden nicht auf.
WCF Mag „RPC/Encoded“ also nicht.
Baut man den Webservice zu einen „document/literal“ WebService um, kann man diesen als WCF-Dienstverweis in das Projekt einbinden und die Webservice-Methoden erscheinen nun auch im Intellisense vom Visual Studio.
Alles schön!… denkt man… leider ist noch nicht alles schön.
Denn wenn man die Anwendung aufruft und die Methode des WebServices benutzen will, kommt ein Fehler „unable to serialize result“.
Was nun? Dieser Fehler ist ein Standard-Fehler des WebService an sich auf der PHP-Seite.
Warum dieser Fehler auftaucht? Keine Ahnung!
Aber nach insgesamt 8 Stunden Fehlersuche habe ich diesen Fehler lösen können, indem ich nicht „document/literal“ in meinem WebService verwendet habe, sondern „rpc/literal“.

Hier mein vollständiger NuSOAP-Test-Webservice:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
require_once('./lib_095/nusoap.php');
$server = new soap_server();
$server->configureWSDL('test_wsdl', 'urn:test_wsdl');
$server->wsdl->schemaTargetNamespace = 'urn:test_wsdl';
 
// Methode, die zum Test des Webservices dient																							
$server->register('test',               // method name		
    array('var' => 'xsd:string'),       // input parameters	
    array('return' => 'xsd:string'),    // output parameters	
    'urn:test_wsdl',                  	// namespace		
    'urn:test_wsdl#test',         	// soapaction		
    'rpc',                              // style			
    'literal',                          // use			
    'Test-Methode des Webservices'      // documentation		
);
 
function test($var) 
{
    return "Test bestanden,ubergebe Variable: $var";
}
 
// Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
 
?>

Damit dieser Webservice nun auch für den WCF-Client funktioniert, muss das HTTPBinding für den Aufruf in ein „BasicHTTPBinding“ geändert werden und die URL als Endpoint mit übergeben werden.

Das ganze sieht dann für eine Winform in etwa so aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
 
namespace wcftest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            BasicHttpBinding binding = new BasicHttpBinding();
            EndpointAddress endpoint =  new EndpointAddress("http://meinserver.de/soap/soaptest.php");
            ServiceReference1.test_wsdlPortTypeClient tester = new ServiceReference1.test_wsdlPortTypeClient(binding,endpoint);
 
            Console.WriteLine(tester.test("lalala"));
        }
    }
}

Diesen WebService kann man nun auch für einen Windows Phonne 7 WCF Client benutzen.
Dafür muss man allerdings wissen das WP7 bzw. Silverlight mit WebServices Asynchron Kommuniziert.
Man muss also den Event der Methode abwarten und kann dann daraus das Result verwenden.
Das ganze sieht dann für Windows Phone 7 wie fogt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.ServiceModel;
 
namespace WindowsPhoneTest
{
    public partial class start : PhoneApplicationPage
    {
        public start()
        {
            InitializeComponent();
        }
 
        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            BasicHttpBinding binding=new BasicHttpBinding();
            EndpointAddress endpoint = new EndpointAddress("http://meinserver.de/soap/soaptest.php");
            ServiceReference1.test_wsdlPortTypeClient test = new ServiceReference1.test_wsdlPortTypeClient(binding,endpoint);
 
            test.testCompleted += new EventHandler<ServiceReference1.testCompletedEventArgs>(test_testCompleted);
            test.testAsync("lalala");
        }
 
        void test_testCompleted(object sender, ServiceReference1.testCompletedEventArgs e)
        {
            MessageBox.Show(+e.Result);
        }
    }
}

Das war es auch schon!
Nun können wir PHP-Webservices, welche wir sehr einfach mit NuSoap bauen können auch mit WCF CLients ansprechen.

5 Responses to PHP SOAP-Webservice mit NuSOAP für .NET 4.0 WCF Client und WP7

  1.  

    Hi, ich hab noch ein paar Randinfos und Vor- und Nachteile mit NuSOAP unter PHP veröffentlicht: http://www.kammerath.net/php-und-soap.html … Vielleicht interessiert’s ja Jemanden 🙂 Vg, Jan

  2.  

    Hallo,

    ich bin recht neu in der Entwicklung von Windows Phone7. Woher bekomme ich das ServiceReference1 (Zeile 28) her? Wo ist die Deklaration? bzw. wie mache ich die?

    Danke schon mal für die Antworten. Auch wenn dieser Beitrag etwas älter ist, hilft er auch heute dem ein oder anderen.

  3. Hallo Andre,
    ServiceReference1 ist der Verweis zum Webservice.
    Dieser wird wie ein anderer normaler Verweis auch mit einem Rechtsklick im Projektmappen-Explorer unter „Verweise“->“Webverweise/Webdienste“ erstellt.

     
  4.  

    Hallo Leute,

    wie bekommt man den PHP mit nusoap dazu im UTF-8 zu antworten. Habe es mit:

    <?php
    header('Content-Type: text/xml; charset=UTF-8');
    require_once('./lib_095/nusoap.php');
    $server = new soap_server();

    versucht, aber VS2013 meldet immer, dass ISO-8859-1 geliefert wird.

    Viele Grüße

    Michael

  5.  

    Ok habs gerade selber gefunden. Bei der Def. des Webservices

    $server->soap_defencoding = ‚UTF-8‘;
    $server->decode_utf8 = false;
    $server->encode_utf8 = true;

    angeben.

    Viele Grüße

    Michael

leave your comment


*

Unterstütze den Frickelblog!