0

Problem:

I inherited a software where a C# windows service is called with PHP. It does not work properly so I am just getting started on WCF and SOAP.

My major problem is that I am not able to call the windows service using PHP and Soap. When I try it, PHP crashes.

I completed the microsoft tutorial: https://learn.microsoft.com/en-us/dotnet/framework/wcf/getting-started-tutorial When I use the C# client as described in the tutorial, everything works like charme. I added an Installer to make the whole program available as a Windows service. Long story short, in C# everything works as it is supposed to.

I assume that it just not configured correctly for the SOAP call. I already read through: http://www.rizalalmashoor.com/blog/calling-a-wcf-service-from-php/ but I still can't get it running.

Questions:

The source code is further below. I wanted to put my questions first:

1) I expose the service at the base address, right??

http://localhost:1234/GettingStartedLib/CalculatorService

2) The http end point is left empty. Is my soapURL in the PHP code correct?

3) Is there a way to debug the soap call? Even when I debug it in ZendStudio as a CLI application, I don't get any further information.

I am happy to provide further information if needed or something is not explained adequately.

  • Before someone answers: Soap is enabled in the php.ini. Already checked on that.

The source code:

PHP:

$soapURL = 'http://localhost:1234/GettingStartedLib/CalculatorService?wsdl';
$soapAttributes = array('soap_version' => SOAP_1_1);

$result = new SoapClient($soapURL, $soapAttributes);

The configuration of the WCF library:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
  </appSettings>
  <system.web>
    <compilation debug="true"/>
  </system.web>
  <!-- When deploying the service library project, the content of the config file must be added to the host's 
  app.config file. System.Configuration does not support config files for libraries. -->
  <system.serviceModel>
    <services>
      <service name="GettingStartedLib.CalculatorService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1234/GettingStartedLib/CalculatorService"/>
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address="" binding="basicHttpBinding" contract="GettingStartedLib.ICalculator">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <!-- Metadata Endpoints -->
        <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
        <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
  </startup>
</configuration>

The C# interface

namespace GettingStartedLib
{
    [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
    public interface ICalculator {
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
        [OperationContract]
        double Multiply(double n1, double n2);
        [OperationContract]
        double Divide(double n1, double n2);
        [OperationContract]
        string SoapCall();
    }
}

The C# service itself:

namespace GettingStartedLib
{
    public class CalculatorService : ICalculator
    {
        public double Add(double n1, double n2) {
            double result = n1 + n2;
            Console.WriteLine("Received Add({0},{1})", n1, n2);
            // Code added to write output to the console window.  
            Console.WriteLine("Return: {0}", result);
            return result;
        }

        public double Subtract(double n1, double n2) {
            double result = n1 - n2;
            Console.WriteLine("Received Subtract({0},{1})", n1, n2);
            Console.WriteLine("Return: {0}", result);
            return result;
        }

        public double Multiply(double n1, double n2) {
            double result = n1 * n2;
            Console.WriteLine("Received Multiply({0},{1})", n1, n2);
            Console.WriteLine("Return: {0}", result);
            return result;
        }

        public double Divide(double n1, double n2) {
            double result = n1 / n2;
            Console.WriteLine("Received Divide({0},{1})", n1, n2);
            Console.WriteLine("Return: {0}", result);
            return result;
        }
        public string SoapCall() => "SoapCall";
    }
}
NewToSoap
  • 19
  • 2
  • "PHP crashes" it seems that you need a PHP tutorial then, since you say that the c# side works correctly – Camilo Terevinto Feb 26 '18 at 12:36
  • What is the error? Wrap your PHP in try/catch and use this as the catch: `catch (SoapFault $fault) { echo(var_dump($fault)); }` – Crowcoder Feb 26 '18 at 13:02
  • Thanks for the input. Sometimes progress can be quite easy. I get the following error _SOAP-ERROR: Parsing WSDL: Couldn't load from ..._. It looks like a Windows issue. When I run a script with _file_get_contents('http://localhost:1234/GettingStartedLib/CalculatorService?wsdl');_, it says the computer denies permission even though I run the script in the console with administrator privileges. Am I missing something in the Windows configuration here? – NewToSoap Feb 26 '18 at 14:51
  • You can use a local file instead of a hosted wsdl if want to copy it to your file system where the php application can read it. – Crowcoder Feb 26 '18 at 15:01
  • The file is already located in my file system. I am glad that people take time and try to help but my first two questions aren't answered yet. The more I research the topic, the more I want these two questions to be anwsered. Moreover, if my assumptions are correct, what can still go wrong? – NewToSoap Feb 27 '18 at 09:06

1 Answers1

0

Solved the problem. I had to enter

<baseAddresses><add baseAddress="localhost:1234/GettingStartedLib/CalculatorService.vsc"/>
</baseAddresses>

Since I left the address of the http endpoint empty, the soap URL was localhost:1234/GettingStartedLib/CalculatorService.vsc?wsdl

NewToSoap
  • 19
  • 2