A while ago, Jaime Rodriguez, a coworker of mine posted about how to use ASP.NET AJAX from a Vista Sidebar Gadget. That was on a Beta version of ASP.NET AJAX (which was then called "Atlas"). Since then, it's gotten even easier, so I thought I'd write up a quick hello world gadget. As an added bonus, I'll also show how to use a PHP backend, based on PHP for Microsoft AJAX Library.
What we'll make
We'll make a sidebar gadget with a textbox and a button. The user types their name in the textbox and clicks the button. When the button is clicked, the name in the textbox is sent to the web server, and the web server replies with "Hello, <name>!" (where <name> is the name of the user).
Quite frankly, I believe this sidebar gadget will revolutionize the way people are greeted by their computers.
What you'll need
- A web server also running ASP.NET AJAX 1.0 to host the web service. This could just be your development machine, and you can just run the web service right out of Visual Studio.
- Visual Studio or my favorite: Visual Web Developer Express
- Windows Vista to host the gadget
How to do it
Step 1: Create the web service
Fire up Visual Studio and create a new project based on the "ASP.NET AJAX-Enabled Web Site" template. Then delete everything but web.config. We don't need a .aspx page, and we don't need an App_Data directory. There's no harm in leaving them there, but why bother?
Create a new web service and put it in HelloService.asmx. Make the contents look like this:
<%@ WebService Language="C#" Class="HelloService" %>
using System.Web.Services;
using System.Web.Script.Services;
[ScriptService]
public class HelloService : System.Web.Services.WebService {
[WebMethod]
public string SayHello(string name) {
return string.Format("Hello, {0}!", name);
}
}
That's it for the web service!
Step 2: Create the gadget
You don't need to do much to create a gadget. Just go into \Users\<your username>\AppData\Local\Microsoft\Windows Sidebar\Gadgets and create a new directory called HelloWorld.gadget. Inside, create a file called gadget.xml with the following content:
<?xml version="1.0" encoding="utf-8" ?>
<gadget>
<name>Hello, World!</name>
<version>1.0</version>
<hosts>
<host name="sidebar">
<base type="HTML" apiVersion="1.0.0" src="HelloWorld.html" />
<permissions>full</permissions>
<platform minPlatformVersion="0.3" />
</host>
</hosts>
</gadget>
Note that we're giving our gadget a title of "Hello, World!", and we're pointing to HelloWorld.html as the source for the gadget. Speaking of which, let's go ahead and create that file:
<html>
<head>
<title>Hello, World!</title>
<script type="text/javascript" src="MicrosoftAjax.js"></script>
<script type="text/javascript" src="proxy.js"></script>
</head>
<body style="width:100%;height:250px">
Name: <input id="name" type="text" />
<input type="button" value="Say Hello" onclick="button_click(); return false;" />
<br />
Message from server: <span id="response"></span>
</body>
<script type="text/javascript">
function button_click() {
HelloService.SayHello($get('name').value, function (result) {
$get('response').innerHTML = result;
});
}
</script>
</html>
This is almost verbatim a copy of samples/HelloWorld/HelloWorld.html from the PHP for Microsoft AJAX Library project, by the way.
Two things to notice. First, unlike a .aspx page, instead of using the ScriptManager tag to bring in the necessary JavaScript, we're doing it the old fashioned way, with script tags. We're bringing in two scripts:
MicrosoftAjax.js is from the Microsoft AJAX Library (part of ASP.NET AJAX or a separate download). If you need to find it as part of your ASP.NET AJAX install, it's in the easy-to-remember location of \Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\MicrosoftAjaxLibrary\System.Web.Extensions\1.0.61025.0. If you've downloaded the Microsoft AJAX Library separately, then it's wherever you put it.
proxy.js contains the JavaScript proxy for our web service. From a .aspx page, you would use a ScriptReference on your ScriptManager to bring in this code. We'll see where we get this file next.
Step 3: Generate the JavaScript proxy
Navigate in your browser to HelloService.asmx/js, wherever you're hosting the service. That could mean right-clicking and choosing "View in browser" in Visual Studio if you're just running from within the IDE. Make sure you put the /js on the end.
If you're using IE, you'll be prompted to save a file. If you're using Firefox, you'll actually see the JavaScript, so do File/Save Page As. In either case, save the file in the same directory as your gadget code with the filename proxy.js.
That proxy.js is pretty much what we need except for one small change. In a normal web app scenario, it's assumed that the web service lives on the same server as the web page. This is, in fact, pretty much required by the same-origin policy in the browser. (You can't make cross-domain requests, so the web service must be in the same domain.) The sidebar doesn't have that same restriction, and in fact our web service isn't hosted in the same place as our gadget (the filesystem). That means we'll have to change one line in proxy.js. Where it says HelloService.set_path("/NameOfWebApp/HelloService.asmx"), we'll have to make that a full path instead of the relative path there. Here's what my finished proxy.js looks like (I'm hosting the service out of Visual Web Developer Express):
var HelloService=function() {
HelloService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
HelloService.prototype={
SayHello:function(name,succeededCallback, failedCallback, userContext) {
return this._invoke(HelloService.get_path(), 'SayHello',false,{name:name},succeededCallback,failedCallback,userContext); }}
HelloService.registerClass('HelloService',Sys.Net.WebServiceProxy);
HelloService._staticInstance = new HelloService();
HelloService.set_path = function(value) { HelloService._staticInstance._path = value; }
HelloService.get_path = function() { return HelloService._staticInstance._path; }
HelloService.set_timeout = function(value) { HelloService._staticInstance._timeout = value; }
HelloService.get_timeout = function() { return HelloService._staticInstance._timeout; }
HelloService.set_defaultUserContext = function(value) { HelloService._staticInstance._userContext = value; }
HelloService.get_defaultUserContext = function() { return HelloService._staticInstance._userContext; }
HelloService.set_defaultSucceededCallback = function(value) { HelloService._staticInstance._succeeded = value; }
HelloService.get_defaultSucceededCallback = function() { return HelloService._staticInstance._succeeded; }
HelloService.set_defaultFailedCallback = function(value) { HelloService._staticInstance._failed = value; }
HelloService.get_defaultFailedCallback = function() { return HelloService._staticInstance._failed; }
HelloService.set_path("http://localhost:51627/AJAXEnabledWebSite5/HelloService.asmx");
HelloService.SayHello= function(name,onSuccess,onFailed,userContext) {HelloService._staticInstance.SayHello(name,onSuccess,onFailed,userContext); }
Step 4: Run it!
You should now be able to click the plus sign at the top of the sidebar to add a gadget and choose "Hello, World!" from the list. Once the gadget appears, type in your name and press the "Say Hello" button. If everything's working correctly, the message "Hello, <name>!" should appear right under where it says "Message from server:".
That's it!
Bonus: doing it with PHP
Grab PHP for Microsoft AJAX Library. Instead of HelloService.asmx, you can just use the HelloService.php that comes in the HelloWorld sample, or you can write it yourself. It looks like this:
<?php
require_once '../../dist/MSAjaxService.php';
class HelloService extends MSAjaxService
{
function SayHello($name)
{
return "Hello, " . $name . "!";
}
}
$h = new HelloService();
$h->ProcessRequest();
?>
You'll still need to make sure there's an absolute path in proxy.js, this time pointing to HelloService.php/js. Otherwise nothing changes... and that's the point, after all. :-)