Monday, December 29, 2008

Some Facebook Connect problems

While continuing to hook up the http://www.runsaturday.com website with Facebook Connect I hit a problem with an ASP.NET Server (User) Control which was working well in one page but refused to work at all in another.

When debugging the Javascript using Firebug I could see that in one page I was getting the error - "hostWindow.FB.XdComm is undefined" inside the script xdcommreceiver.js on line 66  "func = hostWindow.FB.XdComm.Server.singleton.onReceiverLoaded;" - although this wasn't at first apparent as that line is wrapped in a "catch" statement by Facebook.

What I eventually deduced was.... somehow I'd included the facebook javascript init code twice in the same page. Sorting this out, made everything work OK again... phew!

A static Google Maps proxy in C#

Following on from this blog post - http://hasin.wordpress.com/2008/10/31/wrapper-for-google-static-map-api/ - I thought I'd have a go at my own proxy for Google static Maps in C#

This simple HTTP Handler is the core of what I wrote.

The reason I wrote it.... facebook doesn't seem to like talking to googlemaps directly.

The potential problem.... I think this falls completely within their guidelines (I am still using google maps within a web page), but I think my website could easily overreach their loading quotas - a limit of 1000 requests per user per day (and I think my website proxy will count as one user?)

I'll see how it goes....



using System;

using System.Web;

using System.Net;

using System.IO;

 

namespace MapControl

{

    public class GMapProxy : IHttpHandler {

 

        static void CopyStream(Stream input, Stream output)

        {

            byte[] buffer = new byte[0x1000];

            int read;

            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)

                output.Write(buffer, 0, read);

        }

          

        public void ProcessRequest (HttpContext context)

        {

            string gmapUri = string.Format("http://maps.google.com/staticmap{0}", context.Request.Url.Query);

            WebRequest request = WebRequest.Create(gmapUri);

 

            using (WebResponse response = request.GetResponse())

            {

                context.Response.ContentType = response.ContentType;

                Stream responseStream = response.GetResponseStream();

               

                CopyStream(responseStream,context.Response.OutputStream);

            }

        }

    

        public bool IsReusable {

            get {

                return false;

            }

        }

    }

}


Sunday, December 28, 2008

Uploading large files to an ASP.NET app....

I wanted to let users upload potentially large xml files to my latest web app.

This can be achieved using the simple FileUpload control in ASP.

However, this basic control is very ugly and doesn't give much feedback.

Also, it doesn't seem to offer any zip compression support.

So I had a look around.
I think ultimately I'll follow Steve's approach... but in the meantime I've just decided to do the zip file parsing myself - using the excellent http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx - which is already included in DNN.

The downside of this is that in the short term:
  • I'm forcing the users to continue to suffer from the lack of UI feedback during large uploads...
  • I'm forcing the users to zip files themselves.

Sorry for now, users!

What's new in DNN5

So it seems DNN have been busy over the Xmas period - including launching DNN 5 - http://www.mitchelsellers.com/blogs/articletype/articleview/articleid/279/dotnetnuke-491-and-500-released.aspx

Here's the official blog announcement - http://www.dotnetnuke.com/Community/Blogs/tabid/825/EntryId/2122/DotNetNuke-5-0-0-Released.aspx

And here's the full change release notes (way too much detail) - http://support.dotnetnuke.com/Main.aspx?ReturnUrl=%2fproject%2fChangeLog.aspx%3fPROJID%3d2&PROJID=2

So here's the highlight bullet points:
  • There's new support for XHTML and CSS in skins - removing lots of the non CSS features (table dependent things) - skins should now be much easier to design - they should be less DNN specific.
  • jQuery support has been added - along with a widget framework (widgets being a bit like modules only 100% javascript)
  • Beneath the covers there are more unit tests and more testability - which should lead to long term improvements and stability
  • IE8 web slice support has been added
  • The installer has been improved
  • Admin pages are now no longer quite so special - they're now just normal pages with admin rights - also "deny" has been added as well as "allow" to all the permissions grids.
So.... overall it doesn't seem that big a set of changes... but it is the way forwards.... so time for me to install it (even though I normally wait for a week or two to let key security and other fixes come to light)

