Scott Hanselman

Put Missing Kids on your 404 Page - Entirely Client-Side Solution with YQL, jQuery, and MSAjax

February 25, '10 Comments [51] Posted in ASP.NET | ASP.NET Ajax | Open Source
Sponsored By

image I noticed a post over at a blog called "The other side of the moon" where the author suggests that we put pictures and details of missing children on on 404 pages. It's a simple and brilliant idea. Millions of 404s are delivered every day. We are reporting on missing pages, but not on missing children. He includes a simple PHP solution. I set out to create an ASP.NET solution, but then realized that a server-side solution wasn't really necessary.

Could I do it all on the client side? This way anyone could add this feature to their site, regardless of their server-side choice. This could make the solution much more palatable to folks who may not be into .NET.

Here's what I came up with. You can see it in action if you request a file that doesn't exist from my site, like http://www.hanselman.com/foo.aspx.

The file is called missingkids404.html and it's just static html. You will need to configure your webserver to serve this page when it needs to serve a 404. For me, as I do run ASP.NET and IIS, I needed to add this to my web.config in the System.Web section:

<customErrors mode="On"> 
<error statusCode="404" redirect="/missingkids404.html" />
</customErrors>

The file, in its entirety, is this:

<html>
<head>
<title>Missing Kids 404</title>
<style type="text/css">
.sys-template { display:none; }
.missingkid { clear:both; }
</style>
<script src="http://ajax.microsoft.com/ajax/beta/0911/Start.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
Sys.require([Sys.components.dataView, Sys.scripts.jQuery], function() {
$("#missingkids").dataView();

var statecode = "ZZ";
var dataurl = "http://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20From%20xml%0D%0A%20Where%20url%3D'http%3A%2F%2Fwww.missingkidsmap.com%2Fread.php%3Fstate%3D" + statecode + "'%0D%0A&format=json&callback=?";
var data = $.getJSON(dataurl, function(results){
Sys.get("$missingkids").set_data(results.query.results.locations.location);
}
);
});

function getSrc(url) {
var lastIndex = url.lastIndexOf('=');
return url.substring(lastIndex+1);
}
</script>

<p>
<strong>Sorry, the page you're trying to find is missing.</strong>
</p>
<p>
We may not be able to find the page, but perhaps you could help find one of these missing children:
</p>

<div id="missingkids" class="sys-template">
<div class="missingkid">
<img sys:width="60" sys:align="left" sys:src="{binding medpic, convert=getSrc}" />
<strong>{{firstname + " " + lastname}}</strong>, Age: {{age}} from
{{city}}, {{st}}</br>
Contact: {{policeadd}} at {{policenum}}<br/>
<br/>
</div>
</div>
</body>
</html>

I'm using the standard {{token}} syntax as well as one custom syntax with a convert=callback so I can pre-process the data. The source data feed includes an unfortunate chunk of html, rather than a direct link to a picture. I need to strip everything after the last equals sign (=) in order to get the image src URL. That method is called getSrc, and the binding looks like:

<img sys:width="60" sys:align="left" sys:src="{binding medpic, convert=getSrc}" />

If this is useful, the next step is to add geolocation. You can look at http://www.hanselman.com/missingkids404geo.html for the beginnings of a geo-location aware one. The open issue right now is that the missing kids feed works only in the US, Canada and the UK. I would need to figure out now to determine the two-letter STATE code from the geolocation API, which doesn't provide codes in that way. Worst case scenario, I'd have a lookup table of state names to abbreviations.

Enjoy! Thoughts?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Hanselminutes Podcast 202 - A different way to do ASP.NET WebForms with WebFormsMVP

February 21, '10 Comments [10] Posted in ASP.NET | ASP.NET MVC | Open Source | Podcast
Sponsored By

2008-GrafittiSmall My two-hundred-and-second podcast is up. I sit down (in my home, actually) with Tatham Oddie to talk about the WebFormsMVP open source project created by he and Damian Edwards.  What does it add?  Can we have the best of both worlds, convenience, controls and testability?

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

