How to download .NET Reflector 6 for free

If you like, you can skip the introduction and jump to Downloading .NET Reflector.

A brief history of .NET Reflector

In the beginning

In case you somehow missed it, .NET Reflector is a class browser, analyzer, and decompiler for .NET assemblies. Originally created by Lutz Roeder, it proved to be an extremely useful tool, making lists such as MSDN’s Ten Must-Have .NET Tools Every Developer Should Download Now. Best of all, .NET Reflector was released to the community for free, with Roeder developing and supporting the tool for over 8 years.

The downfall

However, in August 2008, Red Gate Software bought .NET Reflector. At the time, Roeder was told that Red Gate will continue to provide the free community version. Red Gate themselves stated that The first thing we are doing is continuing to offer the software to the community for free downloading. It didn’t stay that way. In February 2011, Red Gate announced that from version 7, .NET Reflector would no longer be free.

This might have been acceptable, but for the fact that free copies .NET Reflector expired after several months. Upon expiry, users were prompted to update to the latest version; if they declined, .NET Reflector would simply exit, although some versions contained a time-bomb that completely deleted .NET Reflector if it was too old. Effectively, all existing free users of .NET Reflector would be forced to either stop using .NET Reflector, or pay for version 7. The community backlash was immediate.

Scorched earth

After two months, Red Gate finally relented, partially reversing their decision to disable the free version of .NET Reflector. However, rather than once more releasing a free community edition, they instead only enabled existing free versions of .NET Reflector to update to a version that does not expire. For those users who had a self-deleting version, Red Gate offered no help. They also offered no way for new users to download the free version of .NET Reflector.

To date, Red Gate’s promise of maintaining a free community version remains broken. It has been more than a year since they first announced that they were going back on their word, but nothing has changed. While there are now more alternatives to .NET Reflector than ever, it is unfortunate that this whole situation came about in the first place.

A brief history of LookingGlass

Like most things developers create, LookingGlass was born out of curiosity. The question: Is it possible to download .NET Reflector from Red Gate without already having a copy? After all, old versions need a way to download updates somehow. Updating an old copy of .NET Reflector while running Wireshark quickly provided the answer: .NET Reflector makes two HTTP requests to Red Gate’s servers, the first to determine the URL of the update, and the second to actually download it.

LookingGlass is a small program that reproduces .NET Reflector’s requests to Red Gate’s servers and saves the result to a file. A few hacks were necessary to perfectly emulate how .NET Reflector makes its HTTP requests (See line 87), including not reusing the HTTP connection despite the Keep-Alive headers (.NET Reflector’s built-in updater launches as a separate process). From Red Gate’s side, it should be impossible to tell the difference between the two.

Downloading .NET Reflector

Simply save the below code as a file (For example, LookingGlass.cs), compile it and run the resulting program. It will save the downloaded file to the same directory as the program itself. If necessary, you can download Visual C# Express for free, or use the C# compiler (csc.exe) that is included with every version of the .NET framework to compile this code. LookingGlass should work perfectly on .NET 2.0 and above.

// This is free and unencumbered software released into the public domain.
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;

