Page view counter
Very light weight XmlHttpRequest wrapper - Make synchronized web service calls again Subscribe to this thread
Last post 04-01-2009 4:46 PM by fatihpiristine. 25 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();

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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

Microsoft WPF & Silverlight Insider
Blog : http://michaelsync.net


mchlsync

Loading...
Joined on 09-16-2005
Singapore
Posts 2,478
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?

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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.

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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 28
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;

}

}

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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.

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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;

}

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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?

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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

Microsoft WPF & Silverlight Insider
Blog : http://michaelsync.net


mchlsync

Loading...
Joined on 09-16-2005
Singapore
Posts 2,478
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 

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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

Silverlight.net Moderator
MVP: Silverlight
Silverlight Insider
POKE 53280,0 - My Blog at irritatedVowel.com

Psychlist1972

Loading...
Joined on 10-12-2004
Maryland, USA
Posts 941
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.

Jack Bond

Khet - The first Silverlight multiplayer game

Zork I: The Great Underground Empire

jackbond

Loading...
Joined on 03-21-2007
Posts 614
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
01-20-2009 6:36 PM
Re: How to make this just return an xml string (not even call a web service)?

code is below

fatihpiristine

Loading...
Joined on 05-08-2008
Budapest
Posts 4
01-20-2009 6:46 PM
Re: How to make this just return an xml string (not even call a web service)?

Could you format that better, or attach a project?

Sam...

"The difference between genius and stupidity is that genius has its limits." - Albert Einstein

samcov

Loading...
Joined on 03-26-2008
Posts 317
01-20-2009 7:01 PM
Re: How to make this just return an xml string (not even call a web service)?
I have modified the code to make it work with ie6, ie5.5 etc. here is the code.
have test on IE6, IE7, FF2, FF3, Opera and Safari. worked fine.
you may need clientaccesspolicy.xml link:
http://msdn.microsoft.com/en-us/library/cc197955(VS.95).aspx  
namespace SyncCall
{
    public class AjaxCall
    {
        protected static System.Windows.Browser.ScriptObject XMLHttpRequest;
        protected static System.String Result = System.String.Empty;
        /// <summary>
        /// Makes XMLHttpRequest
        /// </summary>
        /// <param name="Url">relative or absolute url as string</param>
        /// <param name="Method">GET or POST</param>
        public static void MakeCall(string Url, string Method)
        {
            // Backward compat
            System.Windows.Browser.HtmlPage.Window.Eval("if(typeof XMLHttpRequest==\"undefined\"){XMLHttpRequest=function(){var a=[\"Microsoft.XMLHTTP\",\"MSXML2.XMLHTTP\",\"MSXML2.XMLHTTP.3.0\",\"Msxml3.XMLHTTP\"];for(var b=0;b<a.length;b++){try{return new ActiveXObject(a[ b ]);}catch(ex){}}};}");
            // create the instance
            XMLHttpRequest = System.Windows.Browser.HtmlPage.Window.CreateInstance("XMLHttpRequest");
            // request data from server
            XMLHttpRequest.Invoke("open", Method.ToUpper(), Url, false);
            // send. !!! do not replace it with "null" as it throws exception
            XMLHttpRequest.Invoke("send", "");
            // get result as string. as gecko based browsers does not return xml
            Result = XMLHttpRequest.GetProperty("responseText").ToString();
        }
        /// <summary>
        /// Returns result from request as string
        /// </summary>
        public static System.String GetResult()
        {
            return Result.ToString();
        }
    }
}
 
 
 
 
fatihpiristine

Loading...
Joined on 05-08-2008
Budapest
Posts 4
01-21-2009 2:09 AM
Re: How to make this just return an xml string (not even call a web service)?

This appears to only be able to do a "GET", request, and not a "POST".

"The difference between genius and stupidity is that genius has its limits." - Albert Einstein

samcov

Loading...
Joined on 03-26-2008
Posts 317
04-01-2009 11:01 AM
Re: How to make this just return an xml string (not even call a web service)?

I tried  to call it at application exit event handler using

AjaxCall.MakeCall("Stockservice.asmx", "Logout");

but got InvalidOperationException at line 

XMLHttpRequest.Invoke("open", Method.ToUpper(), Url, false);

How to fix ?

Andrus. 

System.InvalidOperationException was unhandled by user code
  Message="Invalid argument."
  StackTrace:
       at System.Windows.Browser.ScriptObject.Invoke(String name, Object[] args)
       at SyncCall.AjaxCall.MakeCall(String Url, String Method)
       at AWSilverlightLOB.App.Application_Exit(Object sender, EventArgs e)
       at System.Windows.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
       at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, String eventName)
  InnerException:

kobruleht

Loading...
Joined on 04-30-2008
Posts 293
04-01-2009 4:46 PM
Re: How to make this just return an xml string (not even call a web service)?

is it happening when you closing the browser window? if yes, on browser exit, it disposes everything before it exists.

 

i can suggest you to do one thing to try this out, run your solution with firefox, from firebug modify silverlight object position property to absolute,

it will exit and run the application again, if you are not getting this error, then it is related to browser window.

 

 

fatihpiristine

Loading...
Joined on 05-08-2008
Budapest
Posts 4
Microsoft Communities