Thursday, May 6, 2010

Calling PHP SOAP Server from C#/.NET Client

So SOAP Web Services is a pretty mature technology now, and performing cross-language service calls should be a breeze, right? In utopia, yes - unfortunately we live in the real world. I did finally make it work but it took me a day and a half, so I thought I'd share my experience here.
There are other guides on the net that focuse on NuSOAP, like this one on Sanity Free Coding, but I prefer to use the stock SOAP library in PHP5 so that's the focus for this guide.


The server: WSDL or non-WSDL-mode?

As of now, the PHP5 SOAP extension does not support auto-generating WSDL as the .Net Framework does. But it does support a non-WSDL mode. That creates an issue though, because Visual Studio relies on WSDL files in order to create the client reference as illustrated below.



To make a long story short, I never got non-WSDL mode to work with .NET although I got pretty close, but then I relied on a dummy WSDL on the development computer just to fool Visual Studio into creating the proper service reference. So I needed the WSDL anyway.


If you're not proficient in WSDL-hacking, do what I did: Create a dummy .NET Web Service project with the method shells as intended for the PHP server. In my example here I'm going to create a simple service with one input and one output variable. The method TimesTwo doubles the integer input value and returns the result. In C# the code looks like this:


[WebService(Namespace = "http://myservice.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    public class SomeService : System.Web.Services.WebService
    {
        [WebMethod]
        public int TimesTwo(int value)
        {
            return 0;
        }
    }
This I implemented in my dummy web service project. I have not implemented the business logic in the body - I only do as much as I need in order for the service to compile. I then get the WSDL by launching the app and adding ?WSDL to the URL. In my case, this became http://localhost:7048/SomeService.asmx?WSDL. Save this file for later use at the PHP server.

The Client

Now over to the client. I'm creating a simple Windows Forms app which takes an input, allows the user to trigger the web service call and displays the output. See screenshot below.


Add a service reference to the solution by pointing to the local dummy project. It would be a good idea to also test the client in this phase and see that the dummy server returns the value zero. The client is really the easy part, so I'm moving over to the juice.

The PHP server

I'm not going into detail on installation and configuration. Consult the PHP SOAP manual for this.Now make sure you upload the WSDL file to the server. Let's assume you call it "SomeService.wsdl" and place it in the same folder as the server file itself. This is the code you need to provide the desired functionality:


<?php
 ini_set("soap.wsdl_cache_enabled", "0");
 $server = new SoapServer("SomeService.wsdl");
 $server->addFunction("TimesTwo");
 $server->handle();
 
 function TimesTwo($valueObj) 
 {   
  // Unwrap input data
  $valueArr = get_object_vars($valueObj);
  $value = $valueArr["value"];  
  // Perform business operations
  $result = $value * 2; 
  // Wrap and return the result
  return array("TimesTwoResult" => $result);
 }  
?>

Now the tricky part was understanding how .NET wrapped the input data and how it expected the return data to be wrapped. Some Googling lead me to the answer on the return value. A bit of trial and error and with aid of the serialize() function, I figured out the input data. Note that the string literal ("TimesTwoResult") on the return line needs to to match the result specification in the WSDL. Similar, the "value" property in the input object is the name of the first input parameter.
Now that's all there is to it!

Download source code.








11 comments:

  1. i'm noob in c#, maybe you ask me? I'm recived array data in the soap envelop, but string s1 = client.TimesTwo("foo");

    string input = InputTextBox.Text;
    ResultTextBox.Text = s1;

    - -------this code snipet return just first element of soap complex type array-----
    How can i fetch all elements? for example 10 items?
    Thak you

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Sorry for late answer. How is your PHP code implemented? Are you saying you are returning an array of String's? If so, try changing the method signatur in C# to "String[]" or "List<String<"

      Delete


  3. شركة نقل عفش
    اهم شركات مكافحة حشرات بالخبر كذلك معرض اهم شركة مكافحة حشرات بالدمام والخبر والجبيل والخبر والاحساء والقطيف كذلك شركة رش حشرات بالدمام ومكافحة الحشرات بالخبر
    شركة مكافحة حشرات بالدمام
    شركة تنظيف خزانات بجدة الجوهرة من افضل شركات تنظيف الخزانات بجدة حيث ان تنظيف خزانات بجدة يحتاج الى مهارة فى كيفية غسيل وتنظيف الخزانات الكبيرة والصغيرة بجدة على ايدى متخصصين فى تنظيف الخزانات بجدة
    شركة تنظيف خزانات بجدة
    شركة كشف تسربات المياه بالدمام
    شركة نقل عفش واثاث

    ReplyDelete


  4. شركة نقل عفش بالرياض وجدة والدمام والخبر والجبيل اولقطيف والاحساء والرياض وجدة ومكة المدينة المنورة والخرج والطائف وخميس مشيط وبجدة افضل شركة نقل عفش بجدة نعرضها مجموعة الفا لنقل العفش بمكة والخرج والقصيم والطائف وتبوك وخميس مشيط ونجران وجيزان وبريدة والمدينة المنورة وينبع افضل شركات نقل الاثاث بالجبيل والطائف وخميس مشيط وبريدة وعنيزو وابها ونجران المدينة وينبع تبوك والقصيم الخرج حفر الباطن والظهران
    شركة نقل عفش بجدة
    شركة نقل عفش بالمدينة المنورة
    شركة نقل اثاث بالرياض
    شركة نقل عفش بالدمام

    ReplyDelete
  5. Forex Signals, MT4 and MT5 Indicators, Strategies, Expert Advisors, Forex News, Technical Analysis and Trade Updates in the FOREX IN WORLD

    Forex Signals Forex Strategies Forex Indicators Forex News Forex World

    ReplyDelete
  6. Shield Security Solutions Provides Ontario Security Training, Security Guard License or Security License in Ontario. Get Started Today

    ReplyDelete