Pretzel and Kudu on Azure

Pretzel Comments

I've published a couple of posts about that I'm using Pretzel to generate the HTML pages of my blog. However, I didn't talk about the hosting.

Actually, it's quite simple: The source files for the site are hosted in a git repository on GitHub. The generated site is hosted in Azure. Whenever I push changes to the git repository, the web site will be updated automatically.

Pretzel and Azure

The setup is a two-stage process: first, you have to create a Azure App Service and connect it to your git repository. The steps involved are documented very well in Continuous Deployment to Azure App Service.

The second step is to execute Pretzel on the Azure side. Enter Kudu. Kudu is the engine behind git deployments in Azure. It's well documented in the wiki at GitHub. By default, Kudu will locate the relevant csproj file, compile it, and copy the artifacts to wwwroot. That's why many web sizes running on Azure contain an empty "shim project".

However, you can simplify the setup by customizing Kudu's behavior. In my case I want Kudu to run pretzel.exe to generate the static HTML files from my sources:

  1. Add pretzel.exe (and all its dependencies) to your git repository (I've used a subfolder named _pretzel)

  2. Add a batch file deploy.cmd to execute pretzel.exe:

    @echo off
    echo Running Pretzel...
    _pretzel\pretzel.exe bake --destination=%DEPLOYMENT_TARGET%
    

    bake is the Pretzel's command to generate the files, and the destination folder is %DEPLOYMENT_TARGET%, which is the wwwroot folder.

  3. Instruct Kudu to execute that deploy.cmd by creating a file .deployment with following content:

    [config]
    command = deploy.cmd
    

That's all. Whenever I push changes to the git repository, Kudu will get the current files, execute Pretzel, and the updated web site is public. The whole process takes less than a minute.

Of course this can be adapted to any other static site generator too, e.g. Jekyll.

Encrypting values when serializing with JSON.NET

JSON.NET Comments

In a small inhouse app I wrote recently I store the settings in a json file, using the popular Json.NET library. However, the settings include a password, which should't appear as clear text in the json file.

I stumbled over this answer at Stack Overflow by Brian Rogers. This solution uses a custom IContractResolver and a new marker attribute JsonEncryptAttribute. Adding the attribute is quite easy:

public class Settings {
    [JsonEncrypt]
    public string Password { get; set; }
}

But you have to remember to add the ContractResolver additionally:

JsonConvert.SerializeObject(book, Formatting.Indented, new JsonSerializerSettings {
    ContractResolver = new EncryptedStringPropertyResolver ("#my*S3cr3t")
});

Though the solution is clever, I don't like the custom IContractResolver. Therefore I read through Json.NET's documentation to find an easier way, i.e. by only applying an attribute to the property to encrypt.

In fact, Json.NET supports custom converters by annotating properties with JsonConverterAttribute. That attribute even allows you to pass additional parameters to your custom converter, like in this case the encryption key.

Therefore I took Brian's code and converted it into a JsonConverter (also published as a Gist):

And the usage is pretty simple:

public class Settings {
    [JsonConverter(typeof(EncryptingJsonConverter), "#my*S3cr3t")]
    public string Password { get; set; }
}

There's no need for any additional code like a custom ContractResolver. And you can even use different encryption keys for different properties.

My code works only for string properties though, but that's all I needed.

Presenting Byte Size Values in WPF

WPF Comments

Though it's not my main job, I still enjoy writing WPF application. Small tools, making my colleagues' and my own life easier.

Recently I had the requirement to display size values in bytes, kilobytes, etc in a well-rounded way. You will find many examples for formatting such values in the internet. Most look like this:

string result;
if (number >= 1024 * 1024 * 1024) {
    result = (number / 1024.0 / 1024 / 1024).ToString("F1") + " GB";
} else if (number >= 1024 * 1024) {
    result = (number / 1024.0 / 1024).ToString("F1") + " MB";
} else if (number >= 1024) {
    result = (number / 1024.0).ToString("F1") + " KB";
} else {
    result = number + " Bytes";
}

or, in a smarter way

string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double len = number;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1) {
    order++;
    len = len / 1024;
}
string result = $"{len:0.##} {sizes[order]}";

However, if you're on the Windows platform, there's a much easier option: StrFormatByteSize. That's the same method that Explorer is using to display file sizes. Its advantages are that you don't have any localization issues, and it it has a fixed precision of 3 digits.

