|
This is already my third article on Silverlight Networking, with only the Credentials in mind. Please read my other articles first:
The workaround
It took me some time to get the work-around ready enough for this article. I must say we finally have the possibility to make a WebRequest with Credentials. Although we have another problem to solve, it’s crossdomain scripting! This article explains how you can make use of the Javascript abilities to make a WebRequest.
Using the ASP.NET Ajax Javascript libraries
I know it’s not very difficult to build some code around XMLHttpRequest, but there’s a very nice wrapper build by the people behind ASP.NET Ajax. This wrapper is the Sys.Net.WebRequest class. This would make a call as simple as the following code:
1 // This function adds and removes the
2 // Web request completed event handler.
3 function WebRequestCompleted()
4 {
5 // Instantiate the WebRequest.
6 var wRequest = new Sys.Net.WebRequest();
7
8 // Set the request Url.
9 wRequest.set_url(getPage);
10
11 // Set the web request completed event handler,
12 // for processing return data.
13 wRequest.add_completed(OnWebRequestCompleted);
14 alert("Added Web request completed handler");
15
16 // Remove the web request completed event handler.
17 // Comment the following two lines if you want to
18 // use the handler.
19 wRequest.remove_completed(OnWebRequestCompleted);
20 alert("Removed handler; the Web request return is not processed.");
21
22 // Execute the request.
23 wRequest.invoke();
24 }
To use this library you first have to download it and reference the MicrosoftAjax.js as follows:
<script type="text/javascript" src="JS/MicrosoftAjax.js"></script>
Calling dynamic Javascript code from Silverlight
It is possible to call Javascript code that already exists by using the HtmlPage.Window.Invoke() method. But as explained next I want to built up the Javascript dynamically.
To call a string containing Javascript you will have to make use of the HtmlPage.Window.Eval() method.
HtmlPage.Window.Eval("(function(){ alert('Hello world! Using dynamic Javascript');})();");
Just for my own sake I build a small wrapper around the Eval function, that just delegates to HtmlPage.Window.
1 public static class JavascriptBridge
2 {
3 private static HtmlWindow window = HtmlPage.Window;
4
5 public static object Eval(string code)
6 {
7 return window.Eval(code);
8 }
9 }
Setting up a JavascriptWebRequest in C#
My idea was to build a C# class that makes use of Javascript to do the actual WebRequest but looks quite similar to the WebRequest object. I came up with the following class which probably speaks for itself.
1 public class JavascriptWebRequest
2 {
3 public string Uri { get; set; }
4 public string Method { get; set; }
5 public Dictionary<string, string> Headers { get; set; }
6 public string Body { get; set; }
7
8 public JavascriptWebRequest()
9 {
10 Headers = new Dictionary<string, string>();
11 }
12
13 public void Execute()
14 {
15 JavascriptWebRequestExecutor.Execute(this);
16 }
17 }
I for myself really like this class. It allows me to write code like this:
1 var request = new JavascriptWebRequest
2 {
3 Uri = "http://localhost:2851/Test.xml",
4 Headers =
5 {
6 {"Authorization", string.Format("Basic {0}", new NetworkCredential("username","password").ToString().EncodeTo64())}
7 },
8 Method = "GET"
9 };
10 request.Execute();
Where’s all the magic?
When you look at the JavascriptWebRequest Execute method you see some magic happens behind the scenes. What happens is the JavascriptWebRequestExecutor does some translation of the JavascriptWebRequest properties to a Sys.Net.Webrequest. The request above will translate to the following Javascript.
1 // Instantiate the WebRequest object.
2 var request = new Sys.Net.WebRequest();
3
4 // Set the request Url.
5 request.set_url('http://localhost:2851/Test.xml');
6
7 // Set the request verb.
8 request.set_httpVerb('GET');
9
10 // Set the headers.
11
12 request.get_headers()['Authorization']='Basic dQBzAGUAcgBuAGEAbQBlADoAcABhAHMAcwB3AG8AcgBkAA==';
13
14 // Set the body
15 request.set_body('');
I posted the sourcecode of the full JavascriptWebRequestExecutor below. It’s just a start with lot’s of uses of string.Format. I think it’s not that readable at this moment, maybe I’ll refactor it in the future to some more readable code for the templates.
1 public class JavascriptWebRequestExecutor
2 {
3 public static void Execute(JavascriptWebRequest request)
4 {
5 string variableName = "request";
6 string javascriptToExecute = string.Format(requestFunctionTemplate, ToJavascriptVariableDeclarion(request, variableName), variableName);
7 JavascriptBridge.Eval(javascriptToExecute);
8 }
9
10 private static string ToJavascriptVariableDeclarion(JavascriptWebRequest request, string variableName)
11 {
12 //Set up the headers
13 IList<string> headers = new List<string>();
14 foreach (var header in request.Headers)
15 headers.Add(string.Format(headerTemplate, variableName, header.Key, header.Value));
16 string headersPresentation = string.Join(Environment.NewLine, headers.ToArray());
17 //Return the complete variable presentation of the request.
18 return string.Format(requestVariableTemplate, variableName, request.Uri, request.Method, headersPresentation, request.Body);
19 }
20
21
22 private const string requestFunctionTemplate =
23 @"
24 (function()
25 {{
26 {0}
27 {1}.add_completed((function(executor, eventArgs){{ alert(executor.get_responseData()); }}));
28 {1}.invoke();
29 }})();
30 ";
31
32 private const string requestVariableTemplate =
33 @"
34 // Instantiate the WebRequest object.
35 var {0} = new Sys.Net.WebRequest();
36
37 // Set the request Url.
38 {0}.set_url('{1}');
39
40 // Set the request verb.
41 {0}.set_httpVerb('{2}');
42
43 // Set the headers.
44 {3}
45 // Set the body
46 {0}.set_body('{4}');
47 ";
48
49 private const string headerTemplate =
50 @"
51 {0}.get_headers()['{1}']='{2}';
52 ";
53 }
Conclusions
So we now have a possibility to make a webrequest through javascript. Although this code works as it seems there still is some work to be done. First, we need some way to get the result back, and not only that we also need to get the result back to the rightful caller of the webrequest. More on this in the next post. Besides this, I already mentioned to trouble with crossdomain scripting, this also needs to be covered. If anyone has a good idea on this, leave some comments on my blog.
|
November 23rd, 2008 at 22:59
I think your idea is very interesting. Have you been able to finish it (getting the answer back to silverlight?
November 23rd, 2008 at 23:08
Sorry, didn’t see the navigation first - I found the following articles now.
Have you actually released the code as an open source project as you said in one of your posts or do I have to combine the different code fragments myself?
December 10th, 2008 at 09:01
I haven’t worked on this solution after the posts. I will try to post the source-code soon.
December 22nd, 2008 at 03:02
Http allows you to login using
username:password@sitename.com/blah
would this work for this case ?
December 22nd, 2008 at 16:06
Yes I know http allows login using the pattern you write, but this won’t work for most situations.