Upgrading my BlogEngine.NET website from 3.1.1.0 to 3.3.80

It's been a while since my last blog post and I was having touble upgrading my BlogEngine.NET websit

It's been a while since my last blog post and I was having touble upgrading my BlogEngine.NET website (it's been a while!). To upgrade, you must log in to the Admin page "http://www.website.com/admin/" and you will get a message on the Home page if you can upgrade or nothing at all.



You can see what I did to get upgraded below.

Unfortunately, whenever I go on the admin home page it's really slow when getting the gallery theme list and logged messages, so this picture took some patience to get.

If you get your browser developer tools (F12) open on this page you will notice that it will call this URL http://www.website.com/api/setup?version=3.1.1.0 to get the latest version to upgrade to. In my case "3.3.8.0".

You would then click on the Upgrade button and it will take you to this page "http://www.website.com/setup/upgrade":


Of course we know this isn't true. We know there is a new version available.

To track down the issue, I looked for the upgrade page and try to understand what it was doing.
Ah, the http://www.website.com/setup/upgrade/index.cshtml page has three script tags, one of which references Updater.js.

<script src="~/setup/upgrade/jquery-2.0.3.min.js"></script>
<script src="~/setup/upgrade/bootstrap.min.js"></script>
<script src="~/setup/upgrade/Updater.js"></script>

When the page is ready it will check the version

$(document).ready(function () {
    Check();
});

var newVersion = "";

function Check() {
    // CurrentVersion
    CheckVersion();

    if (!newVersion) { newVersion = ""; }

    if (newVersion.length > 0) {
        $("#spin1").hide();
        $("#spin2").hide();
        $("#spin3").hide();
        $("#spin4").hide();
        $("#spin5").hide();
        $("#spin9").hide();
        $("#step9").hide();
        $('#msg-success').hide();
        $('#spnNewVersion').html(newVersion);
    }
    else {
        $("#frm").hide();
        $("#btnRun").hide();
        $("h2").html("Looks like you already running latest version!");
    }
}

function CheckVersion() {
    $("#spin1").show();
    $.ajax({
        url: AppRoot + "setup/upgrade/Updater.asmx/Check",
        data: "{ version: '" + CurrentVersion + "' }",
        type: "POST",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        async: false,
        success: function (result) {
            newVersion = result.d; // e.g. "3.2.0.0";
        }
    });
}

Note, the CheckVersion function calls "http://www.website.com/setup/upgrade/Updater.asmx/Check" with the current website version value in the POST request.
I needed to see what the newVersion variable is populated with so I added a console.log() call to the success function.

success: function (result) {
    console.log(result);
    newVersion = result.d; // "3.2.0.0";
},
error: function(err){
    console.log(err);
}

But nothing was getting logged so I added an error function.

error: function(err){
    console.log(err);
}

The returned a large responseText value with a HTML page titled "binary dreams | Error".



Ok, there is something wrong happening in the ASMX file. But, what?

This is the summarised class (the ... (dots) replace unused by the Check method) :

[ScriptService]
public class Updater  : WebService {

    private StringCollection _ignoreDirs;
    private List<InstalledLog> _installed;
    private string _root;
    private string _newZip;
    private string _oldZip;
    private static string _upgradeReleases = BlogConfig.GalleryFeedUrl.Replace("nuget", "/Releases/");
    //private static string _upgradeReleases = "http://dnbe.net/v01/Releases/";
    ...
    private string _versionsTxt = _upgradeReleases + "versions.txt";
    ...

    public Updater()
    {
        _root = HostingEnvironment.MapPath("~/");
        if (_root.EndsWith("\\")) _root = _root.Substring(0, _root.Length - 1);

        _newZip = _root + "\\setup\\upgrade\\backup\\new.zip";
        _oldZip = _root + "\\setup\\upgrade\\backup\\old.zip";

        _ignoreDirs = new StringCollection();
        _ignoreDirs.Add(_root + "\\Custom");
        _ignoreDirs.Add(_root + "\\setup\\upgrade");

        _installed = new List<InstalledLog>();
    }

    [WebMethod]
    public string Check(string version)
    {
        try
        {
            WebClient client = new WebClient();
            Stream stream = client.OpenRead(_versionsTxt);
            StreamReader reader = new StreamReader(stream);
            string line = "";

            while (reader.Peek() >= 0)
            {
                line = reader.ReadLine();
               
                if (!string.IsNullOrEmpty(version) && line.Contains("|"))
                {
                    var iCurrent = int.Parse(version.Replace(".", ""));
                    var iFrom = int.Parse(line.Substring(0, line.IndexOf("|")).Replace(".", ""));
                    var iTo = int.Parse(line.Substring(line.LastIndexOf("|") + 1).Replace(".", ""));

                    if (iCurrent >= iFrom  && iCurrent < iTo)
                    {
                        return line.Substring(line.LastIndexOf("|") + 1);
                    }
                }
            }
            return "";
        }
        catch (Exception)
        {
            return "";
        }
    }
    
    ...
}

So I started ruling things out. I tried to log the exception messages in the Check() try-catch but nothing was logged let alone returning.
The I set the return values to "test" + number so I would know the failing path and reloaded the upgrade page.

try
{
    WebClient client = new WebClient();
    Stream stream = client.OpenRead(_versionsTxt);
    StreamReader reader = new StreamReader(stream);
    string line = "test1";

    while (reader.Peek() >= 0)
    {
        line = reader.ReadLine();
               
        if (!string.IsNullOrEmpty(version) && line.Contains("|"))
     {
            var iCurrent = int.Parse(version.Replace(".", ""));
            var iFrom = int.Parse(line.Substring(0, line.IndexOf("|")).Replace(".", ""));
            var iTo = int.Parse(line.Substring(line.LastIndexOf("|") + 1).Replace(".", ""));

            if (iCurrent >= iFrom  && iCurrent < iTo)
            {
                return "test2";//line.Substring(line.LastIndexOf("|") + 1);
            }
        }
    }
    return "test3";
}
catch (Exception)
{
    return "test4";
}

Still same error page returned in the Check response. I then commented out everything in the Updater() constructor as the Check method never used any of it anyway and still I'm getting error page response.

The workaround

Then I had a hunch, it had to be in the class initialisation and this line was the likely culprit:

private static string _upgradeReleases = BlogConfig.GalleryFeedUrl.Replace("nuget", "/Releases/");

So I commented that line out and uncommented the line below it:

private static string _upgradeReleases = "http://dnbe.net/v01/Releases/";

Now I get this object logged in the AJAX success function.

Object { d: "test2" }

This means the happy path was executed and I can undo my previous debugging changes.

Low and behold another refresh and I get the expected page to say I can upgrade!


The funny thing is. I did the upgrade and I was getting a message saying that I upgrade to v3.3.8.0 even though I am that version right now.

But why did this line of code fail anyway?

I did a search of all the files in the root folder of the source code for the text "GalleryFeedUrl" using NotePad++. I found a few results but what most interested me was this references  like this "BlogEngine.Core.BlogSettings.GalleryFeedUrl" and only one reference to "BlogConfig.GalleryFeedUrl" in the Updater.asmx file. I've submitted an issue on the github repository for this at.

Add comment