Because my application is using WPF, I wrote a IValueConverter to be used in bindings:

Formatting binded values in XAML becomes quite easy with that converter (see full XAML):

<DataGrid
  AutoGenerateColumns="False"
  IsReadOnly="True"
  ItemsSource="{StaticResource numbers}">
  <DataGrid.Resources>
    <!--  the actual converter  -->
    <local:FormatKbSizeConverter x:Key="FormatKbSizeConverter" />
  </DataGrid.Resources>
  <DataGrid.Columns>
    <!--  First column shows the plain values  -->
    <DataGridTextColumn
      Binding="{Binding}"
      ElementStyle="{StaticResource RightCell}"
      Header="Plain" />
    <!--  Second column shows the formatted values  -->
    <DataGridTextColumn
      Binding="{Binding Converter={StaticResource FormatKbSizeConverter}}"
      ElementStyle="{StaticResource RightCell}"
      Header="Formatted" />
  </DataGrid.Columns>
</DataGrid>

FormatKbSizeConverter

Pretzel Plugin: Redirect

Pretzel Comments

A while back I wrote about the migration of my blog from Community Server over Jekyll to Pretzel.

One golden rule when restructuring a web site is to avoid dead links. The original web engine was a classic ASP.NET application, where every URL ends in .aspx (at least if you don't configure extensionless URLs). Tens years ago every URLs ended in an extension like .html, .php, whatever. Now-a-days, you barely see any file extensions anymore. The web servers don't expose the underlying technology, and the user just doesn't care. And so does Pretzel.

To use a new URL schema, but preserve the old links and redirect them to the new schema, I wrote an plugin for Pretzel, Pretzel.RedirectFrom. I've used the jekyll-redirect-from plugin as a guide, so the syntax is the same. Just add alternative URLs in the page's YAML front-matter:

---
title: "My First Post"
redirect_from:
  - /pages/page1
---

This will generate a small html page at \pages\page1\index.html, which will redirect to the new location:

<!DOCTYPE html>
<meta charset="utf-8" />
<title>Redirecting...</title>
<link rel="canonical" href="/2016/10/31/myfirstpost.html" />
<meta http-equiv="refresh" content="0; url=/2016/10/31/myfirstpost.html" />
<h1>Redirecting...</h1>
<a href="/2016/10/31/myfirstpost.html">Click here if you are not redirected.</a>
<script>
    location="/2016/10/31/myfirstpost.html"
</script>

Pretzel is a static file generator, so the redirection must be performed at the client-side.

However, I prefer a "real" redirect, i.e. a response with the correct HTTP status 301 Moved Permanently. Therefore I've implemented an additional switch. If you're using IIS (or Azure, or any other web server supporting ASP.NET), you can specify the switch redirect_generate_aspx: true in Pretzel's _config.yml. In this case the generated page will look like this:

<%@ Page Language="C#"%>
<script runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
    Response.StatusCode = 301;
    Response.Status = "301 Moved Permanently";
    Response.AddHeader("Location","/2016/10/31/myfirstpost.html");
    Response.End();
}
</script>

This ensures that the server returns the correct HTTP status.

Anyway, this plugin is a simple ScriptCs file, so you only have to copy Pretzel.RedirectFrom.csx to the _plugin folder of your Pretzel site, and you will be ready to use redirects.

Pretzel Plugin: Sitemap

Pretzel Comments

A couple of month ago I wrote that I switched to Pretzel to drive my site.

What I really like about Pretzel (except that it's written in .NET) is that it is so easy to extend. You can write plugins either as a .NET assembly, or—even simpler—throw in an .csx file, because Pretzel supports ScriptCs.

One of the first extensions I wrote was a site map plugin. By default Pretzel already creates a site map, but only for static pages. Unfortunately, this doesn't include paginated pages like the home page. Those pages are generated dynamically at runtime of Pretzel, and the default sitemap.xml doesn't take those dynamic pages into account.

Therefore I wrote this plugin which creates the sitemap.xml including all generated pages, even the paginated ones. It uses the same technique as JekyllEngineBase.ProcessFile: for each post and page it adds an url entry to the sitemap. Additionally it checks the page's front-matter if paginate is specified, and adds relevant URLs to the sitemap too.

The plugin is hosted on Github including some basic tests, but in fact you only have to copy Pretzel.Sitemap.csx to the _plugin folder of your Pretzel site.