Il s’agit d’un exemple rudimentaire et je n’entre pas dans les détails, ni sur PHP, ni sur les services web. Le seul but de ce billet est d’illustrer un cas simple de création de service en PHP et de sa consommation en .NET sans “magie”.
Implémentation du service web en PHP
Cet exemple se base sur le tutoriel http://www.sanity-free.org/125/php_webservices_and_csharp_dotnet_soap_clients.html. Je m’en distingue par le fait que l’on n’utilisera pas la génération automatique de code avec la fonction Add Service Reference de VS.
Pré-requis
Le répertoire de la librairie nuSoap (version utilisée ici: 0.7.3) doit être placé à côté du fichier du script php qui suit.
Script PHP
1<?php
2
3require_once("nusoap/lib/nusoap.php");
4$namespace = "http://www.eric-bml.net/service";
5$server = new soap_server();
6$server->soap_defencoding = 'UTF-8';
7$server->configureWSDL("SimpleService");
8$server->wsdl->schemaTargetNamespace = $namespace;
9
10$server->register(
11 // method name:
12 'ProcessSimpleType',
13 // parameter list:
14 array('name'=>'xsd:string'),
15 // return value(s):
16 array('return'=>'xsd:string'),
17 // namespace:
18 $namespace,
19 // soapaction: (use default)
20 false,
21 // style: rpc or document.
22 'document',
23 // use: encoded or literal
24 'literal',
25 // description: documentation for the method
26 'A simple Hello World web method');
27
28// Get our posted data if the service is being consumed
29// otherwise leave this data blank.
30$POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA'])
31 ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
32
33// pass our posted data (or nothing) to the soap service
34$server->service($POST_DATA);
35//$server->service(utf8_encode($POST_DATA));
36exit();
37
38function ProcessSimpleType($who) {
39 return "Hello $who";
40}
41
42?>
Plusieurs remarques importantes
Espace de nom
Notez que l’espace de nom (namespace, ligne 4) est ignoré par nuSoap. Ce dernier retournera l’espace de nom de la requête dans sa réponse, c’est-à-dire celui qui sera défini dans notre contrat .NET un peu plus loin.
Format (style) des messages SOAP
La ligne 22 est importante: elle définit le style (nommé format dans .NET)
document. Par défaut, .NET s’attendra à ce format. Si vous choisissez rpc,
il faudra l’expliciter dans le contrat .NET.
Testez la page PHP
Avant de continuer, assurez-vous que la page PHP est bien accessible par un navigateur. Pour la suite, nous considérerons que le service est accessible à cette adresse:
Consommer le service dans un projet .NET
Il y a deux étapes :
-
Définir le contrat du service (une interface).
-
Instancier un client.
Contrat
Pour cet exemple simple, le projet du contrat ne contient qu’une interface :
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.ServiceModel;
6
7namespace Service.Contract
8{
9
10 [ServiceContract(Namespace = "http://www.eric-bml.net/service")]
11 public interface ITestService
12 {
13 [OperationContract]
14 [return: System.ServiceModel.MessageParameterAttribute(Name = "return")]
15 string ProcessSimpleType(string name);
16 }
17}
Remarquez bien la ligne 14. Sans elle, .NET retournera toujours une valeur
null.
Client
Le projet du client doit référencer le projet du contrat. Dans cet exemple, il s’agit d’une application Console:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Service.Contract;
namespace Service.Client
{
class Program
{
static void Main(string[] args)
{
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
EndpointAddress endPointAddr = new EndpointAddress("http://blog.eric-bml.net/public/phpservice/hello.service.php");
ITestService testService = new ChannelFactory<ITestService>(binding, endPointAddr).CreateChannel();
string message = testService.ProcessSimpleType("World");
if (message == null)
Console.WriteLine("Echec: la méthode a retourné null.");
else
Console.WriteLine("Réponse: '" + message + "'");
Console.ReadKey();
}
}
}
Si vous n’avez pas fait d’erreur, vous devriez obtenir “Réponse: ‘Hello World’”.
En cas de problème…
Les deux cas que j’ai rencontré sont:
-
une
CommunicationException(contenant une erreur SOAP), -
la valeur retournée est
null.
Dans le premier cas, il s’agit a priori de l’interface qui contient une erreur (par exemple, mauvais nom de méthode). Dans le second cas, et c’est le plus dur à déboguer, le problème se situe généralement au niveau de la désérialisation côté client. Il peut y avoir un problème d’espace de nom discordant (néanmoins, cela ne devrait pas arriver dans cet exemple car nuSoap s’adapte à l’espace de nom de la requête). Il peut s’agir d’une mauvaise configuration pour la désérialisation, notamment le format des messages (document ou RPC).
Si le service web est fonctionnel, une technique est d’utiliser Fiddler pour vérifier que le service retourne bien une réponse. Puis d’utiliser la fonction de génération de code de VS en fournissant l’adresse du service, suffixée de “?wsdl”. Enfin, d’éditer le fichier généré (caché par défaut) “Reference.cs” et de comparer les attributs du contrat généré avec le vôtre.
Références
http://www.scottnichol.com/nusoapintro.htm
http://www.sanity-free.org/125/php_webservices_and_csharp_dotnet_soap_clients.html