Programming with interoperable, human-readable protocols opens up lots of integration opportunities. The human-readable part is really important. People understand strings really well, which is why JSON and XML became so pervasive. Most languages and platforms have ways to process these text-based formats.
Why would I focus on interoperability as the first topic in an article about Silverlight and Google Application Engine (GAE)? I have talked to people about work I've done creating a GAE-based backend for Silverlight applications. In general, they seem surprised that a Google-based framework happily supports Silverlight. Google didn't do anything special to make this happen. Neither did Microsoft. Instead, both companies support various web and other open standards. Because of that choice, everything else just works.
As a demonstration of interoperability between GAE and Silverlight, I built a type of application that we've all seen at some point: a photo-management tool. The tool itself is simple. It allows the user to upload and delete images. For existing images, the user can add information about the picture: a caption and a description. Finally, users can choose to expose the image to everyone or just to themselves. To use the tool, users sign in. They manage their photos through a Silverlight interface.
For this discussion, I assume that you already have the following skills:
- You know how to program in C#.
- You're comfortable reading code written in other languages, such as Python.
- You've gone through the tutorials on App Engine and learned how to set up an application.
- You have a high-level understanding of serialization.
- You've used an integrated development environment (IDE) such as Eclipse or Visual Studio.
For this article, we'll focus on the code that allows Silverlight to talk to a Python back end. There's minimal coverage about XAML, Django, and other topics that could distract you from understanding how to enable a .NET application to talking to a Python app.
Google Message-Handling Basics
Hypertext Transfer Protocol (HTTP) has addressable resources that consist of URLs. For example, the following address might identify a resource that describes a 20-ounce bar of chocolate:
HTTP allows me to use a set of verbs against that resource:
- GET fetches information about the chocolate.
- PUT updates the chocolate resource. Through a PUT, I can change information about the resource, such as changing the description of the chocolate.
- POST put a new resource within the context of the parent URL. For instance, I could POST information about a 20-ounce Hershey bar to the URL.
- HEAD retrieves basic information about the resource without actually retrieving the resource. You can find out how large the representation is, the type of content (image, text, etc.), and other information about the resource.
- DELETE removes the resource.
The base libraries in google.appengine.ext.webapp contain a class called RequestHandler. You derive your class from RequestHandler and then define methods that map to the previous five HTTP methods: GET, PUT, POST, HEAD, DELETE. A "Hello World" might look like this:
class MainPage(webapp.RequestHandler): def get(self): self.response.out.write("Hello, world!")
How does a message from the outside reach your GET method? When a message comes into your Python application, the runtime environment first checks to see which Python class should process the message. This happens in app.yaml, a file that you deliver with your deployment. The paths that GAE needs to know about are mapped in the handlers section of app.yaml. For example, to set up a path for image-related messages, you add the following:
handlers: - url: /img script: index.py
This instruction tells the GAE runtime to send messages with /img in the path to index.py. Within index.py, we can provide a bit more information:
application = webapp.WSGIApplication( [('/', MainPage), ('/images', ImageList), ('/img', ActualImage)], debug=True) def main(): run_wsgi_app(application)
This code sets up your application and then routes the paths to specific handlers. Each pair states that a different class should be invoked for a given path (/, /images, or /img). These classes handle the various HTTP methods: GET, PUT, POST, HEAD, and DELETE.
Okay, now try to keep all of that information in your head. We'll come back to it in a bit.