Download: MP3 Full Show

Links from the Show

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

I want to add a big thanks to Telerik. Without their support, there wouldn't be a Hanselminutes. I hope they, and you, know that. Someone's gotta pay the bandwidth. Thanks also to Carl Franklin for all his support over these last 4 years!

Telerik is our sponsor for this show.

Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface and developer tools, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET AJAX,MVC,Silverlight, Windows Forms and WPF. Enjoy developer tools like .NET reporting, ORM, Automated Testing Tools, TFS, and Content Management Solution. And now you can increase your productivity with JustCode, Telerik’s new productivity tool for code analysis and refactoring. Visit www.telerik.com.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Hanselminutes Podcast 201 - The Making of a Open Source MonoTouch iPhone app with Chris Hardy

February 21, '10 Comments [0] Posted in Mono | Open Source | Podcast
Sponsored By

4248245993_aa337e2578_o My two-hundred-and-first podcast is up. Two Englishmen in a row? What a sellout I am. This week I chat with Chris "ChrisNTR" Hardy, an ASP.NET programmer by day who writes C# code for the iPhone by night. He took it upon himself to answer a tweet from me and write the beginnings of a "Hanselminutes iPhone Application." How did he do it? Now we just gotta get it in the App Store, and I need to start on a Windows Phone 7 version. ;)

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

Download: MP3 Full Show

Links from the Show

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

I want to add a big thanks to Telerik. Without their support, there wouldn't be a Hanselminutes. I hope they, and you, know that. Someone's gotta pay the bandwidth. Thanks also to Carl Franklin for all his support over these last 4 years!

Telerik is our sponsor for this show.

Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface and developer tools, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET AJAX,MVC,Silverlight, Windows Forms and WPF. Enjoy developer tools like .NET reporting, ORM, Automated Testing Tools, TFS, and Content Management Solution. And now you can increase your productivity with JustCode, Telerik’s new productivity tool for code analysis and refactoring. Visit www.telerik.com.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

The Weekly Source Code 50 - A little on "A generic error occurred in GDI+" and trouble generating images on with ASP.NET

February 18, '10 Comments [12] Posted in ASP.NET | Source Code
Sponsored By

I got a nice little Yellow Screen of Death (YSOD) error on some code running under IIS that worked fine when running on the VS Developer Web Server. The error was "A generic error occurred in GDI+" and you know that if an error is generic, it's sure in the heck not specific.

My little application takes an overhead map that's stored in a local file, does some calculations from user input and draws an X on the map, then returns the resulting dynamically generated image.

There's basically three ways to do images on the server side. Use Native APIs and Interop, which only works in full trust, use System.Drawing, which "isn't supported" or use WPF on the server side, which also, ahem, isn't officially supported. I'm still trying to figure out why, but just to be clear, I used System.Drawing in extremely high traffic sites with no problems. As long as paid close attention to my unmanaged resources, I have never had a problem. I've heard anecdotally of people having trouble with GDI+ (System.Drawing) and switching over to WPF and having no problem with that. As with all things, test what you're doing. There's even some ASP.NET Controls on CodePlex that might help.

Now this post can't answer ALL reasons you're getting "a generic error occurred in GDI+" but it can answer mine. In my particular case (and I think this is the most common mistake) I was saving the composited image as a PNG.

First, I'll show you a little chunk of a code from 5 years ago that took two images and built a single image from them.

