Very light weight XmlHttpRequest wrapper - Make synchronized web service calls again
Last post 05-01-2008 6:06 AM by vchoudhary. 19 replies.
Sort Posts:
03-13-2008 8:00 AM
Very light weight XmlHttpRequest wrapper - Make synchronized web service calls again

I used to send a notification message via web services when a user navigated away from my silverlight app, but with the shift to async services, the app would exit before my call had a chance to complete. So I took the time to write the following managed wrapper for XmlHttpRequest. It won't work in browsers that don't expose XmlHttpRequest, but it's better than nothing.

public class SyncToTheRescue

{

ScriptObject _XMLHttpRequest;

StringBuilder _Body;

XmlWriter _Writer;StringBuilder _Result = new StringBuilder();

 

public SyncToTheRescue(string url, string nspace, string method)

{

_XMLHttpRequest = HtmlPage.Window.CreateInstance("XMLHttpRequest");

_Body = new StringBuilder();

_Writer = XmlWriter.Create(_Result);

_XMLHttpRequest.Invoke("open", "POST", url, false);

_XMLHttpRequest.Invoke("setRequestHeader", "Content-Type", "text/xml; charset=utf-8");

_XMLHttpRequest.Invoke("setRequestHeader", "SOAPAction", string.Concat(nspace, method));

_Writer = XmlWriter.Create(_Result);

_Writer.WriteStartDocument();_Writer.WriteStartElement("soap", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");

 

_Writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");

_Writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");

_Writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/");

_Writer.WriteStartElement(null, method, nspace);

}public void AddArgument(string arg, string val)

{

_Writer.WriteStartElement(arg);

_Writer.WriteValue(val);_Writer.WriteEndElement();

}

public string Send()

{

_Writer.WriteEndDocument();

_Writer.Flush();

_XMLHttpRequest.Invoke("send", _Result.ToString());

ScriptObject dom = (ScriptObject)_XMLHttpRequest.GetProperty("responseXML");return (string)dom.GetProperty("xml");

}

}

//Here's how I use it:

SyncToTheRescue sttr = new SyncToTheRescue("KhetServices.asmx", "http://tempuri.org/", "LeaveRoom");

sttr.AddArgument("roomId", roomId);

sttr.Send();

jackbond

Loading...
Joined on 03-21-2007
Posts 385
03-13-2008 9:02 AM
Re: Very light weight XmlHttpRequest wrapper - Make synchronized web service calls again

Hey Jack, 

that's so cool, man... I'm gonna try your code.. thanks a lot for that..  Is it possible for you to attach the project?  

(If this has answered your question, please click on "Mark as Answer" on this post. Thank you!)

Best Regards,
Michael Sync

Blog : http://michaelsync.net
Feed : http://michaelsync.net/feed

mchlSync

Loading...
Joined on 09-16-2005
Singapore
Posts 2,220
03-13-2008 3:44 PM
Re: Very light weight XmlHttpRequest wrapper - Make synchronized web service calls again

mchlSync:
Is it possible for you to attach the project?

Sorry, I can't attach the entire project, you can see it though at www.ascendingintegration.com/khetdemo As far as I know, it's still the only multi-user online Silverlight game. I've tested "SyncToTheRescue" on Firefox 2.0.0.12 and IE7, but don't have access to a Mac. Any Mac users out there willing to test it out?

jackbond

Loading...
Joined on 03-21-2007
Posts 385
03-14-2008 5:56 PM
Re: Very light weight XmlHttpRequest wrapper - Make synchronized web service calls again

Thanks so much!

 I really hope that MS will put the option of making synchronous calls back into SL2 at some point, but until then, your code is a life saver.

ot42

Loading...
Joined on 05-03-2007
Posts 21
03-14-2008 7:31 PM
Re: Very light weight XmlHttpRequest wrapper - Make synchronized web service calls again

ot42:

Thanks so much!

