Search Unity

Soap C#

Discussion in 'Editor & General Support' started by wvd_vegt, May 18, 2009.

  1. wvd_vegt

    wvd_vegt

    Joined:
    Jan 15, 2009
    Posts:
    48
    Hi

    Does anyone have a suggestion for accessing a soap webservice from Unity C# (without the proxy dll's if that is a problem in the webplayer).

    JScript would also be fine as long as I'm able to access the results from within C#.

    The only libraries and samples I seem to encounter during Google searches are the one with a 'wdsl.exe' generated stub/dll or samples using 'system.web.services' which is not present in unity3D v2.5.
     
  2. wvd_vegt

    wvd_vegt

    Joined:
    Jan 15, 2009
    Posts:
    48
    Hi,

    I found a lot of code concerning the WWW and WWWForm object. My major problem is that soap calls expect HTTP POST content. The question is how do I get either the WWW or WWWForm object to post headers and a body.

    WWWForm.AddBinaryData (used in a lot of examples) isn't usefull as it needs a (form)field name to attach the binary data too.

    And unfortunatly, the WWWForm.data property is read-only, so of no use either.

    My code (simplyfied)

    Code (csharp):
    1.  
    2.  WWWForm form = new WWWForm();
    3.  form.AddField("Content-Type", "application/soap+xml; charset=utf-8");
    4.  
    5.  WWW www = new WWW (url, envelope, form.headers);
    6.  Debug.Log("Data2: "+ enc.GetString(envelope));
    7.  
    8.  //Wait until [url]www.iDone[/url] etc.
    9.  
    Any suggstions?
     
  3. wvd_vegt

    wvd_vegt

    Joined:
    Jan 15, 2009
    Posts:
    48
    Hi,

    Got some code working but are left with some mysteries I cannot find answers to on this forum.

    The code below is a combination of variosu pieces of code I found on the forum (thanks all for posting!) and features synchronous and asynchronous retrieval of a soap response (no encoding / decoding is done yet on the xml envelopes).

    The problems still bugging me:

    1) When I remove the line
    Debug.Log("I'm waiting... ");
    in IEWaitaSec, the Async request hangs and never returns.
    2) The async mode logs the same timestamp twice for before and after the request. There should be at least some difference.
    3) The async mode fails in the browser (IE8) but works in the Standalone Windows Executable.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. using System.Collections;
    5.  
    6. public partial class SoapDemo : MonoBehaviour {
    7.  
    8.     private Rect clientrect;
    9.    
    10.     /*
    11.     <?xml version="1.0" encoding="utf-8"?>
    12.     <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    13.         <soap:Body>
    14.             <ZipCodeToDetails xmlns="http://www.jasongaylord.com/webservices/zipcodes">
    15.                 <ZipCode>12345</ZipCode>
    16.             </ZipCodeToDetails>
    17.         </soap:Body>
    18.     </soap:Envelope>
    19.     */
    20.    
    21.     public delegate void Callback( string data, string error );
    22.  
    23.     private WWW CreateRequest(string url) {
    24.         //Debug.Log("Requesting from "+url);
    25.         //DebugConsole.IsOpen = true;
    26.  
    27.         string envelope =
    28.             "<?xml version="+'\"'+"1.0"+'\"'+" encoding="+'\"'+"utf-8"+'\"'+"?>\r\n"+
    29.             "<soap:Envelope xmlns:soap="+'\"'+"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>\r\n"+
    30.             "<soap:Body>\r\n"+
    31.             "<ZipCodeToDetails xmlns='http://www.jasongaylord.com/webservices/zipcodes'>\r\n"+
    32.             "<ZipCode>12345</ZipCode>\r\n"+
    33.             "</ZipCodeToDetails>\r\n"+
    34.             "</soap:Body>\r\n"+
    35.             "</soap:Envelope>\r\n";
    36.        
    37.         Hashtable headers = new Hashtable();
    38.        
    39.         //Official Content-Type "application/soap+xml;" might give a 415 Unsupported Media Type error !
    40.         //headers["Content-Type"] = "application/soap+xml;";
    41.         headers["Content-Type"] = "text/xml;";
    42.        
    43.         //Use the following line to 'fake' IE7 on WinXP SP2.
    44.         //headers["User-Agent"] = "/4.0 (compatible; MSIE 7.0; Windows NT 5.1) ";
    45.  
    46.         // send the data via web
    47.         return new WWW (url, System.Text.Encoding.UTF8.GetBytes(envelope), headers);       
    48.     }
    49.    
    50.     public string RequestSync(string url, float timeout) {
    51.         Debug.Log("Start Sync URL request: "+Time.time.ToString()+" seconds");
    52.  
    53.         WWW www = CreateRequest(url);
    54.         float stop = Time.time+timeout;
    55.  
    56.         while ((![url]www.isDone[/url])  (stop > Time.time)) {  
    57.             StartCoroutine(IEWaitaSec(www, stop));
    58.         }      
    59.        
    60.         Debug.Log("Finished Sync URL request: "+Time.time.ToString()+" seconds");
    61.  
    62.         if ([url]www.isDone[/url]) {
    63.             return [url]www.data;[/url]
    64.         }
    65.        
    66.         return "n/a";
    67.     }
    68.  
    69.     public void RequestAsync(string url, float timeout) {
    70.         RequestAsync(url, timeout, null);
    71.     }
    72.    
    73.     public void RequestAsync(string url, float timeout, Callback callback) {
    74.         Debug.Log("Start Async URL request: "+Time.time.ToString()+" seconds");
    75.  
    76.         //Does not wait for the request we need (so data is returned to early)!!
    77.         StartCoroutine (IEWaitForData(CreateRequest(url), Time.time+timeout, callback));
    78.     }
    79.  
    80.     private IEnumerator IEWaitaSec(WWW www, float stop) {
    81.         //NOTE: We need the Debug log or the program will hang... why?
    82.         Debug.Log("I'm waiting... ");
    83.        
    84.         while ((![url]www.isDone[/url])  (stop > Time.time)) {  
    85.             //Yield simply returns values for the iterator!
    86.             yield return new WaitForFixedUpdate();
    87.         } // while
    88.     }
    89.    
    90.     private IEnumerator IEWaitForData(WWW www, float stop, Callback callback) {
    91.         while ((![url]www.isDone[/url])  (stop > Time.time)) {  
    92.             //Yield simply returns values for the iterator!
    93.             yield return new WaitForEndOfFrame();
    94.         } // while
    95.        
    96.         if (![url]www.isDone[/url]) {
    97.             // print message to the debug log
    98.             Debug.Log ("Timeout: [" +stop+"]");
    99.         } else if (www.error!=null) {
    100.             // print the server answer on the debug log
    101.             Debug.Log ("Error: [" +www.error+"]");
    102.         } else {           
    103.             Debug.Log ("Data: [" +www.data+"]");
    104.         }
    105.  
    106.         Debug.Log("Finished Async URL request: "+Time.time.ToString()+" seconds");
    107.        
    108.         //Use the following code to retrieve data only stored in the bytes property and not in the data property (due to encoding issues).
    109.         //System.Text.Encoding enc = System.Text.Encoding.ASCII;
    110.         //enc.GetString([url]www.bytes[/url])+     
    111.  
    112.         if(callback != null) {
    113.             callback([url]www.data[/url], [url]www.error[/url]); // Executes Callback, passes in retrieved data
    114.             callback = null;
    115.         }
    116.     } // sendData
    117.  
    118.     //Put global code here (whats put outside of functions in JScript.
    119.     public void Awake () {
    120.         //
    121.     }
    122.    
    123.     // Use this for initialization
    124.     void Start () {
    125.         DebugConsole.IsOpen = true;
    126.     }
    127.    
    128.     // Update is called once per frame
    129.     void Update () {
    130.         //
    131.     }
    132.    
    133.     private string data = "";  
    134.     private string error = ""; 
    135.     void GetData(string data, string error)
    136.     {
    137.         this.data = data;  
    138.         this.error = error;
    139.     }
    140.    
    141.     public void OnGUI () {
    142.         if (GUI.Button (new Rect (10,10,150,30), "Send Sync Request")) {
    143.             data = "";
    144.            
    145.             data = RequestSync("http://www.jasongaylord.com/webservices/zipcodes.asmx",1); //?WSDL
    146.            
    147.             Debug.Log(data);
    148.         }
    149.        
    150.         if (GUI.Button (new Rect (10,45,150,30), "Send Async Request")) {
    151.             data = "";
    152.            
    153.             RequestAsync("http://www.jasongaylord.com/webservices/zipcodes.asmx", 10, GetData); //?WSDL
    154.            
    155.             Debug.Log(data);
    156.         }
    157.  
    158.         clientrect.x =10;
    159.         clientrect.y =90;
    160.         clientrect.width =150;
    161.         clientrect.height =30;
    162.                
    163.         //Set Content...
    164.         //GUI.Label(clientrect, String.Format("Time: {0}", DateTime.Now.ToString("HH:mm:ss")));
    165.         GUI.Label(clientrect, data);       
    166.     }
    167.    
    168.     public void OnApplicationQuit() {
    169.         // 
    170.     }
    171. }
    172. [/code/
     
  4. sperry

    sperry

    Joined:
    Apr 24, 2009
    Posts:
    13
    Same problem here.
    And no answer in the forum...

    Have you tried the using the webservices with the HTTP GET interface instead the SOAP one?

    http://www.w3.org/TR/wsdl#_http-e

    We have not tried it yet, but it is feasible to implement something quite simple with the WWW class and the GET way of calling the webservices, and since it does not uses SOAP it should be easier to code.
     
  5. wvd_vegt

    wvd_vegt

    Joined:
    Jan 15, 2009
    Posts:
    48
    Hi,

    I have something working now (it uses post only fails when I use synchronous mode in a browser app).

    The C# script accepts a hashtable with 'parameter=value' pairs as input and performs the request after whch it returns another hashtable with the results found.

    I'm currently testing tweaking it a bit more and will post it once it's working against more than one service.
     
  6. wvd_vegt

    wvd_vegt

    Joined:
    Jan 15, 2009
    Posts:
    48
    Hi

    Attached is a first version of a Soap Object that can be used to access various services without the need to generate dll's.

    For passing parameters and results it uses a treelike datastructure that allows complex data to be added without using xml. For obtaining results an xpath query is used to determine the exact location of the results in the response envelope.

    The object hides all the details of the soap call. It can return either a single records or an array of records.

    For the Bing Demo you need a valid developer BingAppId or you will receive a Soap Error.
     

    Attached Files:

  7. jpcampbell

    jpcampbell

    Joined:
    Sep 25, 2009
    Posts:
    6
    Hi,

    Thanks for putting this together. I'm trying to build this to take a look to see if it meets my needs. I'm trying it on Unity iPhone 1.5. Is there anything special I need to do to get it to build?

    When I include those in a folder the Assets directory, I get the following output. Any ideas?

    Assets/Scripts/GuiScript.cs(5,55): error CS1041: Identifier expected (Filename: Assets/Scripts/GuiScript.cs Line: 5)
    Assets/Scripts/SoapObject.cs(8,55): error CS1041: Identifier expected (Filename: Assets/Scripts/SoapObject.cs Line: 8)
    Assets/Scripts/_SimpleSubtree.cs(19,31): error CS1518: Expected `class', `delegate', `enum', `interface', or `struct' (Filename: Assets/Scripts/_SimpleSubtree.cs Line: 19)
    Assets/Scripts/_SimpleTree.cs(19,28): error CS1518: Expected `class', `delegate', `enum', `interface', or `struct' (Filename: Assets/Scripts/_SimpleTree.cs Line: 19)
    Assets/Scripts/_SimpleTreeNode.cs(20,32): error CS1518: Expected `class', `delegate', `enum', `interface', or `struct' (Filename: Assets/Scripts/_SimpleTreeNode.cs Line: 20)
    Assets/Scripts/_SimpleTreeNodeList.cs(20,36): error CS1518: Expected `class', `delegate', `enum', `interface', or `struct' (Filename: Assets/Scripts/_SimpleTreeNodeList.cs Line: 20)
     
  8. wvd_vegt

    wvd_vegt

    Joined:
    Jan 15, 2009
    Posts:
    48
    Hi,

    This is all there is. It almost seems like the iphone's mono version does not handle generics or the alias made with the using statement on line 5/6/7 of guiscript and others.

    Only thing that can be done (if the iphone supports generics but not the aliassing) is to expand all aliasses to the full name. It will make the code somewhat harder to read.
     
  9. Vishal_ARC

    Vishal_ARC

    Joined:
    Feb 19, 2015
    Posts:
    2
    Hi,

    Is there any way to do it in ios(iPhones & iPads)?, like plugin or any.....please
     
    fredericoraiss likes this.