public class SomeCheckImageHandler : IHttpHandler
{
//some stuff snipped

public SomeCheckImageHandler(){}

public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/jpg";

//some stuff snipped
GetCheckImageRequest req = new GetCheckImageRequest();
//some stuff snipped, get the params from the QueryString
GetCheckImageResponse res = banking.GetCheckImage(req);

//some stuff snipped
if (res.ImageBack != null)
{
//merge them into one image
using(MemoryStream m = new MemoryStream(res.BackImageBytes))
using(Image backImage = System.Drawing.Image.FromStream(m))
using(MemoryStream m2 = new MemoryStream(res.BrontImageBytes))
using(Image frontImage = System.Drawing.Image.FromStream(m2))
using(Bitmap compositeImage = new Bitmap(frontImage.Width,frontImage.Height+backImage.Height))
using(Graphics compositeGraphics = Graphics.FromImage(compositeImage))
{
compositeGraphics.CompositingMode = CompositingMode.SourceCopy;
compositeGraphics.DrawImageUnscaled(frontImage,0,0);
compositeGraphics.DrawImageUnscaled(backImage,0,frontImage.Height);
compositeImage.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
}
else //just show the front, we've got no back
{
using(MemoryStream m = new MemoryStream(frontImageBytes))
using(Image image = System.Drawing.Image.FromStream(m))
{
image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
}
}
}

This code generated a JPEG. No problems, runs fine even today. Now, the code I was working on created a PNG and when you create a PNG you need a seekable stream. This little sample uses the BaseHttpHandler Phil and I made.

Note the highlighted lines in this sample. (You'll see the highlights if you view this post on my blog directly, rather than from RSS.)

The Trick for making PNGs: Without the extra intermediate MemoryStream to save to, you won't be able to make PNGs. You can't image.Save() a PNG directly to Response.OutputStream.

namespace FooFoo
{
public class MapHandler : BaseHttpHandler
public override void HandleRequest(HttpContext context)
{
string filename = context.Server.MapPath(".") + @"\images\newmap2000.jpg";

using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
using (System.Drawing.Image image = System.Drawing.Image.FromStream(fs))
{
using (Graphics g = Graphics.FromImage(image))
{

BrickFinderDrawing drawer = new BrickFinderDrawing(...somedata...);
drawer.DrawBrick(g);
drawer.DrawName(g);

using (MemoryStream stream = new MemoryStream())
{
image.Save(stream, ImageFormat.Png);
stream.WriteTo(context.Response.OutputStream);
}
}
}
}

}

public override bool RequiresAuthentication
{
get { return false; }
}

public override string ContentMimeType
{
get { return "image/png"; }
}

public override bool ValidateParameters(HttpContext context)
{
return true;
}
}
}

Just a little something I wish I remembered when I hit the YSOD. Sure glad I have a blog to put this kind of stuff on! ;)

Related Links

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

DIY: Making a Very Wide Angle Webcam on the Cheap

February 17, '10 Comments [23] Posted in Remote Work | Reviews
Sponsored By

imageAfter I made my Webcam Cart and blogged about it a package I'd forgotten about arrived. It was a cheap "Zeikos ZE-WA37S 37mm 0.45X Wide Angle Lens." Only $10. I've looked all over for wide-angle webcams and they just don't exist. Over the counter webcams have a very narrow field of view.

I started with my favorite webcam, an amazing value, the Lifecam Cinema HD. I've got 4 of these. Now, the wide angle lens has a large opening, about an inch and a half, while the Lifecam is maybe an inch in diameter. I needed something to build up the diameter in such a way that it'd hold the wide angle lens in position while avoiding ruining the camera itself.

How? Electrical tape. Lots of it. I wrapped it around and around until it could offer enough outward tension to keep the lens on tightly.

Zeikos ZE-WA37S 37mm 0.45X Wide Angle Lens Lifecam with Wide Angle Zeikos Lens

Here's a still shot taken with the Lifecam Cinema HD with the lens it came with.

Lifecam HD Sample Photo

Here's a still shot taken with the same Lifecam Cinema HD with the cheap Zeikos Wide-Angle lens attached. Note the blurriness in the periphery and the slight fish-eye warping in the shelves.

Lifecam HD with Zeikos Wide-Angle Lens attached

The Lifecam is ideal for this kind of hack because it has a built in AutoFocus that REALLY works hard to keep things focused. I'll be using this for meetings and "getting a sense of the room" since I can't afford a $3000 "Roundtable" camera. I haven't measured it, but I fell I'm getting at least 100 degrees or more of field of view (my gut) so I think it's a good tradeoff of visual acuity for seeing a LOT more of the room for only $10.

Thoughts?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.