 I really hope that MS will put the option of making synchronous calls back into SL2 at some point, but until then, your code is a life saver.

Thanks for the feedback, and I'm glad it's helping you out.

jackbond

Loading...
Joined on 03-21-2007
Posts 385
03-14-2008 9:43 PM
Re: Very light weight XmlHttpRequest wrapper - Make synchronized web service calls again
jackbond:
...but don't have access to a Mac. Any Mac users out there willing to test it out?
The code above also works using FF2 & Safari3 on mac os 10.4 and 10.5. Hope that helps, - John
JohnSpurlock

Loading...
Joined on 06-12-2007
Posts 27
03-15-2008 4:20 PM
How to make this just return an xml string (not even call a web service)?

Hey - this is great, thanks. I'm trying to make a simplied method - one that just downloads an xml file (doesn't even do the extra work of calling a web service). I was able to modify your code to work in IE, but it just returns null in fireFox. The goal is to have a single, sync, static method that just gets the xml file for you. For example, you request a local xml file on your own web server, specify the appropriate URL, and it returns the file content. Do you know what I'm doing wrong such that this doesn't work with FireFox?

    public static string DownloadXmlStringSync(string url)
    {

      ScriptObject _XMLHttpRequest;
      StringBuilder _Body;
      XmlWriter _Writer;
      StringBuilder _Result = new StringBuilder();

      try
      {
        _XMLHttpRequest = HtmlPage.Window.CreateInstance("XMLHttpRequest");

        _Body = new StringBuilder();
        _Writer = XmlWriter.Create(_Result);

        _XMLHttpRequest.Invoke("open", "GET", url, false);
        _XMLHttpRequest.Invoke("setRequestHeader", "Content-Type", "text/xml; charset=utf-8");

        _Writer = XmlWriter.Create(_Result);

        _Writer.WriteStartDocument();
        _Writer.WriteStartElement("soap", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
        _Writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
        _Writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
        _Writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/");

        _Writer.WriteEndDocument();

        _Writer.Flush();
        _XMLHttpRequest.Invoke("send", _Result.ToString());

        ScriptObject dom = (ScriptObject)_XMLHttpRequest.GetProperty("responseXML");
        string strXml = (string)dom.GetProperty("xml");
        return strXml;
      }
      catch (Exception ex)
      {
        throw;
      }

    }

Tim Stall
http://timstall.dotnetdevelopersjournal.com

timstallc

Loading...
Joined on 11-17-2007
Posts 36
03-15-2008 10:02 PM
Re: How to make this just return an xml string (not even call a web service)?

I have not tested this extensively. Let me know if it works for you. 

public static string DownloadXmlStringSync(string url)

{

ScriptObject request;

try

{

request = HtmlPage.Window.CreateInstance("XMLHttpRequest");

request.Invoke("open", "GET", url, false);

request.Invoke("send");return (string)request.GetProperty("responseText");

}

catch (Exception ex)

{

throw;

}

}

jackbond

Loading...
Joined on 03-21-2007
Posts 385
03-15-2008 10:49 PM
Re: How to make this just return an xml string (not even call a web service)?

Thanks for the reply. It works great in IE, but it still fails in FireFox. Except, now it throws an exception (instead of just returning null).

It fails on this line:

    _XMLHttpRequest.Invoke("send"); 

And throws this exception:

[System.InvalidOperationException] {System.InvalidOperationException: [ScriptObject_InvokeFailed]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=8.0.30226.2&File=System.Windows.Browser.dll&Key=ScriptObject_InvokeFailed
   at System.Windows.Browser.ScriptObject.Invoke(String name, Object[] args)
   at Stall.SilverlightUtilities.XmlHelper.DownloadXmlStringSync(String url)
   at Stall.Test.Page.Button_Click(Object sender, RoutedEventArgs e)} System.InvalidOperationException

I'd be appreciative for any ideas.

Thanks again,

 

Tim Stall
http://timstall.dotnetdevelopersjournal.com

timstallc

Loading...
Joined on 11-17-2007
Posts 36
03-15-2008 10:54 PM
Re: How to make this just return an xml string (not even call a web service)?

Which version of Firefox is it failing on? It worked for me on Firefox 3.

jackbond

Loading...
Joined on 03-21-2007
Posts 385
03-16-2008 12:00 AM
Re: How to make this just return an xml string (not even call a web service)?

Good point. I'm using FireFox 2.0. In more detail: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12

I think many of my users would still be using 2.0, so I can't ask them all to upgrade.

Thanks,

 

Tim Stall
http://timstall.dotnetdevelopersjournal.com

timstallc

Loading...
Joined on 11-17-2007
Posts 36
03-16-2008 12:19 AM
Re: How to make this just return an xml string (not even call a web service)?

Try this:

ScriptObject request;

ScriptObject dom;

try

{

request = HtmlPage.Window.CreateInstance("XMLHttpRequest");

request.Invoke("open", "GET", url, false);

request.Invoke("send");

dom = (ScriptObject) request.GetProperty("responseXML");

return (string)dom.GetProperty("xml");

}

catch (Exception ex)

{

throw;

}

jackbond

Loading...
Joined on 03-21-2007
Posts 385
03-16-2008 2:50 PM
Re: How to make this just return an xml string (not even call a web service)?

Thanks for the new code. It works great in IE, but still no luck in FireFox 2.0.

It fails again on the same like:

    request.Invoke("send");

Similar error:

   [ScriptObject_InvokeFailed]\r\nArguments:\r\nDebugging resource strings are unavailable

I see what you're trying to do, and it makes sense (calling XmlHttpRequest, similar to what ajax does in a browser), but still no luck on FF 2.0.  Is there anything else I can provide to shed some light?

Thanks,

Tim Stall
http://timstall.dotnetdevelopersjournal.com

timstallc

Loading...
Joined on 11-17-2007
Posts 36
03-16-2008 6:08 PM
Re: How to make this just return an xml string (not even call a web service)?

Hi Tim,

I've got so many dev environments, that I got mixed up which version of Firefox I was running. It is actually working on Firefox 2.0.0.12 for me with the following code:

public static string DownloadXmlStringSync(string url)

{

ScriptObject request;

request = HtmlPage.Window.CreateInstance("XMLHttpRequest");

request.Invoke("open", "GET", url, false);

request.Invoke("send");

return (string)request.GetProperty("responseText");

}

Are you able to set a breakpoint on the server to see if the request is actually making it through?

jackbond

Loading...
Joined on 03-21-2007
Posts 385
03-16-2008 9:58 PM
Re: How to make this just return an xml string (not even call a web service)?

I used this wrapper for communicating with Astoria from Silverlight (You can read it here.) Some said that they are having the problem..

I get the following error when deleting or updating

An exception of type ‘System.ArgumentException’ occurred in System.Windows.Browser.dll but was not handled in user code

Additional information: [ScriptObject_TypeDoesNotExist]
Arguments:XMLHttpRequest
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=8.0.30226.2&File=System.Windows.Browser.dll&Key=ScriptObject_TypeDoesNotExist

I can’t retrieve the data too, error on this line
_xmlHttpRequest = HtmlPage.Window.CreateInstance(”XMLHttpRequest”);

{System.ArgumentException: [ScriptObject_TypeDoesNotExist]
Arguments:XMLHttpRequest
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=8.0.30226.2&File=System.Windows.Browser.dll&Key=ScriptObject_TypeDoesNotExist
Parameter name: typeName
at System.Windows.Browser.HtmlWindow.CreateInstance(String typeName, Object[] args)
at SL2Astoria.XMLHttpRequestWrapper.DoPost(Uri url, String httpVerb, String param)
at SL2Astoria.XMLHttpRequestWrapper.DoPost(Uri url, String httpVerb)
at SL2Astoria.Page.retrieveButton_Click(Object sender, RoutedEventArgs e)}

Actually, I mentioned three operations (Insert, delete and retrieve) in that article.  that guy is having some problems in deleting. I'm not sure why. It is working on my machine..

 

(If this has answered your question, please click on "Mark as Answer" on this post. Thank you!)

Best Regards,
Michael Sync

Blog : http://michaelsync.net
Feed : http://michaelsync.net/feed

mchlSync

Loading...
Joined on 09-16-2005
Singapore
Posts 2,220
03-17-2008 12:16 AM
Re: How to make this just return an xml string (not even call a web service)?

Tim, I think you are going to be VERY happy when you run this code:

public static string DownloadXmlStringSync(string url)

{

ScriptObject request;

request = HtmlPage.Window.CreateInstance("XMLHttpRequest");

request.Invoke("open", "GET", url, false);

request.Invoke("send", "");

return (string)request.GetProperty("responseText");

}

As for why it worked for some people and not others: Firebug has its own observer effect 

jackbond

Loading...
Joined on 03-21-2007
Posts 385
03-17-2008 10:14 AM
Re: How to make this just return an xml string (not even call a web service)?

Yes! Works perfectly in both. I also love how clean and simple it now is.

Thanks so much

Tim Stall
http://timstall.dotnetdevelopersjournal.com

timstallc

Loading...
Joined on 11-17-2007
Posts 36
03-17-2008 10:21 AM
Re: How to make this just return an xml string (not even call a web service)?

Very nicely done. :) 