namespace LookingGlass
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
                QueryDownloadUrl(@"http://reflector.red-gate.com/Reflector.version");
            else
                Download(args[0]);
        }

        static void QueryDownloadUrl(string versionUrl)
        {
            Console.WriteLine("Phase 1: Getting download URL...");

            HttpWebRequest request = GetHttpWebRequest(versionUrl);
            string downloadUrl = null;
            string data;

            using (WebResponse response = request.GetResponse())
            {
                data = ReadResponse(response);

                foreach (string line in data.Split('\n'))
                {
                    if (line.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                    {
                        // If this version number stops working, search for other known .NET Reflector version numbers; Red Gate's own forums mention a few
                        downloadUrl = line.Trim('\r').Replace("{Client}", "Reflector").Replace("{Version}", "6.1.0.11");
                        break;
                    }
                }
            }

            if (downloadUrl == null)
            {
                Console.WriteLine("Failed to find download URL. Returned data was:");
                Console.WriteLine(data);
                Console.ReadLine();
            }
            else
            {
                Console.WriteLine("Launching download process...");
                Process.Start(Process.GetCurrentProcess().MainModule.FileName, downloadUrl);
                Console.WriteLine("Phase 1 complete.");
            }
        }

        static void Download(string downloadUrl)
        {
            Console.WriteLine("Phase 2: Downloading...");

            HttpWebRequest request = GetHttpWebRequest(downloadUrl);
            string path;

            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                path = GetDownloadFilename(response);

                if (response.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(path))
                {
                    Console.WriteLine("Saving to {0}...", path);
                    SaveResponse(response, path);
                    Console.WriteLine("Done!");
                }
                else
                {
                    Console.WriteLine("Download failed; server returned status code {0}. Returned data was:", response.StatusCode);
                    Console.WriteLine(ReadResponse(response));
                    Console.ReadLine();
                }
            }
        }

        static HttpWebRequest GetHttpWebRequest(string url)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Headers.Add("Cache-Control: no-cache, no-store, max-age=0");
            // Emulate the manner in which the headers are handled
            FieldInfo usesProxySemantics = typeof(ServicePoint).GetField("m_ProxyServicePoint", BindingFlags.NonPublic | BindingFlags.Instance);
            usesProxySemantics.SetValue(request.ServicePoint, true);
            return request;
        }

        static string GetDownloadFilename(HttpWebResponse response)
        {
            string contentDisposition = response.Headers["content-disposition"];

            if (string.IsNullOrEmpty(contentDisposition))
                return null;

            string filenameField = "filename=";
            int index = contentDisposition.IndexOf(filenameField, StringComparison.CurrentCultureIgnoreCase);

            if (index < 0)
                return null;

            return contentDisposition.Substring(index + filenameField.Length).Trim('"');
        }

        static string ReadResponse(WebResponse response)
        {
            using (Stream netStream = response.GetResponseStream())
            {
                using (StreamReader reader = new StreamReader(netStream))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        static void SaveResponse(WebResponse response, string path)
        {
            byte[] buffer = new byte[4 * 1024];
            int bytesRead;

            using (Stream netStream = response.GetResponseStream())
            {
                if (File.Exists(path))
                    File.Delete(path);

                using (FileStream fileStream = File.Create(path))
                {
                    while ((bytesRead = netStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        Console.Write(".");
                        fileStream.Write(buffer, 0, bytesRead);
                    }
                }
            }

            Console.WriteLine();
        }
    }
}

Where to from here?

Once you have .NET Reflector up and running, be sure to try out some of the many free community add-ins available on .NET Reflector’s site and Codeplex. Tell your friends about it. And above all, don’t always believe a company when they tell you they’ll keep a product free.

  • This article has been quite obsolete, but yet useful
    You are an absolute champ! Thanks for sharing the code! :)
    Now I can move forward in my learning
    Have a good one!

  • Well done – nice work!

    The code will actually work in debug if you change the Process.Start to read:

    Process.Start(Assembly.GetExecutingAssembly().Location, downloadUrl);

    cheers K.

  • Hats off to you sir. Worked great. Great work. Many many Thanks a lot!!!.

  • Thanks for sharing the code. Works like a charm. Great job !!

  • First, thank you! This got me up and running again a long time ago. I recently upgraded to Windows 7 and had to dig this up and run it again to get Reflector back. Since then when browsing almost any of my own assemblies, I get an “Ambiguous match found.” error when I try to disassemble. It doesn’t happen for every member, but nearly every member. I’m bringing this here because only thing I can find online is saying to update to the latest version of Reflector. Any ideas what the problem might be?

  • Your internet access seems to be via a proxy server, and it is that proxy that requires authentication. You with either have to modify the code to use the appropriate proxy settings, or you will need to use an unproxied internet connection.

  • I am receiving this exception. “The remote server returned an error: (407) Proxy Authentication Required.”

    static void QueryDownloadUrl(string versionUrl)
    {
    Console.WriteLine(“Phase 1: Getting download URL…”);

    HttpWebRequest request = GetHttpWebRequest(versionUrl);
    string downloadUrl = null;
    string data;

    using (WebResponse response = request.GetResponse())

  • Thanks a lot
    ILSpy is a bit lacking I believe.
    When I created code using lambda expressions, ILSpy doesn’t display the compiler generated class; reflector does.

  • I just ran this code to download .net reflector and amazingly worked for me. I have windows 7 (64-bit).

    Thank you for the valuable posting. Really appreciate your good work.

  • .NET Reflector’s updater launches as a separate process, which has the effect of opening a new socket to download the update. If the download is not launched in a separate process, the existing socket that requested the update URL is re-used, thanks to the Keep-Alive headers.

    LookingGlass was designed to emulate the original updater’s behaviour as closely as possible, and that means re-launching itself with the download URL to prevent the existing socket from being re-used. This is also why the code won’t work when run from inside Visual Studio.

    But I’m glad you got it working anyway. :)

  • This still works fine. Just ran it now – but you forgot a rather important line of code. lol

    After this line (52):

    Process.Start(Process.GetCurrentProcess().MainModule.FileName, downloadUrl);

    insert:

    Download(downloadUrl);

    And press F5 and reflector.exe is in my debug\bin folder containing version 6.

    By the way, I have Windows 7, Visual Studio 2010, all Frameworks from 1.0 to 4.0. I created a new console application called LookingGlass, pasted this code, added Download(downloadUrl); on line 53 and ran it.

    The downloaded zip file is 1.07MB.

    Thank you for the valuable work Ashley, it is much appreciated. This version should have remained freely available as Roeder requested.

  • It still works like a charm. Thanks a lot!

    Anyway, in case if you guys haven’t noticed, ILSpy is the tool you should be using now. It has almost all the features of once free Reflector and is kept up-to-date by the community. Grab that here: http://ilspy.net/

  • Worked like a charm, but a couple of notes for people who might be having problems. I was not able to compile the code unless I was in admin mode (using the command line compiler) and I also had to run the program from the command line in admin mode to make it work.

  • You are a genius!
    Failed to get the file via a browser directly but I succeeded to get .NET reflector by running the program

  • What downloadUrl are you setting? Phase 1 gives me a downloadUrl of http://reflector.red-gate.com/ServeUpdates<GUID>.aspx?File=Reflector&Client=Reflector&Version=6.1.0.11

  • hi, download failed every time so i used debugger to download.
    Found exception at Line 64
    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse());
    The remote server returned an error: (404) Not Found.

    Whats the solution.
    I am on Windows 7 Enterprise
    Visual Studio 2008

    and i did follow your instructions in one of the above comments

    “If you specifically want to use the debugger, you’ll have to copy the value of the downloadUrl argument passed into Process.Start() on line 51 and set that in Project Properties > Debug > Command line arguments if you’re using Visual Studio. While you’re there, you should also probably set Working directory, as this is where the file will be downloaded to.”
    Please reply ASAP. Thanks.

  • That’s weird, as it still works for me. At which step do you get the 404, 1 or 2?

  • It still works for me, so I would guess it’s your network or proxy. Perhaps try debugging it in Visual Studio Express?

  • Can it work now?
    I tried it(build a program and run the program in an individual command window with admin), but I got the error “The remote server returned an error: (404) Not Found.” and time out. I am not sure if red gate do something or there is something wrong with my network.

  • THANK YOU!!! you just helped me to become more knowledgeable about C# by providing a way to get this very valuable tools that allowed me to see how the compiler break codes apart.

  • Check what version of .NET you are compiling for. This code requires .NET 2.0 and higher.

  • Hello! I’m having compiling and running it. I have a lot of errors. May be I will try again!

  • Perhaps the specific add-ins you are trying to install are incompatible with the latest version of Reflector?

  • Thank you very much, Nicely done, got it to work withing two minutes.

  • True, except that if you don’t use a new process to make the second request, the first connection will be reused instead of being closed and a new one created. Spawning a new process is a simple way to fully emulate Reflector’s update process, including connection behaviour.

  • The original headers look like this:

    GET http://reflector.red-gate.com/Reflector.version HTTP/1.1
    Cache-Control: no-cache, no-store, max-age=0
    Host: reflector.red-gate.com
    Proxy-Connection: Keep-Alive

    At the time, setting m_ProxyServicePoint to true was the simplest way of getting .NET to output that Proxy-Connection header.

    Pity it’s broken, but I suppose that’s what happens when one uses undocumented internals. ;)

    I’ll take a look at updating it for newer versions of the .NET framework in the next few weeks.

  • Also you don’t need to open a new process to make the request, http doesn’t send up any process information. FYI.

  • These lines

    FieldInfo usesProxySemantics = typeof(ServicePoint).GetField(“m_ProxyServicePoint”, BindingFlags.NonPublic | BindingFlags.Instance);
    usesProxySemantics.SetValue(request.ServicePoint, true);

    Don’t work in 4.0+compilers :/ usesProxySemantics is null.

    I tried emulating this by setting the host to

    request.Host = “reflector.red-gate.com:80”;

    Anyway you could show me the headers those lines create?

  • May the Force be with you!.. Thank You for striking down the greedy and the selfish ;)

    It worked FLAWLESSLY!

  • First of all, nice work to get .Net Reflector!

    There is an alternative, however, which is open source, does everything that .Net Reflector does and is free: http://ilspy.net/

    Cheers!

  • It’s still working fine on my side. It sounds like you’re behind a proxy, possibly a corporate or university firewall. You will need to modify the proxy configuration in the code to suit your needs, but it will be probably be easier to run it at home or at an internet café.

  • When run the program crashes with an WebException: Proxy Authentication required. What does this mean? Has Red Gate blocked it?

  • You have made lives around you better than any politician I have seen in my life.
    Thank you!

  • It won’t work in the debugger, because the end of Phase 1 launches a new process of the same executable with extra command line arguments.

    If you specifically want to use the debugger, you’ll have to copy the value of the downloadUrl argument passed into Process.Start() on line 51 and set that in Project Properties > Debug > Command line arguments if you’re using Visual Studio. While you’re there, you should also probably set Working directory, as this is where the file will be downloaded to.

  • Console was not visible at program termination, but in any case (after stepping to view results) stopped at “Phase 1 complete” with no download.

  • That’s a wonderful post, and a magnificent job you’ve done. You saved me a lot of time looking around for the last free version of Reflector.

    Again, Well done and thanks for your sharing.

Leave a Reply

Your email address will not be published. Required fields are marked *