Congratulations!

[Valid Atom 1.0] This is a valid Atom 1.0 feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: http://thomasfreudenberg.com/feed.xml

  1. <?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.2">Jekyll</generator><link href="https://thomasfreudenberg.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://thomasfreudenberg.com/" rel="alternate" type="text/html" /><updated>2022-08-30T07:46:49+00:00</updated><id>https://thomasfreudenberg.com/feed.xml</id><title type="html">Thomas Freudenberg</title><subtitle>Thomas Freudenberg - Confessions of a caffeine addict</subtitle><author><name>Thomas Freudenberg</name></author><entry><title type="html">Async/await in Desktop Applications</title><link href="https://thomasfreudenberg.com/archive/2019/01/28/async-await-in-desktop-applications/" rel="alternate" type="text/html" title="Async/await in Desktop Applications" /><published>2019-01-28T00:00:00+00:00</published><updated>2019-01-28T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2019/01/28/async-await-in-desktop-applications</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2019/01/28/async-await-in-desktop-applications/">&lt;p&gt;&lt;em&gt;This is a transcript of a demonstration I gave in our company internally
  2. about async/await “challenges” in UI programming. You can find the accompanying
  3. repository in &lt;a href=&quot;https://github.com/thoemmi/CrossThreadingTests&quot;&gt;my repository on Github&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
  4.  
  5. &lt;p&gt;&lt;img src=&quot;/files/archive/async-await-winforms-app.png&quot; alt=&quot;Demo App&quot; title=&quot;Demo App&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;
  6.  
  7. &lt;p&gt;The form contains three buttons which are intended to download the
  8. the content from &lt;a href=&quot;http://microsoft.com&quot;&gt;http://microsoft.com&lt;/a&gt; asynchronously and show it
  9. in a TextBox.&lt;/p&gt;
  10.  
  11. &lt;h2 id=&quot;cross-thread-issue-&quot;&gt;Cross-Thread issue :(&lt;/h2&gt;
  12.  
  13. &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;button1_Click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EventArgs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  14. &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  15.    &lt;span class=&quot;c1&quot;&gt;// await a completed task =&amp;gt; will continue synchronously&lt;/span&gt;
  16.    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SomeFastAsyncOperation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureAwait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  17.  
  18.    &lt;span class=&quot;c1&quot;&gt;// await a slow task =&amp;gt; will continue in another thread&lt;/span&gt;
  19.    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SomeSlowAsyncOperation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureAwait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  20.  
  21.    &lt;span class=&quot;c1&quot;&gt;// write text to text box&lt;/span&gt;
  22.    &lt;span class=&quot;n&quot;&gt;textBox1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  23. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  24. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  25.  
  26. &lt;p&gt;When clicking the first button, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvalidOperationException&lt;/code&gt; will
  27. be thrown with the message&lt;/p&gt;
  28.  
  29. &lt;blockquote&gt;
  30.  &lt;p&gt;Cross-thread operation not valid: Control ‘textBox1’ accessed from a
  31. thread other than the thread it was created on.&lt;/p&gt;
  32. &lt;/blockquote&gt;
  33.  
  34. &lt;p&gt;That’s because in Win32 UIs you must access controls from the same thread
  35. that created them. Because the after awaiting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SomeSlowAsyncOperation&lt;/code&gt;
  36. the method continues not in the main thread but a nackground thread,
  37. accessing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textBox1&lt;/code&gt; is forbidden.&lt;/p&gt;
  38.  
  39. &lt;p&gt;When you debug &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;button1_Click&lt;/code&gt;, pay attention to the &lt;em&gt;Threads&lt;/em&gt; tool window.&lt;/p&gt;
  40.  
  41. &lt;p&gt;&lt;img src=&quot;/files/archive/async-await-debugger.png&quot; alt=&quot;Debugger&quot; title=&quot;Debugger Thread Toolwindow&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;
  42.  
  43. &lt;ol&gt;
  44.  &lt;li&gt;Entering the method, you’ll be on thread #1, the main thread.&lt;/li&gt;
  45.  &lt;li&gt;After calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SomeFastAsyncOperation&lt;/code&gt;, the code continues on thread #1.
  46. That’s because the method returns an already completed task, so the code
  47. can continue synchronously.&lt;/li&gt;
  48.  &lt;li&gt;In contrast, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SomeSlowAsyncOperation&lt;/code&gt; returns a not-completed task,
  49. therefore the succeeding code will continue not another one. (The UI thread
  50. will be released here and continue pumping the Win32 message queue)&lt;/li&gt;
  51.  &lt;li&gt;The property &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textBox1.Text&lt;/code&gt; will be set in said background thread and
  52. fail, because Win32 controls mist be accessed from the same thread that
  53. created them.&lt;/li&gt;
  54. &lt;/ol&gt;
  55.  
  56. &lt;h2 id=&quot;blocking-&quot;&gt;Blocking :(&lt;/h2&gt;
  57.  
  58. &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;button2_Click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EventArgs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  59. &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  60.    &lt;span class=&quot;c1&quot;&gt;// await a completed task =&amp;gt; will continue synchronously&lt;/span&gt;
  61.    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SomeFastAsyncOperation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureAwait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  62.  
  63.    &lt;span class=&quot;c1&quot;&gt;// await a slow task =&amp;gt; will continue in another thread&lt;/span&gt;
  64.    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SomeSlowAsyncOperation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureAwait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAwaiter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  65.  
  66.    &lt;span class=&quot;c1&quot;&gt;// write text to text box&lt;/span&gt;
  67.    &lt;span class=&quot;n&quot;&gt;textBox1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  68. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  69. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  70.  
  71. &lt;p&gt;Clicking the second button will freeze the application. The
  72. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetAwaiter().GetResult()&lt;/code&gt; invocation will try to re-enter the
  73. the main thread, which is waiting for the task, so we’ll run into a dead-lock.&lt;/p&gt;
  74.  
  75. &lt;h2 id=&quot;run-smoothly-&quot;&gt;Run smoothly :)&lt;/h2&gt;
  76.  
  77. &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;button3_Click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EventArgs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  78. &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  79.    &lt;span class=&quot;c1&quot;&gt;// force switch to threadpool thread&lt;/span&gt;
  80.    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TaskScheduler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  81.  
  82.    &lt;span class=&quot;c1&quot;&gt;// await a completed task =&amp;gt; will continue synchronously&lt;/span&gt;
  83.    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SomeFastAsyncOperation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureAwait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  84.  
  85.    &lt;span class=&quot;c1&quot;&gt;// await a slow task =&amp;gt; will continue in another thread&lt;/span&gt;
  86.    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SomeSlowAsyncOperation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureAwait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  87.  
  88.    &lt;span class=&quot;c1&quot;&gt;// switch to main thread&lt;/span&gt;
  89.    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_joinableTaskFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SwitchToMainThreadAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  90.  
  91.    &lt;span class=&quot;c1&quot;&gt;// write text to text box&lt;/span&gt;
  92.    &lt;span class=&quot;n&quot;&gt;textBox1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  93. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  94. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  95.  
  96. &lt;p&gt;Using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JoinableTaskFactory&lt;/code&gt; from &lt;a href=&quot;https://github.com/Microsoft/vs-threading&quot;&gt;&lt;em&gt;Microsoft.VisualStudio.Threading&lt;/em&gt;&lt;/a&gt;
  97. (NuGet package &lt;a href=&quot;https://nuget.org/packages/Microsoft.VisualStudio.Threading&quot;&gt;here&lt;/a&gt;),
  98. we are able to “switch” back to the UI thread.&lt;/p&gt;
  99.  
  100. &lt;p&gt;As the namespace implies, &lt;em&gt;Microsoft.VisualStudio.Threading&lt;/em&gt; originates from
  101. the Visual Studio team. I stumbled over this library while reading the documentation
  102. for Visual Studio extensibility. Visual Studio is quite a complex application, and
  103. there are myriads of extensions available. To improve the start-up time, Microsoft
  104. strongly recommends to make use of asynchronous programming (see
  105. &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/extensibility/managing-multiple-threads-in-managed-code?view=vs-2017&quot;&gt;&lt;em&gt;How to: Manage multiple threads in managed code&lt;/em&gt;&lt;/a&gt;
  106. and &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/extensibility/how-to-use-asyncpackage-to-load-vspackages-in-the-background?view=vs-2017&quot;&gt;&lt;em&gt;How to: Use AsyncPackage to load VSPackages in the background&lt;/em&gt;&lt;/a&gt;)&lt;/p&gt;
  107.  
  108. &lt;p&gt;I won’t go into details of how async/await works. Basically, the compiler generates
  109. a state machine, which Dixin explains pretty good in his blog serie
  110. &lt;a href=&quot;https://weblogs.asp.net/dixin/understanding-c-sharp-async-await-1-compilation&quot;&gt;&lt;em&gt;Understanding C# async / await (1) Compilation&lt;/em&gt;&lt;/a&gt;
  111. (&lt;a href=&quot;https://weblogs.asp.net/dixin/understanding-c-sharp-async-await-2-awaitable-awaiter-pattern&quot;&gt;Part 2&lt;/a&gt;,
  112. &lt;a href=&quot;https://weblogs.asp.net/dixin/understanding-c-sharp-async-await-3-runtime-context&quot;&gt;Part 3&lt;/a&gt;).&lt;/p&gt;
  113.  
  114. &lt;p&gt;In our case, two calls are interesting:&lt;/p&gt;
  115.  
  116. &lt;ol&gt;
  117.  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await TaskScheduler.Default;&lt;/code&gt; will continue the succeeding code in a threadpool thread.&lt;br /&gt;
  118. &lt;small&gt;(actually, the library provides an extension method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetAwaiter(this TaskScheduler this)&lt;/code&gt;.
  119. This works because the compiler uses a naming convention instead of requiring an interface implemenntation)&lt;/small&gt;&lt;/li&gt;
  120.  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await _joinableTaskFactory.SwitchToMainThreadAsync();&lt;/code&gt; will continue the succeeding code in the
  121. main thread.&lt;br /&gt;
  122. &lt;small&gt;(actually, in the thread with instantiated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_joinableTaskFactory&lt;/code&gt;).&lt;/small&gt;&lt;/li&gt;
  123. &lt;/ol&gt;
  124.  
  125. &lt;p&gt;As you could see, &lt;em&gt;Microsoft.VisualStudio.Threading&lt;/em&gt; makes asynchronous programming
  126. in desktop applications, both WinForms and WPF, much simpler.&lt;/p&gt;
  127.  
  128. &lt;p&gt;BTW, I’ve learned a lot reading the &lt;a href=&quot;https://github.com/Microsoft/vs-threading&quot;&gt;code of that library&lt;/a&gt;. It provides
  129. much more async helpers like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsyncEventHandlers&lt;/code&gt;.&lt;/p&gt;
  130.  
  131. &lt;p&gt;Here are some more links if you want to learn more about async programming:&lt;/p&gt;
  132.  
  133. &lt;ul&gt;
  134.  &lt;li&gt;&lt;a href=&quot;https://www.slideshare.net/aarnott/the-3-vs-threading-rules&quot;&gt;&lt;em&gt;The 3 VS Threading Rules&lt;/em&gt;&lt;/a&gt; by Andrew Arnott&lt;/li&gt;
  135.  &lt;li&gt;&lt;a href=&quot;https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html&quot;&gt;&lt;em&gt;Don’t Block on Async Code&lt;/em&gt;&lt;/a&gt; by Stephen Cleary&lt;/li&gt;
  136.  &lt;li&gt;&lt;a href=&quot;https://lesen.amazon.de/kp/embed?asin=B00KCY2CB4&amp;amp;preview=newtab&amp;amp;linkCode=kpe&amp;amp;ref_=cm_sw_r_kb_dp_WWQtCbZETE973&quot;&gt;&lt;em&gt;Concurrency in C# Cookbook: Asynchronous, Parallel, and Multithreaded Programming&lt;/em&gt;&lt;/a&gt; by Stephen Cleary&lt;/li&gt;
  137. &lt;/ul&gt;</content><author><name>Thomas Freudenberg</name></author><category term="async" /><category term="WinForms" /><category term="WPF" /><category term="multi-threading" /><summary type="html">This is a transcript of a demonstration I gave in our company internally about async/await “challenges” in UI programming. You can find the accompanying repository in my repository on Github.</summary></entry><entry><title type="html">Generating workflow diagrams for TFS work items</title><link href="https://thomasfreudenberg.com/archive/2018/01/16/generating-workflow-diagram-for-witd/" rel="alternate" type="text/html" title="Generating workflow diagrams for TFS work items" /><published>2018-01-16T00:00:00+00:00</published><updated>2018-01-16T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2018/01/16/generating-workflow-diagram-for-witd</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2018/01/16/generating-workflow-diagram-for-witd/">&lt;p&gt;In my current position as the Technical Lead of Product Development I have several
  138. responsibilities. One of them is the definition and implementation of our development
  139. processes. We’re using Team Foundation Server, which supports rich customization
  140. of the process configuration, especially the workflow of work items.&lt;/p&gt;
  141.  
  142. &lt;p&gt;To document the workflow of our work items, I wanted to create perspicuous charts.
  143. However, if you’re a nerd like me, you don’t want to use Powerpoint or Visio to
  144. create high gloss charts. Instead I like to automate the creation of the charts.&lt;/p&gt;
  145.  
  146. &lt;p&gt;Fortunately, the XML format of work item template definitions (WITD) is well-documented, see
  147. &lt;a href=&quot;https://docs.microsoft.com/en-us/vsts/work/customize/reference/all-workflow-xml-elements-reference?toc=/vsts/work/customize/toc.json&amp;amp;bc=/vsts/work/customize/breadcrumb/toc.json&quot;&gt;All WORKFLOW XML elements reference&lt;/a&gt;.
  148. To get the XML file of a WITD, you can use either the Visual Studio Add-in
  149. &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=KarthikBalasubramanianMSFT.TFSProcessTemplateEditor&quot;&gt;TFS Process Template Editor&lt;/a&gt;
  150. or use &lt;a href=&quot;https://docs.microsoft.com/en-us/vsts/work/customize/reference/witadmin/witadmin-import-export-manage-wits&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;witadmin&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
  151.  
  152. &lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;witadmin exportwitd /collection:CollectionURL /p:Project /n:TypeName &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;/f:FileName]
  153. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  154.  
  155. &lt;p&gt;On the other end, the &lt;a href=&quot;http://www.graphviz.org/&quot;&gt;Graphviz suite&lt;/a&gt; includes a nice
  156. small tool named &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dot&lt;/code&gt;&lt;/strong&gt; to draw directed graphs as PNGs, reading the defintion
  157. of the graph from a text file.&lt;/p&gt;
  158.  
  159. &lt;p&gt;The challenge was now to convert the XML of the WITD to the &lt;a href=&quot;https://graphviz.gitlab.io/_pages/doc/info/lang.html&quot;&gt;DOT language&lt;/a&gt;.
  160. But that’s quite easy to accomplish using Powershell. But before I show the script,
  161. first a picture of the default workflow for bugs from the Scrum process template:&lt;/p&gt;
  162.  
  163. &lt;p&gt;&lt;img src=&quot;/files/archive/witd.bug.default.png&quot; alt=&quot;Pretzel and Azure&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;
  164.  
  165. &lt;p&gt;And here’s the script:&lt;/p&gt;
  166.  
  167. &lt;script src=&quot;https://gist.github.com/a4e5566a53a4b4c72424c59fdbc4eba4.js?file=Create-WorkflowDiagramFromWitd.ps1&quot;&gt; &lt;/script&gt;
  168.  
  169. &lt;p&gt;If you pay close attention, you may notice that if only certain users or groups
  170. are permitted to change a work item to a specific state, the graph will show
  171. this too. E.g. if only members of the QA are allowed to move a but from the
  172. &lt;em&gt;Done&lt;/em&gt; state, the graph will look like this:&lt;/p&gt;
  173.  
  174. &lt;p&gt;&lt;img src=&quot;/files/archive/witd.bug.customized.png&quot; alt=&quot;Pretzel and Azure&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;
  175.  
  176. &lt;p&gt;Nevertheless, the script was written in a short time, it does what it should
  177. do without any error handling. However, it suits my needs. Maybe yours as well.&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term="TFS" /><category term="Graphviz" /><category term="Powershell" /><summary type="html">In my current position as the Technical Lead of Product Development I have several responsibilities. One of them is the definition and implementation of our development processes. We’re using Team Foundation Server, which supports rich customization of the process configuration, especially the workflow of work items.</summary></entry><entry><title type="html">ResourceLib, PE Format, and WiX</title><link href="https://thomasfreudenberg.com/archive/2017/12/11/resourcelib-pe-format-and-wix/" rel="alternate" type="text/html" title="ResourceLib, PE Format, and WiX" /><published>2017-12-11T00:00:00+00:00</published><updated>2017-12-11T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2017/12/11/resourcelib-pe-format-and-wix</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2017/12/11/resourcelib-pe-format-and-wix/">&lt;p&gt;&lt;em&gt;Some time ago I reported a bug and provided a pull request to
  178. &lt;a href=&quot;https://github.com/resourcelib/resourcelib&quot;&gt;&lt;strong&gt;resourcelib&lt;/strong&gt;&lt;/a&gt;, a managed
  179. library to read and write Win32 resources in executables or DLL’s.
  180. And unawarely, the next morning I was a maintainer of that library.&lt;/em&gt;&lt;/p&gt;
  181.  
  182. &lt;p&gt;&lt;em&gt;This blog post is about an issue we’ve received: someone tried to
  183. patched the Win32 resources of a&lt;/em&gt; setup.exe &lt;em&gt;, an executable installer
  184. created with &lt;a href=&quot;http://wixtoolset.org/&quot;&gt;WiX&lt;/a&gt;. However, after changing
  185. the resources with resourdelib, the setup didn’t work anymore.&lt;/em&gt;&lt;/p&gt;
  186.  
  187. &lt;p&gt;&lt;em&gt;I’ve spent some time investigating this issue using &lt;a href=&quot;https://msdn.microsoft.com/de-de/library/756as972.aspx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dumpbin&lt;/code&gt;&lt;/a&gt;
  188. and reading the &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/windows/desktop/ms680547(v=vs.85).aspx#section_table__section_headers_&quot;&gt;PE format specification&lt;/a&gt;.
  189. Because I don’t know how good Google is at indexing Github issues, I’ll
  190. also post my analysis here in my blog for reference. The original
  191. thread is &lt;a href=&quot;https://github.com/resourcelib/resourcelib/issues/19#issuecomment-350891529&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
  192.  
  193. &lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; to me it looks like WiX is doing it wrong.&lt;/p&gt;
  194.  
  195. &lt;p&gt;According to the output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dumpbin&lt;/code&gt; there are 7 sections in the executable the issuer provided:&lt;/p&gt;
  196.  
  197. &lt;table&gt;
  198.  &lt;thead&gt;
  199.    &lt;tr&gt;
  200.      &lt;th&gt;#&lt;/th&gt;
  201.      &lt;th&gt;Name&lt;/th&gt;
  202.      &lt;th&gt;Range&lt;/th&gt;
  203.    &lt;/tr&gt;
  204.  &lt;/thead&gt;
  205.  &lt;tbody&gt;
  206.    &lt;tr&gt;
  207.      &lt;td&gt;1&lt;/td&gt;
  208.      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.text&lt;/code&gt;&lt;/td&gt;
  209.      &lt;td&gt;0x00000400 to 0x00049FFF&lt;/td&gt;
  210.    &lt;/tr&gt;
  211.    &lt;tr&gt;
  212.      &lt;td&gt;2&lt;/td&gt;
  213.      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rdata&lt;/code&gt;&lt;/td&gt;
  214.      &lt;td&gt;0x0004A000 to 0x00068DFF&lt;/td&gt;
  215.    &lt;/tr&gt;
  216.    &lt;tr&gt;
  217.      &lt;td&gt;3&lt;/td&gt;
  218.      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.data&lt;/code&gt;&lt;/td&gt;
  219.      &lt;td&gt;0x00068E00 to 0x000697FF&lt;/td&gt;
  220.    &lt;/tr&gt;
  221.    &lt;tr&gt;
  222.      &lt;td&gt;4&lt;/td&gt;
  223.      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.wixburn&lt;/code&gt;&lt;/td&gt;
  224.      &lt;td&gt;0x00069800 to 0x000699FF&lt;/td&gt;
  225.    &lt;/tr&gt;
  226.    &lt;tr&gt;
  227.      &lt;td&gt;5&lt;/td&gt;
  228.      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.tls&lt;/code&gt;&lt;/td&gt;
  229.      &lt;td&gt;0x00069A00 to 0x00069BFF&lt;/td&gt;
  230.    &lt;/tr&gt;
  231.    &lt;tr&gt;
  232.      &lt;td&gt;6&lt;/td&gt;
  233.      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rsrc&lt;/code&gt;&lt;/td&gt;
  234.      &lt;td&gt;0x00069C00 to 0x0006D7FF&lt;/td&gt;
  235.    &lt;/tr&gt;
  236.    &lt;tr&gt;
  237.      &lt;td&gt;7&lt;/td&gt;
  238.      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.reloc&lt;/code&gt;&lt;/td&gt;
  239.      &lt;td&gt;0x0006D800 to 0x000715FF&lt;/td&gt;
  240.    &lt;/tr&gt;
  241.  &lt;/tbody&gt;
  242. &lt;/table&gt;
  243.  
  244. &lt;p&gt;In a hex viewer you can see that after the last section, the file continues for another &lt;strong&gt;104205 bytes&lt;/strong&gt;, starting with 0x4D 0x53 0x43 0x46 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSCF&lt;/code&gt;, the magic number starting a &lt;a href=&quot;https://de.wikipedia.org/wiki/CAB_(Dateiformat)&quot;&gt;cab file&lt;/a&gt;).&lt;/p&gt;
  245.  
  246. &lt;p&gt;I patched the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StringFileInfo&lt;/code&gt; resource using &lt;strong&gt;resourcelib&lt;/strong&gt;, which changed the content of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rsrc&lt;/code&gt; section only. Afterwards the file ended at 0x000715FF, i.e. the following &lt;strong&gt;104205 bytes&lt;/strong&gt; were missing.&lt;/p&gt;
  247.  
  248. &lt;p&gt;By the way, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.wixburn&lt;/code&gt; section contains following bytes:&lt;/p&gt;
  249.  
  250. &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RAW DATA #4
  251.  0046C000: 00 43 F1 00 02 00 00 00 04 12 28 81 2C 64 40 48  .C±.......(.,d@H
  252.  0046C010: B2 B1 34 64 EC 08 65 64 00 16 07 00 00 00 00 00  ▓▒4d∞.ed........
  253.  0046C020: 00 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00  ................
  254.  0046C030: 92 8E 01 00 7B 08 00 00                          ....{...
  255. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  256.  
  257. &lt;p&gt;which means&lt;/p&gt;
  258.  
  259. &lt;table&gt;
  260.  &lt;thead&gt;
  261.    &lt;tr&gt;
  262.      &lt;th&gt;Field&lt;/th&gt;
  263.      &lt;th style=&quot;text-align: right&quot;&gt;Bytes&lt;/th&gt;
  264.      &lt;th&gt;Value&lt;/th&gt;
  265.    &lt;/tr&gt;
  266.  &lt;/thead&gt;
  267.  &lt;tbody&gt;
  268.    &lt;tr&gt;
  269.      &lt;td&gt;magic number&lt;/td&gt;
  270.      &lt;td style=&quot;text-align: right&quot;&gt;0-3&lt;/td&gt;
  271.      &lt;td&gt;0x00f14300&lt;/td&gt;
  272.    &lt;/tr&gt;
  273.    &lt;tr&gt;
  274.      &lt;td&gt;Version&lt;/td&gt;
  275.      &lt;td style=&quot;text-align: right&quot;&gt;4-7&lt;/td&gt;
  276.      &lt;td&gt;0x00000002&lt;/td&gt;
  277.    &lt;/tr&gt;
  278.    &lt;tr&gt;
  279.      &lt;td&gt;Bundled GUID&lt;/td&gt;
  280.      &lt;td style=&quot;text-align: right&quot;&gt;8-23&lt;/td&gt;
  281.      &lt;td&gt;{81281204-642c-4840-b2b1-3464ec086564}&lt;/td&gt;
  282.    &lt;/tr&gt;
  283.    &lt;tr&gt;
  284.      &lt;td&gt;Engine (stub) size&lt;/td&gt;
  285.      &lt;td style=&quot;text-align: right&quot;&gt;24-27&lt;/td&gt;
  286.      &lt;td&gt;0x00071600&lt;/td&gt;
  287.    &lt;/tr&gt;
  288.    &lt;tr&gt;
  289.      &lt;td&gt;Original checksum&lt;/td&gt;
  290.      &lt;td style=&quot;text-align: right&quot;&gt;28-31&lt;/td&gt;
  291.      &lt;td&gt;0x00000000&lt;/td&gt;
  292.    &lt;/tr&gt;
  293.    &lt;tr&gt;
  294.      &lt;td&gt;Original signature offset&lt;/td&gt;
  295.      &lt;td style=&quot;text-align: right&quot;&gt;32-35&lt;/td&gt;
  296.      &lt;td&gt;0x00000000&lt;/td&gt;
  297.    &lt;/tr&gt;
  298.    &lt;tr&gt;
  299.      &lt;td&gt;Original signature size&lt;/td&gt;
  300.      &lt;td style=&quot;text-align: right&quot;&gt;36-39&lt;/td&gt;
  301.      &lt;td&gt;0x00000000&lt;/td&gt;
  302.    &lt;/tr&gt;
  303.    &lt;tr&gt;
  304.      &lt;td&gt;Container Type (1 = CAB)&lt;/td&gt;
  305.      &lt;td style=&quot;text-align: right&quot;&gt;40-43&lt;/td&gt;
  306.      &lt;td&gt;1&lt;/td&gt;
  307.    &lt;/tr&gt;
  308.    &lt;tr&gt;
  309.      &lt;td&gt;Container Count&lt;/td&gt;
  310.      &lt;td style=&quot;text-align: right&quot;&gt;44-47&lt;/td&gt;
  311.      &lt;td&gt;2&lt;/td&gt;
  312.    &lt;/tr&gt;
  313.    &lt;tr&gt;
  314.      &lt;td&gt;Byte count of manifest + UX container&lt;/td&gt;
  315.      &lt;td style=&quot;text-align: right&quot;&gt;48-51&lt;/td&gt;
  316.      &lt;td&gt;102,034&lt;/td&gt;
  317.    &lt;/tr&gt;
  318.    &lt;tr&gt;
  319.      &lt;td&gt;Byte count of attached container&lt;/td&gt;
  320.      &lt;td style=&quot;text-align: right&quot;&gt;52-55&lt;/td&gt;
  321.      &lt;td&gt;2,171&lt;/td&gt;
  322.    &lt;/tr&gt;
  323.  &lt;/tbody&gt;
  324. &lt;/table&gt;
  325.  
  326. &lt;h3 id=&quot;intermediateresult&quot;&gt;Intermediate result&lt;/h3&gt;
  327.  
  328. &lt;ul&gt;
  329.  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.wixburn&lt;/code&gt; section points to 104,205 bytes (102,034 + 2,171), starting at 0x00071600.&lt;/li&gt;
  330.  &lt;li&gt;the last PE section ends at 0x000715ff.&lt;/li&gt;
  331.  &lt;li&gt;after using the official Win32 API to edit resources, the file ends at 0x000715ff, and the following 104,205 byte are gone.&lt;/li&gt;
  332. &lt;/ul&gt;
  333.  
  334. &lt;p&gt;So after editing the resources, the exact payload WiX is referring to is eliminated.&lt;/p&gt;
  335.  
  336. &lt;h3 id=&quot;therefore-my-conclusion-is-that-wix&quot;&gt;Therefore my conclusion is that WiX&lt;/h3&gt;
  337.  
  338. &lt;ul&gt;
  339.  &lt;li&gt;adds a (small) section &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.wixburn&lt;/code&gt; pointing beyond the last section, and&lt;/li&gt;
  340.  &lt;li&gt;appends the payload (read: the cabinet file) at that location-&lt;/li&gt;
  341. &lt;/ul&gt;
  342.  
  343. &lt;p&gt;As far as I understand the specification, this procedure is not compliant with the PE format. That might be the reason why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EndUpdateResource&lt;/code&gt; cuts the file after the last section when writing the changed resources.&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term="WiX" /><category term="ResourceLib" /><summary type="html">Some time ago I reported a bug and provided a pull request to resourcelib, a managed library to read and write Win32 resources in executables or DLL’s. And unawarely, the next morning I was a maintainer of that library.</summary></entry><entry><title type="html">Cleaning NuGet’s cache</title><link href="https://thomasfreudenberg.com/archive/2017/04/21/cleaning-nugets-cache/" rel="alternate" type="text/html" title="Cleaning NuGet’s cache" /><published>2017-04-21T00:00:00+00:00</published><updated>2017-04-21T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2017/04/21/cleaning-nugets-cache</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2017/04/21/cleaning-nugets-cache/">&lt;p&gt;From the beginning NuGet used a per-solution folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;packages&lt;/code&gt; to store all packages for
  344. the projects in a solution. (Does anyone else remember the numerous discussion whether
  345. that folder belongs into the VCS or not?).&lt;/p&gt;
  346.  
  347. &lt;p&gt;&lt;a href=&quot;http://blog.nuget.org/20151008/NuGet-3-What-and-Why.html&quot;&gt;That changed&lt;/a&gt; with NuGet 3 and
  348. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;project.json&lt;/code&gt;-based projects:&lt;/p&gt;
  349.  
  350. &lt;blockquote&gt;
  351.  &lt;h3 id=&quot;global-packages-folder&quot;&gt;Global Packages Folder&lt;/h3&gt;
  352.  
  353.  &lt;p&gt;With Project.JSON managed projects, there is now a packages folder that is shared for
  354. all projects that you work with. Packages are downloaded and stored in the
  355. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%userprofile%\.nuget\packages&lt;/code&gt; folder. This means that if you are working on multiple
  356. UWP projects on your workstation, you only have one copy of the EntityFramework package
  357. and its dependencies on your machine. All .NET projects will acquire package references
  358. from this global shared folder. This also means that when you need to configure a new
  359. project, your project will not take time starting so that it can download a fresh copy
  360. of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EntityFramework.nupkg&lt;/code&gt; Instead, it will simply and quickly reference the files you
  361. have already downloaded. ASP.NET 5 uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%userprofile%\.dnx\packages&lt;/code&gt; folder and as
  362. that framework nears completion it will use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%userprofile%\.nuget\packages&lt;/code&gt; folder
  363. as well.&lt;/p&gt;
  364. &lt;/blockquote&gt;
  365.  
  366. &lt;p&gt;Well, I didn’t pay much attention to that change, until I ran out of disk space last
  367. week and used &lt;a href=&quot;https://windirstat.net/&quot;&gt;WinDirTree&lt;/a&gt; to find the culprit. Indeed, the size
  368. of my packages folder was more than 6 GB.&lt;/p&gt;
  369.  
  370. &lt;p&gt;Therefore I wrote a small PowerShell script which deletes all packages which haven’t
  371. been accessed for a configurable number of days (150 by default):&lt;/p&gt;
  372.  
  373. &lt;script src=&quot;https://gist.github.com/c76f1a5533fa86e631b2ed9bbc43c412.js?file=Clear-NuGetCache.ps1&quot;&gt; &lt;/script&gt;
  374.  
  375. &lt;p&gt;Don’t worry that you could delete a package which you would need later again. NuGet will
  376. just download the missing package again.&lt;/p&gt;
  377.  
  378. &lt;p&gt;The script support the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-WhatIf&lt;/code&gt; parameter, so calling&lt;/p&gt;
  379.  
  380. &lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;\Clear-NuGetCache.ps1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-CutOffDays&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-WhatIf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  381. &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  382.  
  383. &lt;p&gt;wouldn’t delete a single byte but log which folders the script would remove.&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term="NuGet" /><category term="PowerShell" /><summary type="html">From the beginning NuGet used a per-solution folder packages to store all packages for the projects in a solution. (Does anyone else remember the numerous discussion whether that folder belongs into the VCS or not?).</summary></entry><entry><title type="html">Pretzel and Kudu on Azure</title><link href="https://thomasfreudenberg.com/archive/2017/03/21/pretzel-and-kudu-on-azure/" rel="alternate" type="text/html" title="Pretzel and Kudu on Azure" /><published>2017-03-21T00:00:00+00:00</published><updated>2017-03-21T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2017/03/21/pretzel-and-kudu-on-azure</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2017/03/21/pretzel-and-kudu-on-azure/">&lt;p&gt;I’ve published a couple of posts about that I’m using &lt;a href=&quot;https://github.com/Code52/pretzel&quot;&gt;Pretzel&lt;/a&gt;
  384. to generate the HTML pages of my blog. However, I didn’t talk about the hosting.&lt;/p&gt;
  385.  
  386. &lt;p&gt;Actually, it’s quite simple: The source files for the site are hosted in a
  387. &lt;a href=&quot;https://github.com/thoemmi/thomasfreudenberg.com&quot;&gt;git repository on GitHub&lt;/a&gt;. The generated site is
  388. hosted in Azure. Whenever I push changes to the git repository, the web site will be updated
  389. automatically.&lt;/p&gt;
  390.  
  391. &lt;p&gt;&lt;img src=&quot;/files/archive/pretzel-and-azure.png&quot; alt=&quot;Pretzel and Azure&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;
  392.  
  393. &lt;p&gt;The setup is a two-stage process: first, you have to create a Azure App Service and connect it to
  394. your git repository. The steps involved are documented very well in
  395. &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/app-service-web/app-service-continuous-deployment&quot;&gt;Continuous Deployment to Azure App Service&lt;/a&gt;.&lt;/p&gt;
  396.  
  397. &lt;p&gt;The second step is to execute Pretzel on the Azure side. Enter &lt;strong&gt;Kudu&lt;/strong&gt;. Kudu is the engine
  398. behind git deployments in Azure. It’s well documented in the &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki&quot;&gt;wiki at GitHub&lt;/a&gt;.
  399. &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki/Deployment&quot;&gt;By default&lt;/a&gt;, Kudu will locate the relevant
  400. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;csproj&lt;/code&gt; file, compile it, and copy the artifacts to wwwroot. That’s why many web sizes running on
  401. Azure contain an empty “shim project”.&lt;/p&gt;
  402.  
  403. &lt;p&gt;However, you can simplify the setup by &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki/Customizing-deployments&quot;&gt;customizing Kudu’s behavior&lt;/a&gt;.
  404. In my case I want Kudu to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pretzel.exe&lt;/code&gt; to generate the static HTML files from my sources:&lt;/p&gt;
  405.  
  406. &lt;ol&gt;
  407.  &lt;li&gt;
  408.    &lt;p&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pretzel.exe&lt;/code&gt; (and all its dependencies) to your git repository (I’ve used a subfolder named
  409. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_pretzel&lt;/code&gt;)&lt;/p&gt;
  410.  &lt;/li&gt;
  411.  &lt;li&gt;
  412.    &lt;p&gt;Add a batch file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.cmd&lt;/code&gt; to execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pretzel.exe&lt;/code&gt;:&lt;/p&gt;
  413.  
  414.    &lt;div class=&quot;language-batch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@echo &lt;span class=&quot;na&quot;&gt;off&lt;/span&gt;
  415. &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Running&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;Pretzel&lt;/span&gt;...
  416. _pretzel\pretzel.exe &lt;span class=&quot;kd&quot;&gt;bake&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;--destination&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%DEPLOYMENT_TARGET%&lt;/span&gt;
  417. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  418.  
  419.    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bake&lt;/code&gt; is the Pretzel’s command to generate the files, and the destination folder is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%DEPLOYMENT_TARGET%&lt;/code&gt;,
  420. which is the wwwroot folder.&lt;/p&gt;
  421.  &lt;/li&gt;
  422.  &lt;li&gt;
  423.    &lt;p&gt;Instruct Kudu to execute that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy.cmd&lt;/code&gt; by creating a file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.deployment&lt;/code&gt; with following
  424. content:&lt;/p&gt;
  425.  
  426.    &lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[config]&lt;/span&gt;
  427. &lt;span class=&quot;py&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;deploy.cmd&lt;/span&gt;
  428. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  429.  &lt;/li&gt;
  430. &lt;/ol&gt;
  431.  
  432. &lt;p&gt;That’s all. Whenever I push changes to the git repository, Kudu will get the current files,
  433. execute Pretzel, and the updated web site is public. The whole process takes less than a minute.&lt;/p&gt;
  434.  
  435. &lt;p&gt;Of course this can be adapted to any other static site generator too, e.g. Jekyll.&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term="Pretzel" /><summary type="html">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.</summary></entry><entry><title type="html">Encrypting values when serializing with JSON.NET</title><link href="https://thomasfreudenberg.com/archive/2017/02/11/encrypting-values-when-serializing-with-json-net/" rel="alternate" type="text/html" title="Encrypting values when serializing with JSON.NET" /><published>2017-02-11T00:00:00+00:00</published><updated>2017-02-11T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2017/02/11/encrypting-values-when-serializing-with-json-net</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2017/02/11/encrypting-values-when-serializing-with-json-net/">&lt;p&gt;In a small inhouse app I wrote recently I store the settings in a json file, using the
  436. popular &lt;a href=&quot;http://www.newtonsoft.com/json&quot;&gt;Json.NET&lt;/a&gt; library. However, the settings
  437. include a password, which should’t appear as clear text in the json file.&lt;/p&gt;
  438.  
  439. &lt;p&gt;I stumbled over &lt;a href=&quot;http://stackoverflow.com/a/29240043/4747&quot;&gt;this&lt;/a&gt; answer at Stack Overflow
  440. by Brian Rogers. This solution uses a custom
  441. &lt;a href=&quot;http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Serialization_IContractResolver.htm&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IContractResolver&lt;/code&gt;&lt;/a&gt;
  442. and a new marker attribute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JsonEncryptAttribute&lt;/code&gt;. Adding the attribute is quite easy:&lt;/p&gt;
  443.  
  444. &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Settings&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  445.    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JsonEncrypt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  446.    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  447. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  448. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  449.  
  450. &lt;p&gt;But you have to remember to add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ContractResolver&lt;/code&gt; additionally:&lt;/p&gt;
  451.  
  452. &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SerializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Formatting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Indented&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonSerializerSettings&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  453.    &lt;span class=&quot;n&quot;&gt;ContractResolver&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;EncryptedStringPropertyResolver&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#my*S3cr3t&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  454. &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  455. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  456.  
  457. &lt;p&gt;Though the solution is clever, I don’t like the custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IContractResolver&lt;/code&gt;. Therefore
  458. I read through Json.NET’s documentation to find an easier way, i.e. by only applying
  459. an attribute to the property to encrypt.&lt;/p&gt;
  460.  
  461. &lt;p&gt;In fact, Json.NET supports custom converters by annotating properties with
  462. &lt;a href=&quot;http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConverterAttribute.htm&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JsonConverterAttribute&lt;/code&gt;&lt;/a&gt;.
  463. That attribute even allows you to pass additional parameters to your custom converter,
  464. like in this case the encryption key.&lt;/p&gt;
  465.  
  466. &lt;p&gt;Therefore I took Brian’s code and converted it into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JsonConverter&lt;/code&gt; (also published as a
  467. &lt;a href=&quot;https://gist.github.com/thoemmi/e118c15e7588750b1cc18dab00be31fd#file-encryptingjsonconverter-cs&quot;&gt;Gist&lt;/a&gt;):&lt;/p&gt;
  468.  
  469. &lt;script src=&quot;https://gist.github.com/e118c15e7588750b1cc18dab00be31fd.js?file=EncryptingJsonConverter.cs&quot;&gt; &lt;/script&gt;
  470.  
  471. &lt;p&gt;And the usage is pretty simple:&lt;/p&gt;
  472.  
  473. &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Settings&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  474.    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;JsonConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EncryptingJsonConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;#my*S3cr3t&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
  475.    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Password&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  476. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  477. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  478.  
  479. &lt;p&gt;There’s no need for any additional code like a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ContractResolver&lt;/code&gt;.
  480. And you can even use different encryption keys for different properties.&lt;/p&gt;
  481.  
  482. &lt;p&gt;My code works only for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; properties though, but that’s all I needed.&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term="JSON.NET" /><summary type="html">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.</summary></entry><entry><title type="html">Presenting Byte Size Values in WPF</title><link href="https://thomasfreudenberg.com/archive/2017/01/21/presenting-byte-size-values-in-wpf/" rel="alternate" type="text/html" title="Presenting Byte Size Values in WPF" /><published>2017-01-21T00:00:00+00:00</published><updated>2017-01-21T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2017/01/21/presenting-byte-size-values-in-wpf</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2017/01/21/presenting-byte-size-values-in-wpf/">&lt;p&gt;Though it’s not my main job, I still enjoy writing WPF application. Small tools, making
  483. my colleagues’ and my own life easier.&lt;/p&gt;
  484.  
  485. &lt;p&gt;Recently I had the requirement to display size values in bytes, kilobytes, etc in a well-rounded way.
  486. You will find many examples for formatting such values in the internet. Most look like this:&lt;/p&gt;
  487.  
  488. &lt;div class=&quot;language-c# highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  489. &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  490.    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024.0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;F1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; GB&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  491. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  492.    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024.0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;F1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; MB&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  493. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  494.    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;F1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; KB&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  495. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  496.    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; Bytes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  497. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  498. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  499.  
  500. &lt;p&gt;or, in a smarter way&lt;/p&gt;
  501.  
  502. &lt;div class=&quot;language-c# highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sizes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;KB&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;MB&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;GB&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TB&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  503. &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  504. &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  505. &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  506.    &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++;&lt;/span&gt;
  507.    &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  508. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  509. &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;##&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  510. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  511.  
  512. &lt;p&gt;However, if you’re on the Windows platform, there’s a much easier option:
  513. &lt;strong&gt;&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/windows/desktop/bb759975(v=vs.85).aspx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StrFormatByteSize&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.
  514. That’s the same method that Explorer is using to display file sizes. Its advantages are that
  515. you don’t have any localization issues, and it it has a fixed precision of 3 digits.&lt;/p&gt;
  516.  
  517. &lt;p&gt;Because my application is using WPF, I wrote an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IValueConverter&lt;/code&gt; to be used in bindings:&lt;/p&gt;
  518.  
  519. &lt;script src=&quot;https://gist.github.com/03b81c07586f63accb83521d783d6749.js?file=FormatKbSizeConverter.cs&quot;&gt; &lt;/script&gt;
  520.  
  521. &lt;p&gt;Formatting binded values in XAML becomes quite easy with that converter
  522. (see &lt;a href=&quot;https://gist.github.com/thoemmi/03b81c07586f63accb83521d783d6749#file-mainwindow-xaml&quot;&gt;full XAML&lt;/a&gt;):&lt;/p&gt;
  523.  
  524. &lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;DataGrid&lt;/span&gt;
  525.  &lt;span class=&quot;na&quot;&gt;AutoGenerateColumns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;False&quot;&lt;/span&gt;
  526.  &lt;span class=&quot;na&quot;&gt;IsReadOnly=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;True&quot;&lt;/span&gt;
  527.  &lt;span class=&quot;na&quot;&gt;ItemsSource=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{StaticResource numbers}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  528.  &lt;span class=&quot;nt&quot;&gt;&amp;lt;DataGrid.Resources&amp;gt;&lt;/span&gt;
  529.    &lt;span class=&quot;c&quot;&gt;&amp;lt;!--  the actual converter  --&amp;gt;&lt;/span&gt;
  530.    &lt;span class=&quot;nt&quot;&gt;&amp;lt;local:FormatKbSizeConverter&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;x:Key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;FormatKbSizeConverter&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  531.  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/DataGrid.Resources&amp;gt;&lt;/span&gt;
  532.  &lt;span class=&quot;nt&quot;&gt;&amp;lt;DataGrid.Columns&amp;gt;&lt;/span&gt;
  533.    &lt;span class=&quot;c&quot;&gt;&amp;lt;!--  First column shows the plain values  --&amp;gt;&lt;/span&gt;
  534.    &lt;span class=&quot;nt&quot;&gt;&amp;lt;DataGridTextColumn&lt;/span&gt;
  535.      &lt;span class=&quot;na&quot;&gt;Binding=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding}&quot;&lt;/span&gt;
  536.      &lt;span class=&quot;na&quot;&gt;ElementStyle=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{StaticResource RightCell}&quot;&lt;/span&gt;
  537.      &lt;span class=&quot;na&quot;&gt;Header=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Plain&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  538.    &lt;span class=&quot;c&quot;&gt;&amp;lt;!--  Second column shows the formatted values  --&amp;gt;&lt;/span&gt;
  539.    &lt;span class=&quot;nt&quot;&gt;&amp;lt;DataGridTextColumn&lt;/span&gt;
  540.      &lt;span class=&quot;na&quot;&gt;Binding=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding Converter={StaticResource FormatKbSizeConverter}}&quot;&lt;/span&gt;
  541.      &lt;span class=&quot;na&quot;&gt;ElementStyle=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{StaticResource RightCell}&quot;&lt;/span&gt;
  542.      &lt;span class=&quot;na&quot;&gt;Header=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Formatted&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  543.  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/DataGrid.Columns&amp;gt;&lt;/span&gt;
  544. &lt;span class=&quot;nt&quot;&gt;&amp;lt;/DataGrid&amp;gt;&lt;/span&gt;
  545. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  546.  
  547. &lt;p&gt;&lt;img src=&quot;/files/archive/FormatKbSizeConverter.png&quot; alt=&quot;FormatKbSizeConverter&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term="WPF" /><summary type="html">Though it’s not my main job, I still enjoy writing WPF application. Small tools, making my colleagues’ and my own life easier.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://thomasfreudenberg.com/files/archive/FormatKbSizeConverter.png" /><media:content medium="image" url="https://thomasfreudenberg.com/files/archive/FormatKbSizeConverter.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Pretzel Plugin: Redirect</title><link href="https://thomasfreudenberg.com/archive/2017/01/08/pretzel-redirect-plugin/" rel="alternate" type="text/html" title="Pretzel Plugin: Redirect" /><published>2017-01-08T00:00:00+00:00</published><updated>2017-01-08T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2017/01/08/pretzel-redirect-plugin</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2017/01/08/pretzel-redirect-plugin/">&lt;p&gt;A while back I wrote about the migration of my blog from Community Server over Jekyll to Pretzel.&lt;/p&gt;
  548.  
  549. &lt;p&gt;One golden rule when restructuring a web site is to avoid dead links. The original web engine was
  550. a classic ASP.NET application, where every URL ends in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.aspx&lt;/code&gt; (at least if you don’t configure
  551. extensionless URLs). Tens years ago every URLs ended in an extension like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.html&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.php&lt;/code&gt;, whatever.
  552. Now-a-days, you barely see any file extensions anymore. The web servers don’t expose the underlying
  553. technology, and the user just doesn’t care. And so does Pretzel.&lt;/p&gt;
  554.  
  555. &lt;p&gt;To use a new URL schema, but preserve the old links and redirect them to the new schema, I wrote
  556. an plugin for Pretzel, &lt;a href=&quot;https://github.com/thoemmi/Pretzel.RedirectFrom&quot;&gt;Pretzel.RedirectFrom&lt;/a&gt;.
  557. I’ve used the &lt;a href=&quot;https://github.com/jekyll/jekyll-redirect-from&quot;&gt;jekyll-redirect-from&lt;/a&gt; plugin as
  558. a guide, so the syntax is the same. Just add alternative URLs in the page’s YAML front-matter:&lt;/p&gt;
  559.  
  560. &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
  561. &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;My&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;First&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Post&quot;&lt;/span&gt;
  562. &lt;span class=&quot;na&quot;&gt;redirect_from&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  563.  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/pages/page1&lt;/span&gt;
  564. &lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
  565. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  566.  
  567. &lt;p&gt;This will generate a small html page at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\pages\page1\index.html&lt;/code&gt;, which will redirect to the new
  568. location:&lt;/p&gt;
  569.  
  570. &lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
  571. &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  572. &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Redirecting...&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  573. &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canonical&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/2016/10/31/myfirstpost.html&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  574. &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;http-equiv=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;refresh&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0; url=/2016/10/31/myfirstpost.html&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  575. &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Redirecting...&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  576. &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/2016/10/31/myfirstpost.html&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Click here if you are not redirected.&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  577. &lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  578.    &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/2016/10/31/myfirstpost.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
  579. &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  580. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  581.  
  582. &lt;p&gt;Pretzel is a static file generator, so the redirection must be performed at the client-side.&lt;/p&gt;
  583.  
  584. &lt;p&gt;However, I prefer a “real” redirect, i.e. a response with the correct HTTP status &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;301 Moved Permanently&lt;/code&gt;.
  585. Therefore I’ve implemented an additional switch. If you’re using IIS (or Azure, or any other web server
  586. supporting ASP.NET), you can specify the switch &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redirect_generate_aspx: true&lt;/code&gt; in Pretzel’s
  587. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;. In this case the generated page will look like this:&lt;/p&gt;
  588.  
  589. &lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%@&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Page&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Language=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;C#&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  590. &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;runat=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;server&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  591. &lt;span class=&quot;kr&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Page_Load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;EventArgs&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  592. &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  593.    &lt;span class=&quot;nx&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;StatusCode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;301&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  594.    &lt;span class=&quot;nx&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;301 Moved Permanently&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  595.    &lt;span class=&quot;nx&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AddHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/2016/10/31/myfirstpost.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  596.    &lt;span class=&quot;nx&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;End&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  597. &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  598. &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  599. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  600.  
  601. &lt;p&gt;This ensures that the server returns the correct HTTP status.&lt;/p&gt;
  602.  
  603. &lt;p&gt;Anyway, this plugin is a &lt;a href=&quot;https://github.com/Code52/pretzel/wiki/create-plugins&quot;&gt;simple ScriptCs file&lt;/a&gt;,
  604. so you only have to copy
  605. &lt;a href=&quot;https://github.com/thoemmi/Pretzel.RedirectFrom/blob/master/Pretzel.RedirectFrom.csx&quot;&gt;Pretzel.RedirectFrom.csx&lt;/a&gt;
  606. to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_plugin&lt;/code&gt; folder of your Pretzel site, and you will be ready to use redirects.&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term="Pretzel" /><summary type="html">A while back I wrote about the migration of my blog from Community Server over Jekyll to Pretzel.</summary></entry><entry><title type="html">Pretzel Plugin: Sitemap</title><link href="https://thomasfreudenberg.com/archive/2016/12/29/pretzel-sitemap/" rel="alternate" type="text/html" title="Pretzel Plugin: Sitemap" /><published>2016-12-29T00:00:00+00:00</published><updated>2016-12-29T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2016/12/29/pretzel-sitemap</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2016/12/29/pretzel-sitemap/">&lt;p&gt;A couple of month ago &lt;a href=&quot;/archive/2016/05/16/from-jekyll-to-pretzel/&quot;&gt;I wrote&lt;/a&gt; that
  607. I switched to &lt;strong&gt;Pretzel&lt;/strong&gt; to drive my site.&lt;/p&gt;
  608.  
  609. &lt;p&gt;What I really like about Pretzel (except that it’s written in .NET) is that it is
  610. so &lt;a href=&quot;https://github.com/Code52/pretzel/wiki/create-plugins&quot;&gt;easy to extend&lt;/a&gt;. You can
  611. write plugins either as a .NET assembly, or—even simpler—throw in an
  612. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.csx&lt;/code&gt; file, because Pretzel supports &lt;a href=&quot;http://scriptcs.net/&quot;&gt;ScriptCs&lt;/a&gt;.&lt;/p&gt;
  613.  
  614. &lt;p&gt;One of the first extensions I wrote was a &lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Site_map&quot;&gt;site map&lt;/a&gt;&lt;/strong&gt;
  615. plugin. By default Pretzel already creates a site map, but only for static pages.
  616. Unfortunately, this doesn’t include paginated pages like the home page. Those pages
  617. are generated dynamically at runtime of Pretzel, and the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sitemap.xml&lt;/code&gt; doesn’t
  618. take those dynamic pages into account.&lt;/p&gt;
  619.  
  620. &lt;p&gt;Therefore I wrote this plugin which creates the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sitemap.xml&lt;/code&gt; including all generated
  621. pages, even the paginated ones. It uses the same technique as
  622. &lt;a href=&quot;https://github.com/Code52/pretzel/blob/master/src/Pretzel.Logic/Templating/JekyllEngineBase.cs#L89&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JekyllEngineBase.ProcessFile&lt;/code&gt;&lt;/a&gt;:
  623. for each post and page it adds an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt; entry to the sitemap. Additionally it checks
  624. the page’s front-matter if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paginate&lt;/code&gt; is specified, and adds relevant URLs to the sitemap
  625. too.&lt;/p&gt;
  626.  
  627. &lt;p&gt;The plugin is &lt;a href=&quot;https://github.com/thoemmi/Pretzel.Sitemap&quot;&gt;hosted on Github&lt;/a&gt; including
  628. some basic tests, but in fact you only have to copy
  629. &lt;a href=&quot;https://github.com/thoemmi/Pretzel.Sitemap/blob/master/Pretzel.Sitemap.csx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Pretzel.Sitemap.csx&lt;/code&gt;&lt;/a&gt;
  630. to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_plugin&lt;/code&gt; folder of your Pretzel site.&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term="Pretzel" /><summary type="html">A couple of month ago I wrote that I switched to Pretzel to drive my site.</summary></entry><entry><title type="html">Naming Events in .NET</title><link href="https://thomasfreudenberg.com/archive/2016/07/01/naming-events-in-dotnet/" rel="alternate" type="text/html" title="Naming Events in .NET" /><published>2016-07-01T00:00:00+00:00</published><updated>2016-12-29T00:00:00+00:00</updated><id>https://thomasfreudenberg.com/archive/2016/07/01/naming-events-in-dotnet</id><content type="html" xml:base="https://thomasfreudenberg.com/archive/2016/07/01/naming-events-in-dotnet/">&lt;p&gt;&lt;strong&gt;Update 2016/12/29&lt;/strong&gt;: I’ve complained about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;On&lt;/code&gt; prefix in the &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/articles/csharp/events-overview#comments-container&quot;&gt;comment section&lt;/a&gt;
  631. of the documentation (and &lt;a href=&quot;http://blog.gauffin.org/&quot;&gt;Jonas Gauffin&lt;/a&gt; too). In fact the prefix was a mistake and
  632. is &lt;a href=&quot;https://github.com/dotnet/docs/pull/1012&quot;&gt;fixed&lt;/a&gt; by now.&lt;/p&gt;
  633.  
  634. &lt;hr /&gt;
  635.  
  636. &lt;p&gt;Things are changing in the .NET world. A couple of days ago Microsoft released
  637. &lt;a href=&quot;https://blogs.msdn.microsoft.com/dotnet/2016/06/27/announcing-net-core-1-0/&quot;&gt;.NET Core 1.0&lt;/a&gt;,
  638. the new cross-platform, open source, and modular .NET platform.&lt;/p&gt;
  639.  
  640. &lt;p&gt;Unfortunately, not only the managed framework’s changing, but naming guidelines
  641. too.&lt;/p&gt;
  642.  
  643. &lt;p&gt;Lets start with the old .NET framework. Microsoft says in the
  644. &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms229012.aspx#Anchor_2&quot;&gt;Naming Guideline for Events&lt;/a&gt;:&lt;/p&gt;
  645.  
  646. &lt;blockquote&gt;
  647.  &lt;p&gt;&lt;strong&gt;✓ DO&lt;/strong&gt; name events with a verb or a verb phrase.&lt;/p&gt;
  648.  
  649.  &lt;p&gt;Examples include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clicked&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Painting&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DroppedDown&lt;/code&gt;, and so on.&lt;/p&gt;
  650.  
  651.  &lt;p&gt;&lt;strong&gt;✓ DO&lt;/strong&gt; give events names with a concept of before and after, using the present
  652. and past tenses.&lt;/p&gt;
  653.  
  654.  &lt;p&gt;For example, a close event that is raised before a window is closed would be
  655. called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Closing&lt;/code&gt;, and one that is raised after the window is closed would be
  656. called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Closed&lt;/code&gt;.&lt;/p&gt;
  657. &lt;/blockquote&gt;
  658.  
  659. &lt;p&gt;The (slightly outdated) &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/h0eyck3s(VS.71).aspx&quot;&gt;Event Naming Guidelines for .NET Framework 1.1&lt;/a&gt;
  660. even says more explicitly:&lt;/p&gt;
  661.  
  662. &lt;blockquote&gt;
  663.  &lt;ul&gt;
  664.    &lt;li&gt;Do not use a prefix or suffix on the event declaration on the type. For
  665. example, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Close&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnClose&lt;/code&gt;.&lt;/li&gt;
  666.  &lt;/ul&gt;
  667. &lt;/blockquote&gt;
  668.  
  669. &lt;p&gt;That’s what we’ve been taught for the last 15 years: Events are named without
  670. a prefix.&lt;/p&gt;
  671.  
  672. &lt;p&gt;Let’s repeat: Events are named without a prefix.&lt;/p&gt;
  673.  
  674. &lt;h2 id=&quot;entry-net-core&quot;&gt;Entry .NET Core!&lt;/h2&gt;
  675.  
  676. &lt;p&gt;&lt;a href=&quot;https://github.com/MrRoundRobin&quot;&gt;Robin Müller&lt;/a&gt;, maintainer of the &lt;a href=&quot;https://github.com/MrRoundRobin/telegram.bot&quot;&gt;telegram.bot&lt;/a&gt;
  677. library, changed the names of all event from an unprefixed name to prefixed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;On&lt;/code&gt;
  678. in a &lt;a href=&quot;https://github.com/MrRoundRobin/telegram.bot/commit/54860e7048c2a0b76a206739d1bc1a2795e31199&quot;&gt;recent commit&lt;/a&gt;.
  679. I complained that this renaming would contradict the guidelines recommendations by Microsoft
  680. and what we’ve learnt the last 15 years.&lt;/p&gt;
  681.  
  682. &lt;p&gt;However, Robin pointed me to the &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/articles/csharp/events-overview#language-support-for-events&quot;&gt;new guidelines&lt;/a&gt;
  683. (emphasis mine):&lt;/p&gt;
  684.  
  685. &lt;blockquote&gt;
  686.  &lt;p&gt;There are a number of conventions that you should follow when declaring an event.
  687. Typically, the event delegate type has a void return. &lt;strong&gt;Prefix event declarations
  688. with ‘On’.&lt;/strong&gt; The remainder of the name is a verb.&lt;/p&gt;
  689. &lt;/blockquote&gt;
  690.  
  691. &lt;p&gt;WTF? Do we have to forget the old habits and rename all events when moving from good ol’
  692. .NET Framework to .NET Core?&lt;/p&gt;
  693.  
  694. &lt;p&gt;The new guidelines include a comment section at the bottom where I asked for the rational
  695. behind the changed guideline a few days ago, but I still got no answer. I’d really like to
  696. now…&lt;/p&gt;
  697.  
  698. &lt;p&gt;&lt;strong&gt;Sidenote:&lt;/strong&gt; Most of us are used to name the &lt;strong&gt;handler&lt;/strong&gt; for an event
  699. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;On&amp;lt;name of the event&amp;gt;&lt;/code&gt;, e.g.&lt;/p&gt;
  700.  
  701. &lt;div class=&quot;language-c# highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SomethingHappened&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnSomethingHappened&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  702. &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
  703.  
  704. &lt;p&gt;What should we call those event handlers now? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnOnSomethingHappened&lt;/code&gt;?&lt;/p&gt;</content><author><name>Thomas Freudenberg</name></author><category term=".NET" /><summary type="html">Update 2016/12/29: I’ve complained about the On prefix in the comment section of the documentation (and Jonas Gauffin too). In fact the prefix was a mistake and is fixed by now.</summary></entry></feed>

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid Atom 1.0" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=http%3A//thomasfreudenberg.com/feed.xml

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda