Click here to Skip to main content
Click here to Skip to main content

Synchronous WCF Service Calls with Silverlight

By , 16 Mar 2010
 
Clicking on one button freezes the Silverlight UI Thread, but not the browser.

Introduction

This small article is dedicated to Daniel Vaughan, one of the greatest article writers on CodeProject. Yesterday, I saw one of his articles about synchronous call on Silverlight. I did not agree with his method which finally makes a synchronous call on an asynchronous thread. Most of the synchronous problems cannot work with it.

I have to make synchronous calls in my own application to create a communication pipe between my Silverlight app and an LMS server (exposing WCF services).

My Solution

My solution is very simple, I just use JavaScript, the Silverlight blood brother to make my WCF call with the help of the XmlHttpRequest object. I create a generic JS function that will call the specified method on a WCF frontage and add specified parameters.

I created a manager that calls this JS function and formats a simple JSON message.

The sample is very basic because I do not have a lot of time to improve it. It just works with string parameters and string returns. If you want to use WCF OperationContract with other object types, just use a true JSON serializer. :)

JavaScript Part

The function read the arguments passed by the manager with the arguments array:

function SyncWCFServiceCaller() 
{
var client = null;

if (window.XMLHttpRequest)
client = new XMLHttpRequest();
else if (window.ActiveXObject)
client = new ActiveXObject("Microsoft.XMLHTTP");
var data = arguments[1];
client.open('POST', arguments[0], false);
client.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
client.setRequestHeader('Content-Length', data.length + '');
client.send(data);
var response = eval('(' + client.responseText + ')').d;
return response;
}

arguments[0] contains the WCF endpoint and the method name (such as "localhost/service.svc/method").

arguments[1] contains the serialized parameters (in JSON), like "{"name" : "daniel"}"

Nothing complicated here. The XmlHttpRequest creates a sync call so if it is called from Silverlight it does not return to the caller before the return of the service.

My work uses only the string object type so I just return the default 'd' JSON object that contains the result.

Silverlight Part

The C# manager is very simple too:

public class ContractToJavascriptCaller<T>
{
public string ServiceEndPointUri
{
get;
private set;
}
public ContractToJavascriptCaller(string serviceEndPointUri)
{
this.ServiceEndPointUri = serviceEndPointUri;
}
public object CallMethod(string methodName, params string[] arguments)
{
StringBuilder builder = new StringBuilder();
builder.Append("{");
MethodInfo methodInfo = typeof(T).GetMethod(methodName);
ParameterInfo[] parameters = methodInfo.GetParameters();
int parameterIndex = 0;
foreach (ParameterInfo parameter in parameters)
{
builder.Append("\"");
builder.Append(parameter.Name);
builder.Append("\"");
builder.Append(":\"");
builder.Append(arguments[parameterIndex++]);
builder.Append("\",");
}

string jsonSerializedParameters = builder.ToString().TrimEnd(',');
jsonSerializedParameters = string.Concat(jsonSerializedParameters, "}");

return HtmlPage.Window.Invoke("SyncWCFServiceCaller", 
	string.Concat(this.ServiceEndPointUri, "/", methodName), 
	jsonSerializedParameters);
}
}

This manager has just one method, CallMethod, that will invoke the JS function with the end point of the service and the method name, and the parameters serialized as JSON. The HtmlPage.Window.Invoke does not return before the WCF service call.

The CallMethod receives the WCF MethodName to call. It uses reflection to get the parameters and serializes their name and values in JSON.

That's all! If you call a WCF service in this way, you will freeze the UI Thread but not the Browser.

Calling a WCF Service

My WCF service contains two methods:

string DoWork(string name);
string DoWorkWithTwoParams(string name, string name2); 

I put a Thread.Sleep instruction inside their instruction block to simulate a big computing set of instructions. The Interface for the WCF service is linked inside the Silverlight project. So to call a WCF method, I just have to do:

ContractToJavascriptCaller<IDanielService> caller = 
new ContractToJavascriptCaller<IDanielService>(http://localhost:23770/DanielService.svc);
string response = caller.CallMethod("DoWork", this.firstMathodTextBlock.Text).ToString();
this.ResultTextBlock.Text = response; 

Sorry for:

  1. My poor English
  2. The bad quality of the code, I really do not have time for myself: I am currently listening to Mix 2010 session about WP7.

History

  • 15th March, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Valentin Billotte
Architect Viablue - GraphicStream
France France
Member
I spent most of time on Silverlight, Xna (where i am MVP) and ADO.Net Data Services.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionnot work browser operamemberouadie9920 Feb '13 - 6:27 
good project , I tested in IE, firefox, chrome it works but not work opera
can you help me
GeneralMy vote of 5membernileshpatel1583@gmail.com2 May '12 - 20:39 
thanks
GeneralRe: My vote of 5membernileshpatel1583@gmail.com7 May '12 - 2:17 
It is one of the great artical for silverlight.
I have solved many problem by using this approch
Thanks
QuestionIIs problem?membercoerrace12 Jan '11 - 8:22 
I tested on IIs 7 with windows 2008 Server and when you click on the button to generate the result on any of both options
The result is blank. If I test via local with visual studio works perfect any suggestion?
Off course I redirect the call http:// of the service to where the server 2008 server is.
Thank you
GeneralOut of Browsermemberdanparker27630 Aug '10 - 9:58 
This won't work with an out of broswer app because it needs the javascript on the browser right?
QuestionHow to Synchronous Call WCF RIA Services in SL 4? [modified]memberMember 14670219 Aug '10 - 23:03 
It is excellent!
But WCF RIA Services's format is not xml or json, is binary, How to Synchronous Call WCF RIA Services in silverlight 4?

modified on Friday, August 20, 2010 5:10 AM

GeneralMy vote of 5memberMember 14670219 Aug '10 - 2:45 
best
GeneralFYI: This has been around for yearsmemberDewey18 Jun '10 - 18:13 
    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();
        }
    }
    public static class XMLHttpRequestWrapper
    {
        static ScriptObject _xmlHttpRequest;
 
        public static string DoPost(Uri url, string httpVerb)
        {
            return DoPost(url, httpVerb, string.Empty);
        }
        public static string DoPost(Uri url, string httpVerb, string param)
        {
            _xmlHttpRequest = HtmlPage.Window.CreateInstance("XMLHttpRequest");
 
            _xmlHttpRequest.Invoke("open", httpVerb, url, false);
            _xmlHttpRequest.Invoke("setRequestHeader", "Content-Type", "application/json");
            //_XMLHttpRequest.Invoke("setRequestHeader", "SOAPAction", string.Concat(nspace, method));
            if (param == string.Empty)
            {
                _xmlHttpRequest.Invoke("send");
            }
            else
            {
                _xmlHttpRequest.Invoke("send", param);
            }
 
            ScriptObject dom = (ScriptObject)_xmlHttpRequest.GetProperty("responseXML");
            return (string)dom.GetProperty("xml");
        }
    }

GeneralSuperb!mvpDaniel Vaughan18 Mar '10 - 4:21 
Great thinking Valentin! I like this a lot, and not just because of your kind words and dedication (which was very nice by the way).
With this approach we rely on magic strings and loose typing, and give up the WCF infrastructure unfortunately. I suspect that if we had a generated API or layer it would improve its viability.
But it's excellent and creative work! 5 from me.
 
Cheers,
Daniel
GeneralRe: Superb!memberValentin Billotte18 Mar '10 - 5:13 
Thx you for your kind words Daniel.
It can be improved a lot yes.
Need help ? Ask me Smile | :)

GeneralRe: Superb!mvpDaniel Vaughan18 Mar '10 - 6:08 
But it does what you intended! And for simple scenarios where you simply must have synchronous calls on the UI thread, and not on another thread, it works. Very cool.
GeneralEnjoyed the articlememberlinuxjr16 Mar '10 - 12:17 
Have a five from me.
GeneralRe: Enjoyed the articlememberValentin Billotte16 Mar '10 - 21:31 
Thx you Smile | :)
Need help ? Ask me Smile | :)

GeneralLike it, like itmvpSacha Barber16 Mar '10 - 6:23 
Have a 5
Sacha Barber
  • Microsoft Visual C# MVP 2008/2009
  • Codeproject MVP 2008/2009
Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: Like it, like itmemberValentin Billotte16 Mar '10 - 7:26 
Thx you Sacha.
Need help ? Ask me Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 16 Mar 2010
Article Copyright 2010 by Valentin Billotte
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid