Showing posts with label Downloadable. Show all posts
Showing posts with label Downloadable. Show all posts

Sunday, April 3, 2011

Cookieless Session State in ASP.NET without nasty URLs

Some of you have probably heard about the EU proposal that plans to end the internet as we know it on May 25th 2011. If you haven’t heard of it, David Naylor has made a nice little example of it’s consequences here. In essence most sites that use cookies will have to ask visitors to opt-in for every single cookie before using it. I’m very  much in favor of online privacy – yet it seems to me that this is a very poorly thought through directive. First of all, most cookies server 1 of 2 purposes:

  • Help web sites recognize visitors in order to provide them with the best possible service. Much like when I walk into my local barbershop and the barber recognizes me and knows exactly how I prefer him to cut my hair (the little I have left after reading crazy directives) – and which subjects I want to small talk about.
  • Visitor tracking in order to do statistics the site owners can use to improve the web site with. Again – it’s not all that different from when a grocery store owner thinks “wow – 10 customers this last week has asked me for low-fat milk. Perhaps I should start to carry that product here”.

I have no problem with both of the above scenarios – they fall into what I call good service and help enhance my online experience.
Another problem is that I generally dislike when legal stuff comes in the way for the best technical solution to a problem. Laws should describe the concept of what they are outlawing – not specific technical architectures such as cookies…But before I digress any further into political territory I’ll get right back on track.

Many ASP.NET developers rely on the Session State mechanism to store user relevant data within a visit, that can improve the user experience – for instance with personalization, prefilled forms, and so on. Unfortunately the Session state relies on a unique session key being stored in a local cookie in order to have a unique way to identify the same visitor throughout a visit. It actually comes with a built-in switch to make it stop using cookies – but unfortunately the solution looks rather ugly – it changes all the URLs on the site to contain a Guid and thereby track the visitor using the Guid. I, for one, am rather fond of clean and pretty friendly urls – so that’s no good. So – I started thinking…Many years ago I worked for a company that built a statistics tool. It was pretty unobtrusive and we didn’t use cookies. Instead we just tracked the source IP – and checked for repeated requests with a 10 minutes time-out. Sure, it wasn’t bullet-proof, but it actually worked surprisingly well. And in those cases where it didn’t work? Well – it was just 1 statistical entry out of many. It’s not like we used it to authorize access to the nuclear football, right?! Now, I thought that if we combine all the static information we get in the HTTP Request like IP, Accept Languages, Accept Types, User Agent and so on, smash it all together and take a fingerprint of it – we might end up with something that can almost be used as a session id. Consider: What are the odds that you’ll get 2 different visitors using the exact same configuration, coming from the exact IP on your site within the 20 minutes default time-out??
Of course it turns out I wasn’t the first to think this thought. In fact the clever people at the Electronic Frontier Foundation (EFF) has for some time been running a little example site that calculates those exact odds – just to prove that Privacy online isn’t solved by simply outlawing cookies.

So – I decided to put the thoughts into code. The code consist of 2 parts. First part is an extension method for the HttpRequest class, called “GetUniqueFingerprint()” which will return a MD5 Hash fingerprint.

using System;



using System.Collections.Generic;



using System.Linq;



using System.Web;



using System.Text;



using System.Security.Cryptography;



 



namespace AllanTech.NoCookie



{



    public static class NoCookies



    {



 



        static private string GetMd5Sum(string s)



        {



            Encoder enc = System.Text.Encoding.Unicode.GetEncoder();



            byte[] text = new byte[s.Length * 2];



            enc.GetBytes(s.ToCharArray(), 0, s.Length, text, 0, true);



            MD5 md5 = new MD5CryptoServiceProvider();



            byte[] result = md5.ComputeHash(text);



            StringBuilder sb = new StringBuilder();



            for (int i=0; i<result.Length; i++)



            {



                sb.Append(result[i].ToString("X2"));



            }



            return sb.ToString();



        }



 



        public static string GetUnqiueFingerprint(this HttpRequest Request)



        {



            string source=



                string.Join(",", Request.AcceptTypes)+";"+



                string.Join(",", Request.UserLanguages)+";"+



                Request.UserHostAddress+";"+



                Request.UserAgent;



            return GetMd5Sum(source);



        }



    }



}






Second part is a replacement for the ASP.NET SessionIDManager. This is the mechanism that uniquely identifies the visitor – either by a cookie or url – and by replacing it we can make it use our new UniqueFingerprint method instead. It’s really simple – just implement the ISessionIDManager and you’re good to go:





using System;



using System.Collections.Generic;



using System.Linq;



using System.Web;



using System.Web.SessionState;



 



namespace AllanTech.NoCookie



{



 



    public class CookielessIDManager : ISessionIDManager



    {



        public CookielessIDManager() { }



 



        #region ISessionIDManager Members



 



        public string CreateSessionID(HttpContext context)



        {



            return context.Request.GetUnqiueFingerprint();



        }



 



        public string GetSessionID(HttpContext context)



        {



            return context.Request.GetUnqiueFingerprint();



        }



 



        public void Initialize()



        {



            



        }



 



        public bool InitializeRequest(HttpContext context, bool suppressAutoDetectRedirect, out bool supportSessionIDReissue)



        {



            supportSessionIDReissue=true;



            return context.Response.IsRequestBeingRedirected;



        }



 



        public void RemoveSessionID(HttpContext context)



        {



        }



 



        public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)



        {



            redirected=false;



            cookieAdded=false;



        }



 



        public bool Validate(string id)



        {



            return true;



        }



 



        #endregion



    }



}




Finally, all I have to do is to change the configuration (web.config) to use my CookielessIDManager instead of the default:



<sessionState mode="InProc" sessionIDManagerType="AllanTech.NoCookie.CookielessIDManager,AllanTech.NoCookie" … /> 



Enjoy a site with 1 less cookie!

Monday, August 2, 2010

A simple, little web load tool

There are many ways of doing performance testing of web applications. In the good ol’ days I remember starting up Microsofts Application Center Test (ACT) and recording some vbscripts that could later be executed. Nowadays ACT is a lot sexier – but now it comes with Visual Studio 2010 but unfortunately only in Ultimate edition. I tried to persuade my wife to spend the $11000 on the ultimate edition – but she failed to see why this was more important than buying her a car.

Another good option is to use WebLoad. It’s a neat tool – and even if you buy it (to actually get a compiled and running version instead of the do-it-yourself-open-source) it still comes at a more decent price point. I recently played around with it – and it does solve a lot of your performance testing needs – but it’s almost a bit too much overkill for my need (which is essentially to find out how many request/s a web site can handle). I also didn’t like that it hijacked all my browsers and forced them to go through a proxy (in order for it to record what was going on) – and then failing to reset the proxy selection afterwards.

In the end I decided to spend the 30 min it would take to do a simple little performance tester of my own – that does exactly what I want it to.

I came up with AWebLoadTesting which is a compact and ultra-simple console app. It takes an input file which is essentially a text file with a list of urls to visit for each visitor during the test, an output filename – in which it will put a csv file with saved statistics – and that’s about it. If you need to you can also specify a hostname to run the test against – and even a custom UserAgent for the requests.

image

When it starts you have 0 visitors active. Then, by pressing “+” you can add visitors one at a time – and by pressing “1” and “5” you can add chunks of 10 or 50 visitors at a time. Each visitor is started in its own thread and will continuously go through the urls from the input file again and again.

“u” updates your view, “r” resets the counters", “s” saves the current data to the output file, “-“ removes a visitor” and of course “q” quits.

You’ll constantly be presented with the measured numbers: Time measured (s), Requests / s, Visitor count, Max load time, average load time and min. load time. On top of that it will show you a prioritized list of which urls are the slowest to return. That’s it.

The screenshot above is a test against a local EPiServer CMS 6.0 web site on my laptop, running with ASP.NET caching turned on (Set cache-expiration to 1h in episerver.config, site settings).

Download the binary here and the entire project here. Use AS-IS, LGPL 2.0, Quick&Dirty.

Sunday, August 2, 2009

Guest Post: Конвертирование FB2 в PDF для Sony Reader PRS-505

image

Я - счастливый обладатель Sony Reader PRS-505!
Однако взявшись за чтение книг на русском языке, я обнаружила, что формат, в котором можно скачать большинство книг на русском в интернете FB2, не поддерживается моим Reader. Возникла проблема - как сконвертировать FB2 в один из форматов, поддерживаемых Sony Reader (например, PDF).
Найденная в интернете веб страничка http://fb2pdf.com/ , которая позволяет сконвертировать формат в PDF, к сожалению, сработала только в первый раз. В остальных случаях конвертация занимала слишком долгое время.
К счастью, мой муж - волшебник, и по совместительству программист, создал программу, которая позволяет сконвертировать FB2 в PDF в считанные секунды, и он безвозмедно предлагает ее всем любителям (электронных) книг на русском языке.
Загрузить программу можно здесь.

New Tool: Convert .FB2 files to PDF

ereader

It all started a couple of months ago when my wife, @othraen, got her Sony eReader. She loves it, and reads a couple of books a week on it. I can definitely see why she likes it – it’s slick, simple, and very pleasant to read on. Great toy, if you like books!

Anyway, with the speed she’s reading, not even the 5000000000000000 (or whatever count they reached now) free titles at Google Books is enough, and she’s started looking online for public domain Russian language books (most Russian is like Greek to me, but she likes it :-) ). As it turns out most of the Russian e-books online are in the FictionBook 2 format (.FB2). It’s an open XML format, probably defined by a league of Russian e-book publishers or so – it doesn’t seem to be all that popular in the rest of the world.

As you might imagine, the friendly people at Sony didn’t take this into consideration when planning on which formats to use in the eReader, so it is not supported. However, our friend, good old reliable PDFs are of course supported. It didn’t take many Google searches to find the fb2pdf.com website – a site devoted to converting fb2 files to PDF. It worked great on the first book….And on the second book. But later on, several of the books she tried to convert wouldn’t work. It would just freeze up and we could wait for ever and ever. As it so often happens, this resulted in the statement I fear so much “Honey, can’t you spend a little less time playing around with that programming stuff and a little more helping me get this book I want to read on my ereader??!” (yes, one of those questions where there’s only one right answer). In this case it would have made sense to simply drop a mail to the owners of the before mentioned website, asking them to fix whatever bug that caused the conversion to fail – but I was determined not to let this be the first time I give in to common sense :-)

image Instead this was a perfect opportunity to take a closer look at FB2, PDFs, the iTextSharp library, SharpZipLib and ClickOnce deployment. At the same time, I’d get to program in my spare time – and with a perfect excuse – helping her :-)

It didn’t take much more than a couple of hours before I had a working windows application, that can load .fb2 files (or zip-files containing 1 .fb2 file), correct / change their Author / Title (since the ereader doesn’t seem to support Cyrillic characters in the title browsing menu), and convert into a PDF. It’s a ClickOnce application, which means you can install it directly from it’s online source – and it will automatically get updated if I upload a new version. The only tricky thing in developing it was actually embedding a font to show the Cyrillic Unicode characters that most Russian books are comprised of.

[UPDATE 2009-12-20] I finally found some time to fix a few bugs and add two new check-boxes: "Optimize for Sony Reader" and "Optimize for Kindle". Right now, all they do is to optimize page-sizes, so it should work better on the respective devices - but in the future they might also adjust font, font-sizes, etc. Let me know how well it works - I don't have a kindle, so I can't test it myself. Update should install itself.

Install the FB2 to PDF Converter tool from here.