For other folks who may stumble on this code in the future, though, it should be said that this doesn't support some of new things in SL2 like cross-domain policies or anything MSFT does with secure service calls in the future. Often not a deal-killer, but useful to know.

Pete

If your question was answered, please mark the response as the answer.

Silverlight.net Moderator
MVP: Visual Developer - Client Application Development
POKE 53280,0 - My Blog

Psychlist1972

Loading...
Joined on 10-12-2004
Maryland, USA
Posts 765
03-17-2008 4:44 PM
Re: How to make this just return an xml string (not even call a web service)?

Psychlist1972:
it should be said that this doesn't support some of new things in SL2 like cross-domain policies or anything MSFT does with secure service calls in the future.

Unfortunate, but true. I developed this code because there was no way to call a web service during application exit. I actually hope in the next beta, or sometime before RTM this code becomes entirely irrelevant. I fear however that this code is going to get a lot of usage.

jackbond

Loading...
Joined on 03-21-2007
Posts 385
05-01-2008 6:06 AM
Re: How to make this just return an xml string (not even call a web service)?

 If I want to use this code in an application that uses cross domain policies,then what changes should I make in the code so that the code works properly.

Or is there any other method by which the same error gets removed in application that uses cross domain policies 

vchoudhary

Loading...
Joined on 04-16-2008
Posts 15
Page view counter