Some cloud hosting options

I've been looking at various alternatives for cloud hosting recently.

My particular requirements are for a .NET host (so I need windows)

For cloud hosts in the UK:
- I had a look at Flexiscale - they seem to have a had a few negative customer reviews
- Then I had a look at elastichosts - they say they support Windows - but you'll need to install it yourself.
- I looked at Mosso - they seem reasonable but don't really give you much control - e.g. if I wanted the chart control installed then I'd have to submit a ticket and hope...
- And Amazon Europe are Dublin based (I think) but they are Linux not Windows at present.

I think I'm going to end up on Amazon EC2 in the US... but now I do also have an Azure invite - so I'll definitely also be giving that a spin.

Skiing was fabulous and....

Skiing Les Arcs was lovely - some great snow and wall to wall (slope to slope) sunshine - especially offering some really fabulous views of Mont Blanc:


And now I've returned home to discover.... that on xmas eve Microsoft sent me a present:

Thank you for your interest in Windows© Azure™.

Your invitation code is XXXXX-XXXXX-XXXXX-XXXXX-XXXXX.

You can now sign up for a Windows Azure account at http://lx.azure.microsoft.com/fs. Please keep this email in a safe place.
This invitation to participate in the Windows Azure Community Technical Preview is subject to the following usage limits:

Total compute usage: 2000 VM hours
Cloud storage capacity: 50GB
Total storage bandwidth: 20GB/day

During the CTP, we reserve the right to suspend your account activity (this does not imply we will delete your cloud storage) if you exceed these usage limits.

Sincerely,
Azure Services Platform Team


Yes! 2009 is going to be fun :)

Friday, December 19, 2008

Going dark - going white!

I'm heading off skiing to the Alps for Christmas week.... so will be taking a break from all this incessant techie posting!

But I will be back soon to launch a site or two - maybe including using EC2....

Other things coming soon.... C# 4.0 would be nice.... and maybe one day I'll get an Azure invite?

Happy Christmas all!

Quick link - to remind myself... Amazon S3 best practices

This thread points to best practices for S3 development - very much something I need to keep reading over...

http://developer.amazonwebservices.com/connect/thread.jspa?threadID=26225

Setting up a pie chart so that each segment has the color of your choice

Just answered this question - http://social.msdn.microsoft.com/Forums/en-US/MSWinWebChart/thread/8e9b49d5-2e06-4c8b-a932-4da924adc0a2

Here some example code...

        int runListColorIndex = startingIndex;

        int bikeListColorIndex = startingIndex;

        int swimListColorIndex = startingIndex;

        foreach (DataPoint p in series.Points)

        {

            ChartHatchStyle hatchStyle = ChartHatchStyle.None;

            Color colorToUse = Color.ForestGreen;

            switch (p.AxisLabel[0])

            {

                case 'R':

                    colorToUse = myCurrentFilterOptions.RunColor;

                    hatchStyle = HatchArray[runListColorIndex];

                    runListColorIndex++;

                    runListColorIndex %= HatchArray.Count;

                    break;

 

                case 'B':

                    colorToUse = myCurrentFilterOptions.BikeColor;

                    hatchStyle = HatchArray[bikeListColorIndex];

                    bikeListColorIndex++;

                    bikeListColorIndex %= HatchArray.Count;

                    break;

 

                case 'S':

                    colorToUse = myCurrentFilterOptions.SwimColor;

                    hatchStyle = HatchArray[swimListColorIndex];

                    swimListColorIndex++;

                    swimListColorIndex %= HatchArray.Count;

                    break;

            }

            p.Color = colorToUse;

            p.BackHatchStyle = hatchStyle;

        }




ThreeSharp - AWS C# Access - superb! Second attempt at posting!

Let's try that code again.... it got garbled...

using System;

using System.Collections.Generic;

using System.Text;

using Affirma.ThreeSharp.Model;

using Affirma.ThreeSharp.Query;

using System.IO;

using System.IO.Compression;

 

namespace Affirma.ThreeSharp.Wrapper

{

    public class SlodgeThreeSharpWrapper : ThreeSharpWrapper

    {

        public SlodgeThreeSharpWrapper(String awsAccessKeyId, String awsSecretAccessKey)

            : base(awsAccessKeyId, awsSecretAccessKey)

        {

        }

 

        /// <summary>

        /// Adds a string to a bucket, as an object - but compress it first!

        /// </summary>

        public void AddStringObjectWithCompression(String bucketName, String keyName, String data)

        {

            string compressedData = Compress(data);

            this.AddStringObject(bucketName, keyName, compressedData);

        }

 

        /// <summary>

        /// Gets a string object from a bucket, and returns it as a String

        /// </summary>

        public String GetStringObjectWithDecompression(String bucketName, String keyName)

        {

            string compressedData = GetStringObject(bucketName, keyName);

            return Decompress(compressedData);

        }

 

        // The origin of the compress/decompress code in this region is unclear

        // - it seems to be listed in many blogs

        // Plus it looks identical to book content...

        // Regardless, it doesn't look like it will be any infringement of IP to use it!

 

        private static string Compress(string text)

        {

            byte[] buffer = Encoding.UTF8.GetBytes(text);

            MemoryStream ms = new MemoryStream();

            using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))

            {

                zip.Write(buffer, 0, buffer.Length);

            }

 

            ms.Position = 0;

            MemoryStream outStream = new MemoryStream();

 

            byte[] compressed = new byte[ms.Length];

            ms.Read(compressed, 0, compressed.Length);

 

            byte[] gzBuffer = new byte[compressed.Length + 4];

            System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);

            System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);

            return Convert.ToBase64String(gzBuffer);

        }

 

        private static string Decompress(string compressedText)

        {

            byte[] gzBuffer = Convert.FromBase64String(compressedText);

            using (MemoryStream ms = new MemoryStream())

            {

                int msgLength = BitConverter.ToInt32(gzBuffer, 0);

                ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

 

                byte[] buffer = new byte[msgLength];

 

                ms.Position = 0;

                using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))

                {

                    zip.Read(buffer, 0, buffer.Length);

                }

 

                return Encoding.UTF8.GetString(buffer);

            }

        }

    }

}

Adding string compression to the ThreeSharp wrapper

I wanted to store XML blobs on AWS.

However, these are notoriously bloated - so I thought I'd zip them first (yes, I know there are other compression formats available!)

Note - this optimisation was more for the benefit of network latency rather than for reducing required storage.

To do this I built this class (I added it to the existing namespace - you might want to use the code somewhere else?) - the two methods of importance are:
  • AddStringObjectWithCompression
  • GetStringObjectWithDecompression
On my xml data this took a typical stored data size down from about 233628 bytes to 30012 bytes which will save me bandwidth costs, storage costs and will save me both network delays and help me avoid dropouts too - but admittedly it might cost me some compute power on the encode and decode.

Enjoy!

SNIP - Code moved to new post - http://slodge.blogspot.com/2008/12/threesharp-aws-c-access-superb-second.html - blogger garbled the first one (I must move to a better platform!)

ThreeSharp - AWS C# Access - superb!

Following up from yesterday I've signed up for an AWS account (the clock is now ticking!) and I've been playing with this ThreeSharp library - http://www.codeplex.com/ThreeSharp/

All I can say is it is superb - very easy to use and looks very good all round :)

Only problem I've had so far is that the wrapper does not support European domains by default - you get a message about needing to specify the endpoint - the way around this is to add the SUBDOMAIN Format specifier to the wrapper constructor

        public ThreeSharpWrapper(String awsAccessKeyId, String awsSecretAccessKey)

        {

            this.config = new ThreeSharpConfig();

            this.config.AwsAccessKeyID = awsAccessKeyId;

            this.config.AwsSecretAccessKey = awsSecretAccessKey;

            // added by Stuart

            this.config.Format = CallingFormat.SUBDOMAIN;

 

            this.service = new ThreeSharpQuery(this.config);

        }


Summary - a really good library - really easy to use - thanks to Affirma!

Writing text to an iframe in Javascript

A simple example - writing text to an iframe - note that if you don't close() the document each time then firefox shows you it's still downloading the outer page content - on vista you'll see the circle of download.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head>

    <title>Untitled Page</title>

