I am not sure what to call this post. Essentially, it will describe how you can call JavaScript code from Silverlight. In addition, it will show how to call code running on the server from Silverlight using Ajax and then get a response from that code.
For some reason, the code examples that have been included with Silverlight do not include an example of calling to the server without using a web service. If you like me you probably do not want to create a webservice just to do an MD5 hash. Yes that is correct, if you need to do an MD5 hash with Silverlight you are out of luck, you will need to either write a custom hashing method in Silverlight or call to the server to hash something (look in the Crypto namespace if you don't believe me). The solution is to create a method that runs on the server that can be called from JavaScript, and thus Silverlight.
Call JavaScript from Silverlight
Create a new 1.1 Silverlight project that will have some C# code that gets compiled for the client. Create an ellipse in the xaml that will act as a button. Whenever the button is clicked it will call a JavaScript function and get a response. Here is what my xaml looks like:
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="parentCanvas"
Loaded="Page_Loaded"
x:Class="Test.Page;assembly=ClientBin/Test.dll"
Width="640"
Height="480"
Background="White"
>
<TextBlock x:Name="ServerTime" Width="249" Height="22" Canvas.Left="90"
Canvas.Top="163" Text="ServerTime" TextWrapping="Wrap"
RenderTransformOrigin="0.5,0.5" />
<Ellipse x:Name="GetTime" Width="97" Height="33" Fill="#FFFFFFFF"
Stroke="#FF000000" Canvas.Left="370" Canvas.Top="152"/>
</Canvas>
Now in the class file for your xaml page add the following code outside of the class brackets to create a custom eventArgs that can be used to pass parameters to your JavaScript.
[
Scriptable]
public class TextArgs :
EventArgs
{
private string _text =
string.Empty;
public TextArgs(
string text)
{
_text = text;
}
[
Scriptable]
public string Text
{
get {
return _text; }
}
}
You will notice that the above code includes the Scriptable attribute. This will expose the eventArgs to JavaScript. In order for it to work you will probably need a using statement for System.Windows.Browser, which is the namespace that contains Scriptable.
Now you will need to create an EventHandler that can be accessed by JavaScript. So add the following code to your xaml class:
[
Scriptable]
public event TextEventHandler CallbackToBrowser;
Now that you have this code in place you will need to register your xaml code behind class so that there is a clear page object that can be accessed by your JavaScript code. To do this add the following line of code to the Page_Loaded method in the xaml code behind.
WebApplication.Current.RegisterScriptableObject(
"testPage",
this);
Next add a function in the JavaScript, which is in the html part of your test page file, to run when the Silverlight onLoad event that will subscribe a function to the TextEventHandler CallbackToBrowser. Here is what the JavaScript looks like in my test page:
<div id="SilverlightControlHost" class="silverlightHost">
<script type="text/javascript">
function createSilverlight()
{
Silverlight.createObjectEx({
source: "Page.xaml",
parentElement: document.getElementById("SilverlightControlHost"),
id: "SilverlightControl",
properties: {
width: "100%",
height: "100%",
version: "1.1",
enableHtmlAccess: "true"
},
events: { onLoad: OnLoaded }
});
// Give the keyboard focus to the Silverlight control by default
document.body.onload = function() {
var silverlightControl = document.getElementById
('SilverlightControl');
if (silverlightControl)
silverlightControl.focus();
}
}
createSilverlight();
function OnLoaded(sender, args)
{
sender.Content.testPage.CallbackToBrowser = onManagedCallback;
}
function onManagedCallback(sender, args)
{
ShowText(ServerPage.GetMd5(args.Text, null).value);
}
function ShowText(textToShow)
{
var control = document.getElementById('SilverlightControl');
if (!control)
return;
control.Content.testPage.ShowText("" +
textToShow);
}
</script>
</div>
You will notice that the OnLoaded event handler creates a handler for the CallbackToBrowser, which is called onManagedCallback. Also, you will notice that the onManagedCallback funtion calls the ShowText function, which passes the args.Text text to it as a parameter. This comes from the TextEventArgs that exists in Silverlight.
Next you will want to fire the CallbackToBrowser, to do this I added a mouseclick event to the ellipse. You can add the following code to the xaml code behind.
public void Page_Loaded(
object o,
EventArgs e)
{
// Required to initialize variables
InitializeComponent();
WebApplication.Current.RegisterScriptableObject(
"testPage",
this);
Ellipse GetTime =
this.FindName(
"GetTime")
as Ellipse;
if (GetTime !=
null)
GetTime.MouseLeftButtonDown +=
new MouseEventHandler (GetTime_MouseLeftButtonDown);
}
void GetTime_MouseLeftButtonDown(
object sender,
MouseEventArgs e)
{
if (CallbackToBrowser !=
null)
CallbackToBrowser(
this,
new TextArgs(
"Message from
Silverlight"));
}
Now you have everything wired up so that whenever you click the ellipse with your mouse your Silverlight control will call the onManagedCallback function. This function in turn calls the ServerPage.GetMD5 method with the text passed from the TextEventArgs. Currently there is not a method on the server for this call, so we should add one. In this example I am using the CommunityServer AjaxMethod attribute to make the server method accessible from JavaScript. You can use ASP.NET Ajax if you need to, here is the code I have on the server:
protected void Page_Load(
object sender,
EventArgs e)
{
AjaxManager.Register(
this,
"ServerPage");
}
[
AjaxMethod(IncludeControlValuesWithCallBack =
false)]
public string GetMd5(
string str)
{
// First we need to convert the string into bytes, which
// means using a text encoder.
Encoder enc = System.Text.
Encoding.Unicode.GetEncoder();
// Create a buffer large enough to hold the string
byte[] unicodeText =
new byte[str.Length * 2];
enc.GetBytes(str.ToCharArray(), 0, str.Length, unicodeText, 0,
true);
// Now that we have a byte array we can ask the CSP to hash it
MD5 md5 =
new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(unicodeText);
// Build the final string by converting each byte
// into hex and appending it to a StringBuilder
StringBuilder sb =
new StringBuilder();
for (
int i = 0; i < result.Length; i++)
{
sb.Append(result[i].ToString(
"X2"));
}
// And return it
return sb.ToString();
}
Now everything is wired up, so whenever you click the ellipse the text from Silverlight ("Message from Silverlight") is passed to JavaScript, which then calls the server method GetMd5. The result of this call is then pushed back into Silverlight and displayed in the TextBlock named ServerTime.
Hopefully, this was helpful for anyone trying to hash something in Silverlight. It should also be helpful for anyone who does not want to create a web service and instead wants to call the server through Ajax directly.
As with any post, let me know if you have any questions.