Stu Smith: Making It Up As I Go Along
“ My life working for BinaryComponents, coding, design, and other stuff. ”
(Actually, most of the solutions presented here apply to all kinds of mashups in Silverlight, not just images).
We've officially started work on the online/web version of FeedGhost, and given that our expertise in mainly in .NET, we've decided to make it a Silverlight application. I've started work on the component that will take the messy HTML found in feeds and display it using Silverlight's subset of WPF. The process will be something like:
Stage 1 has already been coded - you can read about its use in FeedGhost for Windows here. Stage 3 involves the most unknowns for me, so I'm working on that right now.
One of the features I'm going to have implement is displaying images: an author can include an image (or rather, a link to an image) in his/her blog, and FeedGhost Online should be able to display it. Let's take the obstacles one by one...
Silverlight protects against cross-site scripting (XSS) attacks. I won't go into this in detail, but suffice to say, if your Silverlight application is hosted on foo.com (for example), it can happily download resources that are also hosted on foo.com, but it won't be able to download resources from bar.com. This immediately presents us with a problem, since FeedGhost Online will be hosted on feedghost.com, but the images will be coming from, well, anywhere.
Hopefully at some point Microsoft will allow developers to explicitly turn off aspects of XSS protection, but until that day, we need a work-around. There's various ways of achieving this, but I've chosen to use a proxy. Example: let's say my Silverlight application wants to download:
http://www.example.com/image.jpg
It can't, so instead I code up a proxy and have the application ask for this instead:
http://www.feedghost.com/imageproxy.ashx?uri=http://www.example.com/image.jpg
So long as my proxy delivers an image too, my Silverlight application will be able to download it.
(Don't bother trying either of those web addresses by the way, neither of them exist. Also, the parameter supplied should be encoded, but I haven't done that in this example for clarity).
The downside of this particular workaround is bandwidth - each image request is routed through your server, and you pay for each request twice: download and upload.
I'll show sample code for a proxy at the end of this article, but before then, we have more problems in the way.
Silverlight comes with a really helpful class, Downloader, that really simplifies downloading resources asynchronously, but without any kind of threading hassles. Unfortunately, in the latest Alpha Refresh release of Silverlight, a nasty bug crept in.
The bug manifests itself under the debugger, and prevents the Silverlight application from accessing resources that under normal hosting circumstances, it would be able to access. In other words, if I run my Silverlight application under the debugger thus:
file:///C:/...somewhere.../Application.html
and it tries to access a resource:
file:///C:/...somewhere.../Resources/Blah
it (incorrectly) fails.
The moral of this story is that if you can't get your Downloader to work correctly, try hosting your application under IIS and running it from localhost.
I've logged this particular bug with Microsoft:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=293772
Having worked almost exclusively with the .NET Framework for the past few years, I've become accustomed to it being able to handle any standard file I throw at it - any format, any encoding. Silverlight however runs on a cut-down version of the framework, and many features are missing. One of these missing features is support for the GIF file format. Since blog authors can choose to use any image format for their images, we need to solve this.
Luckily, the solution to this dovetails nicely with the XSS/proxy solution - when proxying images, simply convert GIFs to another file format.
Eventually, as well as using them in our online reader, we're planning to make the Silverlight flow-layout and HTML render components available for sale (together with the Silverlight river-view, tree, and list components that we'll need), but in the meantime, if you think you might be interested, please contact me.
Hopefully the following source code is enough to get you started with cross-site mashups. It's very simple; a production version would probably implement some kind of caching, and better error handling.
ImageProxy.ashx
<%@ WebHandler Language="C#" CodeBehind="ImageProxy.ashx.cs" Class="Website.Content.Utility.ImageProxy" %>
ImageProxy.ashx.cs
using System;
using System.Data;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Net;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
namespace Website.Content.Utility
{
[WebService( Namespace = "http://tempuri.org/" )]
[WebServiceBinding( ConformsTo = WsiProfiles.BasicProfile1_1 )]
public class ImageProxy : IHttpHandler
{
public void ProcessRequest( HttpContext context )
{
string uriText = context.Request["uri"];
Uri uri;
if( !Uri.TryCreate( uriText, UriKind.Absolute, out uri ) )
{
throw new HttpException( 404, "Bad URL parameter." );
}
try
{
WebRequest request = WebRequest.Create( uri );
WebResponse response = request.GetResponse();
context.Response.ContentType = response.ContentType;
Stream stream = response.GetResponseStream();
Image image = Image.FromStream( stream );
ImageFormat format = image.RawFormat;
if( object.Equals( image.RawFormat, ImageFormat.Gif ) )
{
format = ImageFormat.Png;
context.Response.ContentType = "image/png";
}
MemoryStream ms = new MemoryStream();
image.Save( ms, format );
ms.WriteTo( context.Response.OutputStream );
response.Close();
}
catch
{
throw new HttpException( 404, "Failed to process image." );
}
}
public bool IsReusable
{
get
{
return true;
}
}
}
}
I bought this book on a whim, and now, even though I'm only halfway through, I can thoroughly recommend it to any programmer.
Beautiful Code: Leading Programmers Explain How They Think
It's not a book of facts or techniques, rather it's thirty-odd "presentations" by different authors about the code they think is most beautiful. If you're anything like me you're not going to agree with 100% of these, and in fact I thought one chapter involving FORTRAN was horrific ugly code, but it will definitely get you thinking.
Why you might want this book:
And if you're still not convinced, all author royalties from this book will be donated to Amnesty International.
Having been using Visual Studio 2008 "Codename Orcas" Beta 1 (breathe) for a while now, I was excited to see that Beta 2 is now available. These betas are stable, have some great new features, and are available as Virtual PC images (if like me you can't risk breaking a work machine), so there's really no excuse not to give it a try.
Unfortunately, I've hit two big breaking changes upgrading from Beta 1 to Beta 2, which is surprising given Microsoft's usual commitment to backwards-compatibility; hopefully this won't be the shape of things to come.
Firstly, double-clicking any solution (.SLN) files created in Beta 1 doesn't do anything. The trick is to load it up into Notepad and change the line:
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio Codename Orcas
to:
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
I can't see any reason why the old format couldn't have been detected or upgraded in this situation.
Secondly, and far more seriously, if you've previously created any LINQ-to-SQL schema files (.DBML), well, they're just junk now. The file format has changed and I can't see any way of upgrading from the old to the new. I'm glad Microsoft aren't sticking with sub-optimal designs just for backwards-compatibility, but if they want us to really get stuck into the betas, especially in key new feature areas, then upgrade paths are a must.