</head>

<body>

       

<script type="text/javascript">

    var i = 0;

    function doThing() {

        i++;

        var a = document.getElementById("stepsAchieved");

        a.contentWindow.document.write("Here again " + i + "<br/>");

        a.contentWindow.document.close();

    }

</script>       

<input type="button" value="hello" onclick="doThing();return false;" id="fred"/>

<hr />

        <iframe src="" id="stepsAchieved" name="garminStepsAchieved" frameborder="1" height="200px" width="340px" scrolling="auto">

        </iframe>

</body>

</html>

Thursday, December 18, 2008

Cloud time again?

No... there still isn't any news on the Azure invitiation front.

Instead, this is a post about the fact that I'm probably going to have to resort to using some S3 storage for my current project. The reason? I've done my sums and it's needed!

According to my current estimates... it's not going to be unusual for one of my users to require 50MB of storage... so if I have 100 users... then I'll need 5GB... and if I get to 10000 users.... then I'll need 500GB. Based on this, it's definitely time to change my storage model - and (since Azure won't let me play) then that means it's now time for Amazon S3.

And the best place to start looking at this seems to be... three sharp - http://www.codeplex.com/ThreeSharp/ - looks like a really good project from http://www.affirmaconsulting.com/ - thanks guys  :)

Escaping javascript strings

I wanted to write out javascript string literals as safely as I could. The only problem being special characters - e.g. ', <, >, etc.

I used this blog post as a base: http://www.wwco.com/~wls/blog/2007/04/25/using-script-in-a-javascript-literal/

This is the C# I now have in place:

        // see http://www.wwco.com/~wls/blog/2007/04/25/using-script-in-a-javascript-literal/

        private static String EscapeJavascriptStringLiteralPlease(String str)

        {

          str = str.Replace("\\","\\\\"); // escape single backslashes

          str = str.Replace("'","\\'"); // escape single quotes

          str = str.Replace("\"","\\\""); // escape double quotes

          str = str.Replace("<","\\<"); // escape open angle bracket

          str = str.Replace(">","\\>"); // escape close angle bracket

          return str;

        }


But was there a way I could have done this straight from the standard ASP.Net libraries?

Into subversion

I'm finally setting up a new subversion source control system at home.

It's a bit scary how little instructions I'm reading in order to set this up (will have to go back and do it properly later?) - but I seem to be up and running now with VisualSVN as my server and with AnkhSVN as my source control plugin in Visual Studio

The only big problem I've had so far (other than not know what I'm doing) was with the database - I can't seem to get the SQL express database to have sufficient open security for IIS7.... this all came about because I moved folders...

I get this problem - http://social.msdn.microsoft.com/forums/en-US/sqlexpress/thread/6dfdcc22-7a81-4e8f-a947-c1ce6982d4b3/ - but none of the hints I've found solve it for me...

I will work this out!

String.Format - how do you escape curly braces

Took me a little bit of googling to find this out...

Basically if you want your output to be "{like INPUT_HERE this}" then you need to use:
string.Format("{{like {0} this}}", input);

i.e. you escape the curly braces by doubling them up.

CSS Dreams....

One of the things I've been slowly getting my head round is CSS.

I think mainly because I've been working with some old ASP.NET and DNN controls, this has proven quite hard.

However, it's also clear that CSS itself is quite hard sometimes....

All I wanted to do was arrange my screen as

IMAGE TEXT

IMAGE TEXT

IMAGE TEXT

Where IMAGE is of an unknown height and TEXT is also multiline.

The sort of thing it would be easy to do with tables....

But it's proving very tricky in CSS. I keep getting effects like

IMAGE TEXT

IMAGE TEXT
TEXT CONTINUED

IMAGE TEXT

I've been all over the shop looking for solutions - faux columns provided some respite... but overall it's nasty! And I could have achieved the effect I wanted with tables in seconds....

Wednesday, December 17, 2008

Forcing some line breaks...

This post gave me a good idea
http://gojomo.blogspot.com/2005/03/cross-browser-invisible-word-break-in.html

In my ASP.NET code I was generating a long url with lots of ....&i=23&j=2343&k=232....

Internet Explorer was very strict at not line breaking this - so I need to encourage it.

Using the post above I decided on:

Response.Write(GenerateFullHRef(true).Replace("&", "&[wbr/]"));

Seemed to work well :)

Note to self - it's time to get a proper tool to post to blogger - this HTML code formatting is doing my nut in!

Azure Invitiation code still not received :(

Just still tracking this....

Can't believe I ever believed I would get this within a week or two of signing up....

I wonder if I'll get it for Christmas?

Changing a chart to store the image on disk

If you want the Microsoft Chart Control to use real semi-persistent URLs for images rather than using charting.axd then:

1. change the web.config settings to include

[add key="ChartImageHandler" value="storage=file;timeout=20;dir=e:\inetpub\yourapp\temp\;deleteAfterServicing=false"/]

2. add this code to your chart initialisation

Chart1.ImageStorageMode = ImageStorageMode.UseImageLocation;
Chart1.ImageLocation = Request.ApplicationPath + "/temp/ChartPic_#SEQ(300,3)";

That seems to work for me :)

One word of warning though: This does open up a security hole - it means charts can be requested multiple times and URLs can be guessed!

Chart - allowing the image to be downloaded multiple times

When using the Microsoft Chart Control in ASP.NET, if you edit webconfig, then you can allow multiple downloads of the same chart image using the deleteAfterServicing key with a false value

[configuration]
[appsettings]
[add key="ChartImageHandler" value="storage=file;timeout=20;dir=e:\inetpub\whatever\temp\;deleteAfterServicing=false" /]
[/appsettings>
[/configuration]

Tuesday, December 16, 2008

Experimenting with facebook connect and Dotnetnuke

I've been spending a little time trying to get Facebook connect integrated with a DotNetNuke portal.

On the technical side, I've been using the Facebook Toolkit from Codeplex and this link on stackoverflow was very useful for working out the cookie confusion: http://stackoverflow.com/questions/323019/facebook-connect-and-aspnet

Currently, it's all gone quite smoothly :)

The only problems I've had:
  • My skin didn't initially specify XHTML - so I had to add a .doctype file to my skins directory - if your skin is called AAA.ascx then you need to add AAA:


    [skindoctype]
    [![CDATA[ [!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"] ]] ]
    [/skindoctype]


  • In order to add the xmlns for fb I did have to change the default.aspx code from DNN - it's not a big change, but it's still a bit sad I have to change the core :(

  • I messed up the ordering of the facebook elements at one point.... for clarification, make sure that FB.init("API_KEY_HERE", "/dnn/connect/xd_receiver.htm"); is the last thing seen on your web page - not the first!

  • I've been fighting with the lack of documentation - facebook seem to be relying on us dissecting their runaround example app...

  • I've hit some problems with API calls resulting in "Session key expired or no longer valid" - but these are basically due to the user logging out of facebook - easy to workaround.

  • Similarly when the user has logged out of facebook I've hit some problems with facebook's automatic buttons (e.g. with fb:login) - but again these are easy to workaround - you just use your own facebook links instead of the automatic buttons.
Anyways.... now I've got the first stage working, it's time to really start exploiting the integration.... be back later....

Using the AJAX Toolkit Tab Control in DNN DotNetNuke

I love this tab control

However, when I came to use it in my DNN module I found it only displayed half the tabs...

A (not so quick) google revealed... http://vladan.strigo.net/2007/04/02/having-issues-displaying-ajax-control-toolkit-tab-control-in-dotnetnuke/

Basically the advice is to include this locally to your module:


:)

Follow up on the "Error executing child request for ChartImg.axd."

Just as a follow up to that last post

Have it reproducible.

- If I restart the webserver each time (I'm using the dev web server at present) with the chart inside the wizard then I get the error - until I move the chart outside the wizard.

- If I restart the webserver with the chart outside the wizard then it works, then when I move the chart inside the wizard again, then it still works.

(Not sure it's relevant, but in this current app my page contains a user control in which I've placed the wizard inside the last step of which I've placed another custom control inside which I've placed the chart)