The Ramblings of TerribleDevMy name is Tommy Parnell. I usually go by TerribleDev on the internets. These are just some of my writings and rants about the software space.2022-07-08T09:18:00Zhttps://blog.terrible.dev/Tommy ParnellBuilding attractive CLIs in TypeScript2022-07-08T09:18:00Zhttps://blog.terrible.dev/blog/Building-attractive-CLIs-in-JavaScript/<p>So you've come to a point where you want to build nice CLIs. There's a few different options for building CLI's. My two favorites are <a href="https://oclif.io/">oclif</a> and <a href="https://github.com/tj/commander.js/">commander.js</a>. I tend toward leaning to commander, unless I know I'm building a super big app. However, I've really enjoyed building smaller CLIs with commander recently.</p>
<!-- more -->
<blockquote>
<p>tl;dr? You can <a href="https://github.com/TerribleDev/example-ts-cli">view this repo</a></p>
</blockquote>
<p><img src="https://blog.terrible.dev/blog/Building-attractive-CLIs-in-JavaScript/cli.gif" alt="a video of the CLI"></p>
<h2>Commander.js Lingo</h2>
<p>So commander has a few different nouns.</p>
<ul>
<li><code>Program</code> - The root of the CLI. Handles running the core app.</li>
<li><code>Command</code> - A command that can be run. These must be registered into <code>Program</code></li>
<li><code>Option</code> - I would also call these <code>flags</code> they're the <code>--something</code> part of the CLI.</li>
<li><code>Arguments</code> - These are named positioned arguments. For example <code>npm install commander</code> the <code>commander</code> string in this case is an argument. <code>--save</code> would be an option.</li>
</ul>
<h2>Initial Setup</h2>
<p>First, do an npm init, and install commander, types for node, typescript, esbuild, and optionally ora.</p>
<pre class="language-bash" tabindex="0"><code class="language-bash"><span class="token function">npm</span> init <span class="token parameter variable">-y</span>
<span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">--save</span> commander typescript @types/node ora</code></pre>
<p>Next we have to configure a build command in the package.json. This one runs typescript to check for types and then esbuild to compile the app for node.</p>
<pre class="language-json" tabindex="0"><code class="language-json"> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"tsc --noEmit ./index.ts && esbuild index.ts --bundle --platform=node --format=cjs --outfile=dist/index.js"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p>We now need to add a bin property in the package.json. This tells the package manager that we have an executable. The key should be the name of your CLI</p>
<pre class="language-json" tabindex="0"><code class="language-json"><span class="token property">"bin"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"<yourclinamehere>"</span><span class="token operator">:</span> <span class="token string">"./dist/index.js"</span>
<span class="token punctuation">}</span></code></pre>
<p>Make a file called index.ts, and place this string on the first line. This is called a shebang and it tells your shell to use node when the file is ran.</p>
<p><code>#!/usr/bin/env node</code></p>
<h2>Getting started</h2>
<p>Hopefully you have done the above. Now in index.ts you can make a very basic program. Try npm build and then run the CLI with --help. Hopefully you'll get some output.</p>
<pre class="language-ts" tabindex="0"><code class="language-ts"><span class="token hashbang comment">#!/usr/bin/env node</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Command <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'commander'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> spinnerError<span class="token punctuation">,</span> stopSpinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./spinner'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> program <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Command</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
program<span class="token punctuation">.</span><span class="token function">description</span><span class="token punctuation">(</span><span class="token string">'Our New CLI'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
program<span class="token punctuation">.</span><span class="token function">version</span><span class="token punctuation">(</span><span class="token string">'0.0.1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">await</span> program<span class="token punctuation">.</span><span class="token function">parseAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// log a new line so there is a nice space</span>
<span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3>Setting up the spinner</h3>
<p>So, I really like loading spinners. I think it gives the CLI a more polished feel. So I added a spinner using ora. I made a file called <code>spinner.ts</code> which is a wrapper to handle states of spinning or stopped.</p>
<pre class="language-ts" tabindex="0"><code class="language-ts"><span class="token keyword">import</span> ora <span class="token keyword">from</span> <span class="token string">'ora'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> spinner <span class="token operator">=</span> <span class="token function">ora</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token comment">// make a singleton so we don't ever have 2 spinners</span>
spinner<span class="token operator">:</span> <span class="token string">'dots'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">updateSpinnerText</span> <span class="token operator">=</span> <span class="token punctuation">(</span>message<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>spinner<span class="token punctuation">.</span>isSpinning<span class="token punctuation">)</span> <span class="token punctuation">{</span>
spinner<span class="token punctuation">.</span>text <span class="token operator">=</span> message
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
spinner<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">stopSpinner</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>spinner<span class="token punctuation">.</span>isSpinning<span class="token punctuation">)</span> <span class="token punctuation">{</span>
spinner<span class="token punctuation">.</span><span class="token function">stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">spinnerError</span> <span class="token operator">=</span> <span class="token punctuation">(</span>message<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>spinner<span class="token punctuation">.</span>isSpinning<span class="token punctuation">)</span> <span class="token punctuation">{</span>
spinner<span class="token punctuation">.</span><span class="token function">fail</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">spinnerSuccess</span> <span class="token operator">=</span> <span class="token punctuation">(</span>message<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>spinner<span class="token punctuation">.</span>isSpinning<span class="token punctuation">)</span> <span class="token punctuation">{</span>
spinner<span class="token punctuation">.</span><span class="token function">succeed</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">spinnerInfo</span> <span class="token operator">=</span> <span class="token punctuation">(</span>message<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
spinner<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<h3>Writing a command</h3>
<p>So I like to separate my commands out into sub-commands. In this case we're making <code>widgets</code> a sub-command. Make a new file, I call it widgets.ts. I create a new <code>Command</code> called <code>widgets</code>. Commands can have commands making them sub-commands. So we can make a sub-command called <code>list</code> and <code>get</code>. <strong>List</strong> will list all the widgets we have, and <strong>get</strong> will retrive a widget by id. I added some promise to emulate some delay so we can see the spinner in action.</p>
<pre class="language-ts" tabindex="0"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> Command <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"commander"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> spinnerError<span class="token punctuation">,</span> spinnerInfo<span class="token punctuation">,</span> spinnerSuccess<span class="token punctuation">,</span> updateSpinnerText <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./spinner"</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> widgets <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Command</span><span class="token punctuation">(</span><span class="token string">"widgets"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
widgets<span class="token punctuation">.</span><span class="token function">command</span><span class="token punctuation">(</span><span class="token string">"list"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">action</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token function">updateSpinnerText</span><span class="token punctuation">(</span><span class="token string">"Processing "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// do work</span>
<span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name"><span class="token builtin">Promise</span></span><span class="token punctuation">(</span>resolve <span class="token operator">=></span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// emulate work</span>
<span class="token function">spinnerSuccess</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">table</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">"Tommy"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">"Bob"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
widgets<span class="token punctuation">.</span><span class="token function">command</span><span class="token punctuation">(</span><span class="token string">"get"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">argument</span><span class="token punctuation">(</span><span class="token string">"<id>"</span><span class="token punctuation">,</span> <span class="token string">"the id of the widget"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">option</span><span class="token punctuation">(</span><span class="token string">"-f, --format <format>"</span><span class="token punctuation">,</span> <span class="token string">"the format of the widget"</span><span class="token punctuation">)</span> <span class="token comment">// an optional flag, this will be in options.f</span>
<span class="token punctuation">.</span><span class="token function">action</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span>id<span class="token punctuation">,</span> options<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token function">updateSpinnerText</span><span class="token punctuation">(</span><span class="token string">"Getting widget "</span> <span class="token operator">+</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name"><span class="token builtin">Promise</span></span><span class="token punctuation">(</span>resolve <span class="token operator">=></span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">spinnerSuccess</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">table</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">"Tommy"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<p>Now lets register this command into our program. (see the last line)</p>
<pre class="language-ts" tabindex="0"><code class="language-ts"><span class="token hashbang comment">#!/usr/bin/env node</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Command <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'commander'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> spinnerError<span class="token punctuation">,</span> stopSpinner <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./spinner'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> widgets <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./widgets'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> program <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Command</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
program<span class="token punctuation">.</span><span class="token function">description</span><span class="token punctuation">(</span><span class="token string">'Our New CLI'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
program<span class="token punctuation">.</span><span class="token function">version</span><span class="token punctuation">(</span><span class="token string">'0.0.1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
program<span class="token punctuation">.</span><span class="token function">addCommand</span><span class="token punctuation">(</span>widgets<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Do a build! Hopefully you can type <code><yourcli> widgets list</code> and you'll see the spinner. When you call <code>spinnerSuccess</code> without any parameters the previous spinner text will stop and become a green check. You can pass a message instead to print that to the console. You can also call <code>spinnerError</code> to make the spinner a red <code>x</code> and print the message.</p>
<h3>Handle unhandled errors</h3>
<p>Back in index.ts we need to add a hook to capture unhandled errors. Add a verbose flag to the program so we can see more details about the error, but by default lets hide the errors.</p>
<pre class="language-ts" tabindex="0"><code class="language-ts"><span class="token keyword">const</span> program <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Command</span><span class="token punctuation">(</span><span class="token string">'Our New CLI'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
program<span class="token punctuation">.</span><span class="token function">option</span><span class="token punctuation">(</span><span class="token string">'-v, --verbose'</span><span class="token punctuation">,</span> <span class="token string">'verbose logging'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now we need to listen for the node unhandled promise rejection event and process it.</p>
<pre class="language-ts" tabindex="0"><code class="language-ts">process<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'unhandledRejection'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>err<span class="token operator">:</span> Error<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// listen for unhandled promise rejections</span>
<span class="token keyword">const</span> debug <span class="token operator">=</span> program<span class="token punctuation">.</span><span class="token function">opts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>verbose<span class="token punctuation">;</span> <span class="token comment">// is the --verbose flag set?</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>debug<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span>stack<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// print the stack trace if we're in verbose mode</span>
<span class="token punctuation">}</span>
<span class="token function">spinnerError</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// show an error spinner</span>
<span class="token function">stopSpinner</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// stop the spinner</span>
program<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> exitCode<span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// exit with error code 1</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<h4>Testing our error handling</h4>
<p>Lets make a widget action called <code>unhandled-error</code>. Do a build, and then run this action. You should see the error is swallowed. Now try again but use <code><yourcli> --verbose widgets unhandled-error</code> and you should see the error stack trace.</p>
<pre class="language-ts" tabindex="0"><code class="language-ts">widgets<span class="token punctuation">.</span><span class="token function">command</span><span class="token punctuation">(</span><span class="token string">"unhandled-error"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">action</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token function">updateSpinnerText</span><span class="token punctuation">(</span><span class="token string">"Processing an unhandled failure "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name"><span class="token builtin">Promise</span></span><span class="token punctuation">(</span>resolve <span class="token operator">=></span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Unhandled error"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<h2>Organizing the folders</h2>
<p>Ok, so you have the basics all setup. Now, how do you organize the folders. I like to have the top level commands in their own directories. That way the folder structure emulates the CLI. This is an idea I saw in oclif.</p>
<pre><code>- index.ts
- /commands/widgets/index.ts
- /commands/widgets/list.ts
- /commands/widgets/get.ts
</code></pre>
<h2>So why not OCLIF?</h2>
<p>A few simple reasons. OCLIF's getting started template comes with an extremely opinionated typescript configuration. For large projects, I've found it to be incredible. However, for smaller-ish things, I've found conforming to it, a trial of turning down the linter a lot. Overall, they're both great tools. Why not both?</p>
Speeding up CraftCMS on Heroku2022-04-13T11:55:00Zhttps://blog.terrible.dev/blog/Speeding-up-CraftCMS-on-Heroku/<p>So, I previously <a href="https://blog.terrible.dev/Hosting-craft-on-heroku/">blogged about how we hosted CraftCMS</a> on Heroku. When we built the marketing site for <a href="https://www.quala.io">Quala</a> the twig templates were built for maximum authoring flexibility at the cost of some TTFB problems. We knew this going into the project. In an ideal world we would use GatsbyJS to build the frontend, but we very limited in time. When we went live, we saw a dramatic improvement to First Contentful paint, but a huge decrease to Time To First Byte, averaging at 1.3 seconds.</p>
<!-- more -->
<p>The initial thinking that was bounced around was <em>we just need caching</em> as our previous wordpress site had cached all renderings in memory. However, we wanted to start rendering CSRF tokens to the browser, and collecting form data. Furthermore, I struggled to come to terms with this being a solution. Simply put, I'm not a fan of PHP, and I know that the Yii framework is known to be slow even in the PHP community, but I couldn't believe that it should be <em>that</em> slow. We did sprinkle some cache tags around our twig templates, and it did improve things, but not enough to brag about. So I started digging into the docs of Heroku, Nginx, and FastCGI.</p>
<h2>Heroku's buildpack</h2>
<p>So <a href="https://devcenter.heroku.com/articles/php-support#php-fpm-configuration">Heroku's buildpack docs</a> contains a lot of very good information. Props to them for docs! I ran into this one quote.</p>
<blockquote>
<p>PHP-FPM is set up to automatically spawn a suitable number of worker processes depending on dyno size and the configured PHP memory_limit</p>
</blockquote>
<p>This made me go look at another article I found by them regarding <a href="https://devcenter.heroku.com/articles/php-concurrency">php concurrency</a>. This article boils down to, different dynos have different memory limits. They allocate 128mb to a php process and divide that by the total memory on a machine and that is used to determine how many threads to have on a single dyno. They also look for a <code>.user.ini</code> file if you want to override the memory defaults. So first I realized our <code>.user.ini</code> file had specified <code>memory_limit = 256M</code> which was causing us to have half as many processes per dyno, so I set this back to 128. Ok great, this did improve things a little. I then read that you could override the concurrency default behavior by setting the environment variable <code>WEB_CONCURRENCY</code> to be whatever you wanted. This did come with a warning.</p>
<blockquote>
<p>When setting WEB_CONCURRENCY manually, make sure that its value multiplied by your memory_limit does not exceed the amount of RAM available on your dyno type.</p>
</blockquote>
<p>Now I started doing some load testing of my own, and while it would over subscribe the dyno, I gave us 10 on a 2x dyno which theoretically would cause us to OOM but with some basic load testing didnt seem like it would happen. This gave us some boost, but not as much as we hoped. I was still very stuck, and I had a suspicion that maybe there was some problem between PHP and Nginx which was slowing things down. I used the craft diagnostic tools, and I couldn't find more than 400ms being wasted in sql queries which didn't account for the almost 1 second page load I still had.</p>
<h2>Nginx configs</h2>
<p>Ok, so I started looking around, and I found a <a href="https://nystudio107.com/">TON of great CraftCMS content by nystudio107</a>. I don't quite remember which article, but I stumbled across several that implied I needed better fastcgi settings in Nginx. So, I <a href="https://github.com/qualaio/heroku-buildpack-php">forked the heroku buildpack</a> and got to work. I ended up making these settings.</p>
<pre class="language-nginx" tabindex="0"><code class="language-nginx"><span class="token directive"><span class="token keyword">fastcgi_buffers</span> <span class="token number">256</span> <span class="token number">16k</span></span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_buffer_size</span> <span class="token number">128k</span></span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_connect_timeout</span> <span class="token number">10s</span></span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_send_timeout</span> <span class="token number">120s</span></span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_read_timeout</span> <span class="token number">120s</span></span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_busy_buffers_size</span> <span class="token number">256k</span></span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_temp_file_write_size</span> <span class="token number">256k</span></span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">reset_timedout_connection</span> <span class="token boolean">on</span></span><span class="token punctuation">;</span></code></pre>
<h2>Brotli</h2>
<p>While I was in the config, I decided <em>what the hell, lets get brolti working</em>. <a href="https://github.com/google/brotli">Brotli</a> is a compression format that is more compact than gzip. Over the wire assets are usually 5-10% smaller than gzipped. So, sending brotli if the browser supports it, is a big win. Turns out there is an <a href="https://github.com/heroku/heroku-buildpack-php/issues/356">issue filed in 2019 with heroku</a> to add it, but its not gone anywhere. Ultimately, I found someone else <a href="https://github.com/seyallin/heroku-brotli-nginx">figured out how to add it</a>. I made some changes and added it to our fork. You can view all of our changes in <a href="https://github.com/heroku/heroku-buildpack-php/compare/main...qualaio:main#diff-ff7b43f722c67a80d4c82bf656918b3bf96f553a5ad1f62ef185dff16582f033R24-R31">github's compare view</a>.</p>
<h2>Results</h2>
<p>So the results was a <strong>huge</strong> drop in TTFB, which overall improved our ligthhouse score by 30 points. The other thing that's great is, we're moderately fast without caches, which means caches can only improve the situation further.</p>
<p><img src="https://blog.terrible.dev/blog/Speeding-up-CraftCMS-on-Heroku/1.png" alt="A graph showing a drop in response time from over 1 second to less than one"></p>
<hr>
Dynamically changing the site-theme meta tag2022-04-12T15:05:00Zhttps://blog.terrible.dev/blog/Dynamically-changing-the-site-theme-meta-tag/<p>So, incase you are unfamiliar, there is a meta tag called <code><meta name="theme-color" content="..."></code> that is used to change the color of the navbar on desktop safari, mobile safari, and mobile chrome. If you don't set a value these browsers tend to find a color that match the site to the best of their ability. However, sometimes even setting the value can cause the site to look ugly.</p>
<!-- more -->
<p>So, I've been recently working on an NFT project called <a href="http://squigglesquatches.io/">Squiggle Squatches</a>. NFT projects are essentially digital art projects for sale. Our website, really needs to reflect our look and feel as much as we can. When I first loaded our page, I noticed this <strong>huge</strong> white bar on the top of Safari.</p>
<p><img src="https://blog.terrible.dev/blog/Dynamically-changing-the-site-theme-meta-tag/1.jpg" alt="An un-themed page with a big white bar at the top of the page"></p>
<blockquote>
<p>So I set out to change this. I knew there was a <code><meta name="theme-color" content="..."></code> tag that can add the theme.</p>
</blockquote>
<p>I first made the theme be the color of the top section, and this looked great!</p>
<p><img src="https://blog.terrible.dev/blog/Dynamically-changing-the-site-theme-meta-tag/2.jpg" alt="An theme where the top bar color clashes on scroll"></p>
<p>However after scrolling, I noticed this looked super ugly.</p>
<p><img src="https://blog.terrible.dev/blog/Dynamically-changing-the-site-theme-meta-tag/3.jpg" alt="An theme where the top bar color clashes on scroll"></p>
<p>So I decided to write some code to fix this problem.</p>
<h2>Listening to scroll events</h2>
<p>So, I started with decorating certain tags with a <code>data-scroll-theme</code> attribute that signaled our code to look at this div to manipulate the theme color. This looks like <code><section data-scroll-theme class="blue/red/etc">content</section></code></p>
<p>I then ended up crafting this JS code. Basically, make a throttle function so we only fire our event every 100ms. Grab the default color. Then on scroll figure out if any boxes are at the top of the page, and if so set the meta tag to that color.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token comment">// a function to only call the wrapped functions every x milliseconds so the scroll event doesn't make our function run all the time</span>
<span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> timeFrame</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> lastTime <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> now <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>now <span class="token operator">-</span> lastTime <span class="token operator">>=</span> timeFrame<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">func</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
lastTime <span class="token operator">=</span> now<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// get the theme color on load so we can revert to this</span>
<span class="token keyword">const</span> ogColor <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[name="theme-color"]'</span><span class="token punctuation">)</span><span class="token operator">?.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">'content'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// handle scroll event</span>
<span class="token keyword">const</span> handleScroll <span class="token operator">=</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token comment">// find all tags that have `data-scroll as a property`</span>
<span class="token keyword">const</span> targets <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'[data-scroll-theme]'</span><span class="token punctuation">)</span>
<span class="token comment">// are any targets at the top of the window?</span>
<span class="token keyword">const</span> isTop <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>targets<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> rect <span class="token operator">=</span> target<span class="token punctuation">.</span><span class="token function">getBoundingClientRect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>rect<span class="token punctuation">.</span>y <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span> target<span class="token punctuation">,</span> rect <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> b<span class="token punctuation">.</span>rect<span class="token punctuation">.</span>y <span class="token operator">-</span> a<span class="token punctuation">.</span>rect<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
<span class="token comment">// if we found an element at the top of the document then</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>isTop<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// set theme color meta tag to the background color of div</span>
<span class="token keyword">const</span> color <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">getComputedStyle</span><span class="token punctuation">(</span>isTop<span class="token punctuation">.</span>target<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getPropertyValue</span><span class="token punctuation">(</span><span class="token string">'background-color'</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>color<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// find the theme color meta tag and set the attribute to it</span>
document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[name="theme-color"]'</span><span class="token punctuation">)</span><span class="token operator">?.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'content'</span><span class="token punctuation">,</span> color<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>ogColor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// set theme color meta tag to original</span>
document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[name="theme-color"]'</span><span class="token punctuation">)</span><span class="token operator">?.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'content'</span><span class="token punctuation">,</span> ogColor<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// run every 100ms</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span>
document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'scroll'</span><span class="token punctuation">,</span> handleScroll<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">passive</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre>
<h2>End result</h2>
<p>The end result is the top bar of safari changes as you scroll between blocks. This has made <a href="http://squigglesquatches.io/">Squiggle Squatches</a> look way better on mobile.</p>
<iframe width="662" height="1176" src="https://www.youtube.com/embed/iLksuqZP4L8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<!-- ![video](https://youtu.be/iLksuqZP4L8) -->
<p>You can see a simpler example on <a href="https://replit.com/@TerribleDev/ScrollableTheme">replit</a></p>
<iframe frameborder="0" width="100%" height="500px" src="https://replit.com/@TerribleDev/ScrollableTheme?embed=true#script.js"></iframe>Serving AMP Pages with Dotnet Core2022-03-10T11:00:00Zhttps://blog.terrible.dev/blog/Serving-AMP-Pages-with-dotnet-core/<p>I remember when (Accelerated Mobile Pages) first came out, and it was very restrictive and weird. I think this ultimately hurt the <em>AMP Brand</em> Beyond this, several companies have built AMP experiences which haven't always been the best experience. I do however think AMP pages always load extremely fast. A lot of that is just the constraints of AMP. Last night I put my blog posts on AMP for a laugh, and it was much easier than I thought it would be.</p>
<!-- more -->
<h2>Step 0</h2>
<p>Download the <a href="https://chrome.google.com/webstore/detail/amp-validator/nmoffdblmcmgeicmolmhobpoocbbmknc?hl=en">AMP chrome extension</a> and read what your violations are on an existing page you want to serve as an amp page.</p>
<h2>AMP Requirements</h2>
<p>So these days AMP is a webpage with several restrictions.</p>
<ul>
<li>No JavaScript, or well very restrictive JS.
<ul>
<li>JS is possible, but not without work. For the sake of this tutorial I decided to skip the JS.</li>
</ul>
</li>
<li>Inlined only css</li>
<li>No <code>picture</code> tags</li>
<li>A few other tags you need for AMP.</li>
</ul>
<h2>Razor</h2>
<p>First things first, we need to figure out how we will adjust our layout for AMP. The easiest way for a layout to get a variable either from any controller or any razor page is using the <code>ViewData</code> dictionary. I added the following at the top of my layout page. This lets me read if we are in an amp page.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">@<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> amp <span class="token operator">=</span> ViewData<span class="token punctuation">[</span><span class="token string">"amp"</span><span class="token punctuation">]</span> <span class="token keyword">as</span> <span class="token class-name"><span class="token keyword">bool</span><span class="token punctuation">?</span></span> <span class="token operator">??</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> htmlTag <span class="token operator">=</span> amp <span class="token punctuation">?</span> <span class="token string">"amp"</span> <span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Ok, so lets dive into the required HTML markup. AMP pages require a...</p>
<ul>
<li><code><html></code> tag with an <code>amp</code> attribute.</li>
<li>a <code><head></code> tag with an <code><amp-boilerplate></code> tag that contains some boilerplate CSS.</li>
<li>The amp JS runtime</li>
<li><code><link></code> tags to point the non-amp page at the amp page.</li>
</ul>
<p>HTML tag is an easy start. The code block above has an <code>htmlTag</code> attribute that is used for the tag.</p>
<pre class="language-cshtml" tabindex="0"><code class="language-cshtml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span> <span class="token attr-name">@htmlTag</span><span class="token punctuation">></span></span></code></pre>
<p>The head tag containing the boilerplate CSS is easy. Note that the boilerplate has <code>@</code> signs for CSS which need to be <code>@@</code> in razor, to escape the <code>@</code> sign.</p>
<pre class="language-cshtml" tabindex="0"><code class="language-cshtml"><span class="token block"><span class="token keyword">@if</span><span class="token csharp language-csharp"><span class="token punctuation">(</span>amp<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name">amp-boilerplate</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><span class="token selector">body</span><span class="token punctuation">{</span><span class="token property">-webkit-animation</span><span class="token punctuation">:</span>-amp-start 8s <span class="token function">steps</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span>end<span class="token punctuation">)</span> 0s 1 normal both<span class="token punctuation">;</span><span class="token property">-moz-animation</span><span class="token punctuation">:</span>-amp-start 8s <span class="token function">steps</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span>end<span class="token punctuation">)</span> 0s 1 normal both<span class="token punctuation">;</span><span class="token property">-ms-animation</span><span class="token punctuation">:</span>-amp-start 8s <span class="token function">steps</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span>end<span class="token punctuation">)</span> 0s 1 normal both<span class="token punctuation">;</span><span class="token property">animation</span><span class="token punctuation">:</span>-amp-start 8s <span class="token function">steps</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span>end<span class="token punctuation">)</span> 0s 1 normal both<span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@-webkit-keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@-moz-keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@-ms-keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@-o-keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span></span><span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>noscript</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name">amp-boilerplate</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><span class="token selector">body</span><span class="token punctuation">{</span><span class="token property">-webkit-animation</span><span class="token punctuation">:</span>none<span class="token punctuation">;</span><span class="token property">-moz-animation</span><span class="token punctuation">:</span>none<span class="token punctuation">;</span><span class="token property">-ms-animation</span><span class="token punctuation">:</span>none<span class="token punctuation">;</span><span class="token property">animation</span><span class="token punctuation">:</span>none<span class="token punctuation">}</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>noscript</span><span class="token punctuation">></span></span></span>
<span class="token punctuation">}</span></span></span></code></pre>
<p>Finally, the JS runtime. This needs to also go in the head tag. You can include this with the boilerplate code.</p>
<pre class="language-cshtml" tabindex="0"><code class="language-cshtml"><span class="token block"><span class="token keyword">@if</span><span class="token csharp language-csharp"><span class="token punctuation">(</span>amp<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name">amp-boilerplate</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><span class="token selector">body</span><span class="token punctuation">{</span><span class="token property">-webkit-animation</span><span class="token punctuation">:</span>-amp-start 8s <span class="token function">steps</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span>end<span class="token punctuation">)</span> 0s 1 normal both<span class="token punctuation">;</span><span class="token property">-moz-animation</span><span class="token punctuation">:</span>-amp-start 8s <span class="token function">steps</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span>end<span class="token punctuation">)</span> 0s 1 normal both<span class="token punctuation">;</span><span class="token property">-ms-animation</span><span class="token punctuation">:</span>-amp-start 8s <span class="token function">steps</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span>end<span class="token punctuation">)</span> 0s 1 normal both<span class="token punctuation">;</span><span class="token property">animation</span><span class="token punctuation">:</span>-amp-start 8s <span class="token function">steps</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span>end<span class="token punctuation">)</span> 0s 1 normal both<span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@-webkit-keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@-moz-keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@-ms-keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@-o-keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span>@<span class="token atrule"><span class="token rule">@keyframes</span> -amp-start</span><span class="token punctuation">{</span><span class="token selector">from</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>hidden<span class="token punctuation">}</span><span class="token selector">to</span><span class="token punctuation">{</span><span class="token property">visibility</span><span class="token punctuation">:</span>visible<span class="token punctuation">}</span><span class="token punctuation">}</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span></span><span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>noscript</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name">amp-boilerplate</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><span class="token selector">body</span><span class="token punctuation">{</span><span class="token property">-webkit-animation</span><span class="token punctuation">:</span>none<span class="token punctuation">;</span><span class="token property">-moz-animation</span><span class="token punctuation">:</span>none<span class="token punctuation">;</span><span class="token property">-ms-animation</span><span class="token punctuation">:</span>none<span class="token punctuation">;</span><span class="token property">animation</span><span class="token punctuation">:</span>none<span class="token punctuation">}</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>noscript</span><span class="token punctuation">></span></span></span>
<span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">async</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.ampproject.org/v0.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span></span>
<span class="token punctuation">}</span></span></span></code></pre>
<h3>Inline CSS</h3>
<p>AMP Pages must have inlined CSS. To accomplish this I wrote this tag helper which loads a comma separated list of files into memory and then inlines them. The <code><link></code> tag your CSS needs to be in has to have the <code>amp-custom</code> attribute.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HtmlTargetElement</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"inline-style"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">InlineStyleTagHelper</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">TagHelper</span></span>
<span class="token punctuation">{</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HtmlAttributeName</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"href"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> Href <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token return-type class-name">IWebHostEnvironment</span> HostingEnvironment <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token return-type class-name">IMemoryCache</span> Cache <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token function">InlineStyleTagHelper</span><span class="token punctuation">(</span><span class="token class-name">IWebHostEnvironment</span> hostingEnvironment<span class="token punctuation">,</span> <span class="token class-name">IMemoryCache</span> cache<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
HostingEnvironment <span class="token operator">=</span> hostingEnvironment<span class="token punctuation">;</span>
Cache <span class="token operator">=</span> cache<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token keyword">async</span> <span class="token return-type class-name">Task</span> <span class="token function">ProcessAsync</span><span class="token punctuation">(</span><span class="token class-name">TagHelperContext</span> context<span class="token punctuation">,</span> <span class="token class-name">TagHelperOutput</span> output<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> paths <span class="token operator">=</span> Href<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token char">','</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Get the value from the cache, or compute the value and add it to the cache</span>
<span class="token class-name"><span class="token keyword">var</span></span> fileContent <span class="token operator">=</span> <span class="token keyword">await</span> Cache<span class="token punctuation">.</span><span class="token function">GetOrCreateAsync</span><span class="token punctuation">(</span><span class="token string">"InlineStyleTagHelper-"</span> <span class="token operator">+</span> paths<span class="token punctuation">,</span> <span class="token keyword">async</span> entry <span class="token operator">=></span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> fileProvider <span class="token operator">=</span> HostingEnvironment<span class="token punctuation">.</span>WebRootFileProvider<span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> result <span class="token operator">=</span> paths<span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span><span class="token keyword">async</span> path <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>HostingEnvironment<span class="token punctuation">.</span><span class="token function">IsDevelopment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> changeToken <span class="token operator">=</span> fileProvider<span class="token punctuation">.</span><span class="token function">Watch</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span>
entry<span class="token punctuation">.</span><span class="token function">AddExpirationToken</span><span class="token punctuation">(</span>changeToken<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
entry<span class="token punctuation">.</span><span class="token function">SetPriority</span><span class="token punctuation">(</span>CacheItemPriority<span class="token punctuation">.</span>NeverRemove<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> file <span class="token operator">=</span> fileProvider<span class="token punctuation">.</span><span class="token function">GetFileInfo</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>file <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token operator">!</span>file<span class="token punctuation">.</span>Exists<span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">await</span> <span class="token function">ReadFileContent</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> allFinished <span class="token operator">=</span> <span class="token keyword">await</span> Task<span class="token punctuation">.</span><span class="token function">WhenAll</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">Join</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">,</span> allFinished<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>fileContent <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
output<span class="token punctuation">.</span><span class="token function">SuppressOutput</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
output<span class="token punctuation">.</span>TagName <span class="token operator">=</span> <span class="token string">"style"</span><span class="token punctuation">;</span>
output<span class="token punctuation">.</span>Attributes<span class="token punctuation">.</span><span class="token function">RemoveAll</span><span class="token punctuation">(</span><span class="token string">"href"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
output<span class="token punctuation">.</span>Content<span class="token punctuation">.</span><span class="token function">AppendHtml</span><span class="token punctuation">(</span>fileContent<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">async</span> <span class="token return-type class-name">Task<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">></span></span> <span class="token function">ReadFileContent</span><span class="token punctuation">(</span><span class="token class-name">IFileInfo</span> file<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">using</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> stream <span class="token operator">=</span> file<span class="token punctuation">.</span><span class="token function">CreateReadStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">using</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> textReader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">StreamReader</span><span class="token punctuation">(</span>stream<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">await</span> textReader<span class="token punctuation">.</span><span class="token function">ReadToEndAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<pre class="language-cshtml" tabindex="0"><code class="language-cshtml"><span class="token block"><span class="token keyword">@if</span><span class="token csharp language-csharp"><span class="token punctuation">(</span>amp<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>inline-style</span> <span class="token attr-name">amp-custom</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>css/site.css,css/site.desktop.css,css/site.mobile.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><span class="token operator"><</span><span class="token operator">/</span>inline<span class="token operator">-</span>style<span class="token operator">></span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
<span class="token punctuation">{</span>
<span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">asp-append-version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>~/css/site.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></span>
<span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">asp-append-version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>~/css/site.mobile.css<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></span>
<span class="token punctuation">}</span></span></span></code></pre>
<h3>Javascript</h3>
<p>AMP, <a href="https://amp.dev/documentation/components/amp-script/">does allow for using JS</a> in a web worker. This has a lot of caveats, and for my use-case (this blog) it was better to just skip rendering any JS. I guarded the <code>RenderSection</code> call for the scripts section behind an <code>if(amp)</code> statement.</p>
<pre class="language-cshtml" tabindex="0"><code class="language-cshtml"><span class="token block"><span class="token keyword">@if</span><span class="token csharp language-csharp"><span class="token punctuation">(</span><span class="token operator">!</span>amp<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
@<span class="token function">RenderSection</span><span class="token punctuation">(</span><span class="token string">"Scripts"</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">required</span><span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">asp-append-version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>~/your/script.js<span class="token punctuation">"</span></span> <span class="token attr-name">async</span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span></span>
<span class="token punctuation">}</span></span></span></code></pre>
<h3>Link tags</h3>
<p>On pages that render AMP, you'll need to be able to generate 2 meta tags. The first is a canonical tag that tells google what the canonical URL is of the page. The second is one, to tell google where your amp pages are for a URL. This is data you typically want to pass to the Model of the view you are rendering. Adding these meta to the head of the layout through a section.</p>
<pre class="language-cs" tabindex="0"><code class="language-cs"><span class="token return-type class-name">@section</span> Head <span class="token punctuation">{</span>
<span class="token operator"><</span><span class="token class-name">link</span> rel<span class="token operator">=</span><span class="token string">"canonical"</span> href<span class="token operator">=</span><span class="token string">"@Model.Post.CanonicalUrl"</span> <span class="token operator">/</span><span class="token operator">></span>
<span class="token operator"><</span><span class="token class-name">link</span> rel<span class="token operator">=</span><span class="token string">"amphtml"</span> href<span class="token operator">=</span><span class="token string">"@Model.Post.AMPUrl"</span><span class="token operator">></span>
<span class="token punctuation">}</span></code></pre>
<h2>Routes</h2>
<p>In my implementation I added <code>/amp</code> to the end of my URLs for amp. Then in the controller you can set <code>this.ViewData["amp"] = amp == "amp";</code> the view data for the page to be an amp page or not. If you would prefer, you can set the boolean with a view model, it would also work very well.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Route</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"{postUrl}/{amp?}"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token return-type class-name">IActionResult</span> <span class="token function">Post</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span></span> postUrl<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">string</span></span> amp <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>String<span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>amp<span class="token punctuation">)</span> <span class="token operator">&&</span> amp <span class="token operator">!=</span> <span class="token string">"amp"</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">// handle 404s</span>
<span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
ViewDictionary<span class="token punctuation">[</span><span class="token string">"amp"</span><span class="token punctuation">]</span> <span class="token operator">=</span> amp <span class="token operator">==</span> <span class="token string">"amp"</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">View</span><span class="token punctuation">(</span><span class="token named-parameter punctuation">model</span><span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ViewModel</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2>Google Analytics</h2>
<p>There is a snippet of code makes GA work in an AMP page. I made the following partial view that I call from the layout page.</p>
<pre class="language-cshtml" tabindex="0"><code class="language-cshtml"><span class="token block"><span class="token keyword">@</span><span class="token csharp language-csharp"><span class="token punctuation">{</span>
Layout <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> amp <span class="token operator">=</span> ViewData<span class="token punctuation">[</span><span class="token string">"amp"</span><span class="token punctuation">]</span> <span class="token keyword">as</span> <span class="token class-name"><span class="token keyword">bool</span><span class="token punctuation">?</span></span> <span class="token operator">??</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></span></span>
<span class="token block"><span class="token keyword">@if</span><span class="token csharp language-csharp"><span class="token punctuation">(</span><span class="token operator">!</span>amp<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
window<span class="token punctuation">.</span>dataLayer <span class="token operator">=</span> window<span class="token punctuation">.</span>dataLayer <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">gtag</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> dataLayer<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>arguments<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token function">gtag</span><span class="token punctuation">(</span><span class="token string">'js'</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">gtag</span><span class="token punctuation">(</span><span class="token string">'config'</span><span class="token punctuation">,</span> <span class="token string">'GTAG_ID'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'DOMContentLoaded'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> script <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'script'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
script<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'https://www.googletagmanager.com/gtag/js?id=GTAG_ID'</span><span class="token punctuation">;</span>
script<span class="token punctuation">.</span>async <span class="token operator">=</span> <span class="token boolean">true</span>
document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>script<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span></span>
<span class="token punctuation">}</span></span></span>
else
{
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>amp-analytics</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>gtag<span class="token punctuation">"</span></span> <span class="token attr-name">data-credentials</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>include<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>application/json<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
<span class="token punctuation">{</span>
<span class="token string-property property">"vars"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token string-property property">"gtag_id"</span><span class="token operator">:</span> <span class="token string">"GTAG_ID"</span><span class="token punctuation">,</span>
<span class="token string-property property">"config"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token string-property property">"GTAG_ID"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"GTAG_ID"</span><span class="token operator">:</span> <span class="token string">"default"</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>amp-analytics</span><span class="token punctuation">></span></span>
}
</code></pre>
<h2>So what's next?</h2>
<p>Go through your pages and look at the violations in the Chrome Extension. If you push the pages live, and register them in your sitemap. Errors with amp pages will appear in <a href="https://search.google.com/search-console/about">the Google Search Console.</a> as google indexes your AMP pages.</p>
<h2>I need more help!</h2>
<p>You can look at <a href="https://github.com/TerribleDev/blog.terrible.dev/commit/83eb1bc565dfb4bdb38d3c5f0cbfbc21b05ad4b2">my implementation</a>.</p>
How to host a javascript monorepo on Heroku2022-03-01T15:35:00Zhttps://blog.terrible.dev/blog/How-to-host-a-javascript-monorepo-on-heroku/<p>So I've been using monorepos for some time, and recently I've gotten a lot of questions about how to host them on Heroku. I figured I'd give you the simple guide. There are two basic scenarios. The root of your git repo has your yarn/npm workspace, or you have a folder inside of a gitrepo you wish to use.</p>
<!-- more -->
<h2>Scenario 1: yarn/npm workspace</h2>
<p>In this case, create a Heroku app with the official nodejs buildpack. Add <code>heroku-postbuild: "YourBuildCommand"</code> to your scripts section of the root package.json. This will run after the npm install, and can be used to run any build commands you need (such as compiling typescript). Then use <a href="https://github.com/heroku/heroku-buildpack-multi-procfile">the multi-procfile buildpack</a> which will grab a procfile from any directory and copy it to the root to boot your app. That way your monorepo can have a <code>server/package.json</code> package that contains your web app and in there you can have the procfile <code>server/Procfile</code>.</p>
<p>Your buildpacks should have this order:</p>
<pre><code>heroku/nodejs
heroku-buildpack-multi-procfile
</code></pre>
<p>The multi-procfile requires an Environment variable called <code>PROCFILE</code> which has the path to the procfile to use. For example it can be <code>/server/Procfile</code>. Usually my procfile contains a workspace command to start the server.</p>
<pre><code>web: yarn workspace server run start
</code></pre>
<h2>Scenario 2: Folder inside of Git Repo</h2>
<p>So this is a strategy where you make a heroku app in a nested directory. Not using a yarn workspace. In this case you can use the <a href="https://github.com/lstoll/heroku-buildpack-monorepo">monorepo buildpack</a> to copy a subdirectory to the root directory before the build happens. After that buildpack include the <code>heroku/nodejs</code> buildpack which will run the npm/yarn/etc. install commands and then use the <code>Procfile</code> in that directory to start your app.</p>
Hosting Craft CMS on Heroku2022-02-24T12:19:00Zhttps://blog.terrible.dev/blog/Hosting-craft-on-heroku/<p>So, like most early startups, <a href="https://www.quala.io">Quala</a> (where I currently work) bought into a Wordpress site to sell our product, probably before it really existed. Flash forward, we have customers, and we're on a path to building a platform to change the game on customer management. The Wordpress site was terrible for performance, and <a href="https://web.dev/vitals/">core web vitals</a>. None of us know Wordpress, and barely know any php. We had huge drive to rebrand ourselves, but to do that we needed to edit the Wordpress theme 😬 or use something else.</p>
<!-- more -->
<p><em>tl;dr you can use this sweet <a href="https://github.com/oof-bar/craft-heroku">deploy to heroku button</a> that <a href="https://oof.studio/">oof.studio</a> made. Most of this post is inspired by their implementation</em></p>
<h2>Why Craft?</h2>
<p>I was introduced to <a href="https://craftcms.com/">CraftCMS</a> 2 years ago. Back then my first instinct was <em>eww php</em>, might also still be my primary reaction 🤣. At that time, and still today, I love the headless CMS (<a href="https://www.contentful.com/">Contentful</a>, <a href="https://www.sanity.io/">Sanity</a>) + <a href="https://www.gatsbyjs.com/">Gatsby</a> strategy. However, we are a startup. For us, every dollar counts. The license for Craft is $300/year. Most of the other GraphQL CMS' we looked at were more expensive. We have a developer that's used craft, and I know some other <a href="https://www.johnlamb.me/">big brain craft people</a>.</p>
<h2>Craft + Heroku</h2>
<p>So, Heroku is a Platform to host webapps. They have good postgres support, and we've used them in the past. Apps on Heroku need to be <a href="https://12factor.net/">12 factor apps</a>. Heroku has an ephemeral file system, scales horizontally, and logs stdout/stderr streams.</p>
<p>Craft is based on the yii php framework. You'll need to use the official <code>php</code> buildpack for craft to work, and any libraries for yii will work with Craft. When we started looking into this, I found a <a href="https://github.com/oof-bar/craft-heroku">deploy to heroku button</a> that <a href="https://oof.studio/">oof.studio</a> built. We had to fork this, and update it. However, since then they've updated it (almost exactly how we did), so you may want to use their deploy button to get started. I didn't have much experience with craft, so much of this writing you can attribute to me reverse engineering their configs and updating it to the newest version of craft.</p>
<h2>Configuring Craft</h2>
<p>Craft configurations sit in an <code>app.php</code> file. This file will need to add redis for sessions, and cache (the cache for the cache tags). Also, using <a href="https://github.com/codemix/yii2-streamlog">codemix's logstream</a>, piping the stream to stdout.</p>
<pre class="language-php" tabindex="0"><code class="language-php"> <span class="token string single-quoted-string">'production'</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'redis'</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">yii<span class="token punctuation">\</span>redis<span class="token punctuation">\</span>Connection</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'hostname'</span> <span class="token operator">=></span> <span class="token function">parse_url</span><span class="token punctuation">(</span><span class="token class-name static-context">App</span><span class="token operator">::</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_URL'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token constant">PHP_URL_HOST</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'port'</span> <span class="token operator">=></span> <span class="token function">parse_url</span><span class="token punctuation">(</span><span class="token class-name static-context">App</span><span class="token operator">::</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_URL'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token constant">PHP_URL_PORT</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'password'</span> <span class="token operator">=></span> <span class="token function">parse_url</span><span class="token punctuation">(</span><span class="token class-name static-context">App</span><span class="token operator">::</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'REDIS_URL'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token constant">PHP_URL_PASS</span><span class="token punctuation">)</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'session'</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">yii<span class="token punctuation">\</span>redis<span class="token punctuation">\</span>Session</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'as session'</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>craft<span class="token punctuation">\</span>behaviors<span class="token punctuation">\</span>SessionBehavior</span><span class="token operator">::</span><span class="token keyword">class</span>
<span class="token punctuation">]</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'cache'</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">yii<span class="token punctuation">\</span>redis<span class="token punctuation">\</span>Cache</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'defaultDuration'</span> <span class="token operator">=></span> <span class="token number">86400</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'log'</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'targets'</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
<span class="token punctuation">[</span>
<span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">codemix<span class="token punctuation">\</span>streamlog<span class="token punctuation">\</span>Target</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'url'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'php://stderr'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'levels'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'warning'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'logVars'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">]</span>
<span class="token punctuation">]</span>
<span class="token punctuation">]</span>
<span class="token punctuation">]</span>
<span class="token punctuation">]</span></code></pre>
<p>There is also a file to set the db configuration in <code>db.php</code>. That must have the following, which will use heroku's <code>DATABASE_URL</code> environment variable in prod, and <a href="https://craftcms.com/docs/nitro/2.x/">nitro's</a> set of environment variables locally. You'll need a <code>bootstrap.php</code> file to setup the environment properly (including license keys).</p>
<pre class="language-php" tabindex="0"><code class="language-php">
<span class="token php language-php"><span class="token delimiter important"><?php</span>
<span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'CRAFT_BASE_PATH'</span><span class="token punctuation">,</span> <span class="token constant">__DIR__</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'CRAFT_VENDOR_PATH'</span><span class="token punctuation">,</span> <span class="token constant">CRAFT_BASE_PATH</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/vendor'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">require_once</span> <span class="token constant">CRAFT_VENDOR_PATH</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/autoload.php'</span><span class="token punctuation">;</span>
<span class="token comment">// Load dotenv?</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">class_exists</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Dotenv\Dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name class-name-fully-qualified static-context">Dotenv<span class="token punctuation">\</span>Dotenv</span><span class="token operator">::</span><span class="token function">createUnsafeImmutable</span><span class="token punctuation">(</span><span class="token constant">CRAFT_BASE_PATH</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">safeLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'CRAFT_ENVIRONMENT'</span><span class="token punctuation">,</span> <span class="token function">getenv</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'ENVIRONMENT'</span><span class="token punctuation">)</span> <span class="token operator">?</span><span class="token punctuation">:</span> <span class="token string single-quoted-string">'production'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'CRAFT_LICENSE_KEY'</span><span class="token punctuation">,</span> <span class="token function">getenv</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'CRAFT_LICENSE_KEY'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'CRAFT_STORAGE_PATH'</span><span class="token punctuation">,</span> <span class="token function">getenv</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'CRAFT_STORAGE_PATH'</span><span class="token punctuation">)</span> <span class="token operator">?</span><span class="token punctuation">:</span> <span class="token string single-quoted-string">'../storage'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'CRAFT_STREAM_LOG'</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></code></pre>
<h2>S3</h2>
<p>In our case, the button didn't provide any support for uploaded files. We went for S3. I added the Craft s3 plugin, and configured it to read the apikeys, and bucket names from environment variables. Then I registered those variables in the environment variables in heroku.</p>
<h2>Other important files</h2>
<p>Heroku requires a Procfile to launch apps.</p>
<pre class="language-shell" tabindex="0"><code class="language-shell">web: vendor/bin/heroku-php-nginx <span class="token parameter variable">-C</span> nginx_app.conf web
worker: ./craft queue/listen <span class="token parameter variable">--verbose</span>
release: ./bin/release.sh</code></pre>
<p><code>release.sh</code> will run a db migration</p>
<pre class="language-shell" tabindex="0"><code class="language-shell"><span class="token keyword">if</span> /usr/bin/env php /app/craft install/check
<span class="token keyword">then</span>
/usr/bin/env php /app/craft up <span class="token parameter variable">--interactive</span><span class="token operator">=</span><span class="token number">0</span>
<span class="token keyword">fi</span></code></pre>
<p>A <code>nginx_app.conf</code> nginx config for heroku's php buildpack.</p>
<pre class="language-nginx" tabindex="0"><code class="language-nginx"><span class="token directive"><span class="token keyword">if</span> (<span class="token variable">$http_x_forwarded_proto</span> != <span class="token string">"https"</span>)</span> <span class="token punctuation">{</span>
<span class="token directive"><span class="token keyword">return</span> <span class="token number">301</span> https://<span class="token variable">$host</span><span class="token variable">$request_uri</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token directive"><span class="token keyword">if</span> (<span class="token variable">$host</span> ~ ^www\.(.+))</span> <span class="token punctuation">{</span>
<span class="token directive"><span class="token keyword">return</span> <span class="token number">301</span> https://<span class="token variable">$1</span><span class="token variable">$request_uri</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">{</span>
<span class="token comment"># try to serve file directly, fallback to rewrite</span>
<span class="token directive"><span class="token keyword">try_files</span> <span class="token variable">$uri</span> @rewriteapp</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token directive"><span class="token keyword">location</span> @rewriteapp</span> <span class="token punctuation">{</span>
<span class="token comment"># rewrite all to index.php</span>
<span class="token directive"><span class="token keyword">rewrite</span> ^(.*)$ /index.php?p=<span class="token variable">$1</span> last</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token directive"><span class="token keyword">location</span> ~ ^/(index)\.php(/|$)</span> <span class="token punctuation">{</span>
<span class="token directive"><span class="token keyword">fastcgi_pass</span> heroku-fcgi</span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_split_path_info</span> ^(.+\.php)(/.*)$</span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">include</span> fastcgi_params</span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_param</span> SCRIPT_FILENAME <span class="token variable">$document_root</span><span class="token variable">$fastcgi_script_name</span></span><span class="token punctuation">;</span>
<span class="token directive"><span class="token keyword">fastcgi_param</span> HTTPS <span class="token boolean">on</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment"># Global Config</span>
<span class="token directive"><span class="token keyword">client_max_body_size</span> <span class="token number">20M</span></span><span class="token punctuation">;</span></code></pre>
<h2>Anything else?</h2>
<p>Nope, not really. You need to be aware that you need to treat craft's configuration as entirely immutable. Any changes to configuration such as plugins, twig templates, etc. Will need to be changed in dev and pushed to Heroku. Nothing can be mutated in production, other than the authoring of the site. Even file uploads!</p>
Building a remote cache server for Turborepo2022-02-12T14:52:00Zhttps://blog.terrible.dev/blog/Building-a-remote-cache-server-for-Turborepo/<p><a href="https://turborepo.org/">Turborepo</a> is a tool that came across my virtual desk recently. Monorepo develoment has been around for a long time. This is a strategy where all of your code remains in one repository regardless of services. A lot of people use monorepo's even for microservices. The huge upside is to keep everything in one place, which allows for development efficiency, such as grepping an entire codebase for specific keywords. A quick example would be a top level directory which has child directories that each contain an npm package, unlike publishing these packages, you access them locally as though they were published.</p>
<!-- more -->
<p>There are many tools in the Javascript ecosystem to manage monorepos. <a href="https://classic.yarnpkg.com/lang/en/docs/cli/workspaces/">Yarn</a>, and <a href="https://docs.npmjs.com/cli/v7/using-npm/workspaces">npm</a> both have their own workspaces. <a href="https://lerna.js.org/">Lerna</a> is a tool that people use to run commands a cross these packages. I've been a huge fan of monorepos for years. One of the big problems with this setup is build times. At <a href="https://www.quala.io">Quala</a> we have around 38 packages, and some of my previous employers have had over 100. When you have these large repos sometimes you can make a change in a single package, but when you run <code>build</code> you have to wait to build the entire repository which can take a long time.</p>
<p><a href="https://turborepo.org/">Turborepo</a>, however caches the build output of packages, so when you change a package it will get cache hits on particular packages, and thus you only build the changes you make. This is not a new idea. Years ago, google built <a href="https://bazel.build/">bazel</a>, A lot of people in C++ land have had remote builds. With Turborepo it seems the only official way to have remote caches is to use Vercel, or host your own server. For many reasons at <a href="https://www.quala.io">Quala</a> I decided to opt for hosting our own server.</p>
<p>So to add turborepo to your monorepo, you need to add some <a href="https://turborepo.org/docs/features/caching">simple config</a> to the root of your workspace, and your root <code>package.json</code> needs to replace its build command with <code>turborepo build</code>. In the case of remote caches you need to add</p>
<p><code>--api="https://yourCacheServer.dev" --token="token" --team="team"</code></p>
<p>Notice, the api flag does not contain a <code>/</code> at the end. Now according to the docs you don't need to pass a team, but I was unable to get the caches to register without it 🤷♀️</p>
<h2>The API</h2>
<p>According to the <a href="https://turborepo.org/docs/features/remote-caching">docs</a></p>
<blockquote>
<p>You can self-host your own Remote Cache or use other remote caching service providers as long as they comply with Turborepo's Remote Caching Server API. I opted to write the server in go, and <a href="https://github.com/gofiber/fiber">I used Go Fiber</a>. At first I figured I could copy their structs to my project but honestly the API is so simple, there is no advantage to this.</p>
</blockquote>
<p>To get a list of the API's you need, you are linked to some <a href="https://github.com/vercel/turborepo/blob/main/cli/internal/client/client.go">code written in Go</a>. I reverse engineered this code a bit, and came up with 4 APIs, and an AUTH token</p>
<pre><code>Authorization: Bearer ${token}
PUT: /v8/artifacts/:hash
GET: /v8/artifacts/:hash
GET: /v2/user
GET: /v2/teams
</code></pre>
<h3>Authorization</h3>
<p>When turborepo sends requests it appends the <code>Authorization</code> header which will contain our token. Ideally you would add to your server a way to auth a user and give them this token. In the below example we have a single token that comes from an environment variable. You really should have per user auth.</p>
<pre class="language-go" tabindex="0"><code class="language-go"> app<span class="token punctuation">.</span><span class="token function">Use</span><span class="token punctuation">(</span><span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>fiber<span class="token punctuation">.</span>Ctx<span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
authHeader <span class="token operator">:=</span> c<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">"Authorization"</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> authHeader <span class="token operator">!=</span> <span class="token string">"Bearer "</span><span class="token operator">+</span>token <span class="token punctuation">{</span>
c<span class="token punctuation">.</span><span class="token function">Status</span><span class="token punctuation">(</span><span class="token number">401</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">SendString</span><span class="token punctuation">(</span><span class="token string">"Unauthorized"</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> c<span class="token punctuation">.</span><span class="token function">Next</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<h3>Handling Requests</h3>
<p>The API pretty much breaks down like this.</p>
<p><code>PUT: /v8/artifacts/:hash</code> will send a file that you must write somewhere. Some people opt for sending it to S3, I decided to use a persistent disk, and save on the disk. I wanted the fastest responses for the caches. Heck if I'm going to remote cache something that would still be kinda quick on an M1, it better perform.</p>
<pre class="language-go" tabindex="0"><code class="language-go"> app<span class="token punctuation">.</span><span class="token function">Put</span><span class="token punctuation">(</span><span class="token string">"/v8/artifacts/:hash"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>fiber<span class="token punctuation">.</span>Ctx<span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token function">string</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span><span class="token function">Request</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">URI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">QueryString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> os<span class="token punctuation">.</span><span class="token function">WriteFile</span><span class="token punctuation">(</span><span class="token string">"./cache/"</span><span class="token operator">+</span>c<span class="token punctuation">.</span><span class="token function">Params</span><span class="token punctuation">(</span><span class="token string">"hash"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> c<span class="token punctuation">.</span><span class="token function">Request</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Body</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0644</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>The same URL but on a get is simple. Retrieve a file and serve it up, or return a 404</p>
<pre class="language-go" tabindex="0"><code class="language-go"> app<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">"/v8/artifacts/:hash"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>fiber<span class="token punctuation">.</span>Ctx<span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token function">string</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span><span class="token function">Request</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">URI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">QueryString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> c<span class="token punctuation">.</span><span class="token function">SendFile</span><span class="token punctuation">(</span><span class="token string">"./cache/"</span> <span class="token operator">+</span> c<span class="token punctuation">.</span><span class="token function">Params</span><span class="token punctuation">(</span><span class="token string">"hash"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>The last two honesty you don't need to make things work. You can just return a 200</p>
<pre class="language-go" tabindex="0"><code class="language-go"> app<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">"/v2/teams"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>fiber<span class="token punctuation">.</span>Ctx<span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> c<span class="token punctuation">.</span><span class="token function">SendStatus</span><span class="token punctuation">(</span>fiber<span class="token punctuation">.</span>StatusOK<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
app<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">"/v2/user"</span><span class="token punctuation">,</span> <span class="token keyword">func</span><span class="token punctuation">(</span>c <span class="token operator">*</span>fiber<span class="token punctuation">.</span>Ctx<span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> c<span class="token punctuation">.</span><span class="token function">SendStatus</span><span class="token punctuation">(</span>fiber<span class="token punctuation">.</span>StatusOK<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>The <code>/v2/user</code> API is supposed to return information about the current user in the following shape. I'm pretty sure (not positive) created at is an <a href="https://en.wikipedia.org/wiki/Unix_time">epoch</a> of the time the user was created. I'm guessing its largely used for Vercel.</p>
<pre><code>{
ID string
Username string
Email string
Name string
CreatedAt int
}
</code></pre>
<p>The team api is supposed to look something like the following.</p>
<pre><code>{
Pagination {
Count: int,
Next: int,
Prev: int
}
Teams [
Team {
ID: string,
Slug: string,
Name: string,
CreatedAt: int,
Created: string
}
]
}
</code></pre>
<blockquote>
<p>What about the --team flag?</p>
</blockquote>
<p>So when requests are made with <code>--team</code> a query string <code>?slug=team</code> is added to the request. You can use this to ensure a particular user is in the given team, and you can fragment your caches by team. I ommitted that code from the above example, but the easiest way would be to have <code>./cache/${team}/${hash}</code> directory structure for the caches on disk. Note, on the GET requests you should auth the token against the team ID, and return a 404 if the user is not in the team. <strong>I would not opt to return a Unauthorized header</strong>, as that can be used by bad actors to cycle through tokens to know which one will work to cause harm.</p>
<h2>The Result</h2>
<p>An extremely minimal server <a href="https://github.com/TerribleDev/turbogo">is in this github repo</a> (although you shouldn't probably use it without building it out more).</p>
Optimizing heroku's node_module cache for JS monorepos2021-10-12T04:00:00Zhttps://blog.terrible.dev/blog/Optimizing-Heroku-Cache-For-JS-Monorepos/<p>For many of us a JS workspace is the simplest way to structure code for future growth while providing very quick iterations. Incase you are unfamiliar, several technologies exist such as <code>yarn workspaces</code>, <code>lerna</code>, <code>npm workspaces</code>, etc. That can seamlessly stitch npm packages on disk as though they were published to a private NPM registry. This allows for fast iteration inside of a single git repo, while allowing a future where these dependencies could be abstracted.</p>
<!-- more -->
<p>The file system looks something like the following</p>
<pre><code>root/
packages/
server
workers
data
utils
</code></pre>
<p>In my quick example we can pretend that an express app in in server, and some background workers are in workers. However both apps need to share code. One strategy would be to version the <code>data</code>, and <code>utils</code>, packages and ship them to a private NPM registry, or we could use these mono-repo technologies so that <code>import utils from 'utils'</code> just works without the need for a remote package store. When installing node modules into a JS workspace the following can occur</p>
<pre><code>root/
node_modules
packages/
server/node_modules
data
utils
worker/node_modules
</code></pre>
<p>In the above scenario node modules are both resolved into the root package but also several layers deep. In heroku you can cache your <code>node_modules</code> to improve build speed. However the paths to these directories <strong>must be declared prior to the build</strong>. This becomes an issue when big mono-repos litter <code>node_modules</code> everywhere.</p>
<p>I decided to write the following JS script to walk over the directories where <code>node_modules</code> could be placed and rewrite the root <code>package.json</code> file so those directories are explicitly declared.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">const</span> glob <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'glob'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// do not run this in the heroku build</span>
<span class="token comment">// we treat this a bit more like a yarn lockfile</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NODE_ENV</span> <span class="token operator">!==</span> <span class="token string">'production'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">glob</span><span class="token punctuation">(</span><span class="token string">"./packages/*/node_modules"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">er<span class="token punctuation">,</span> result</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> packageJson <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./package.json'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// include the root node_modules</span>
<span class="token keyword">let</span> cacheDirectories <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'node_modules'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
cacheDirectories <span class="token operator">=</span> cacheDirectories<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span>
packageJson<span class="token punctuation">.</span>cacheDirectories <span class="token operator">=</span> cacheDirectories<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">i</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token comment">// ensure the directory node_modules are found contain a package.json file</span>
<span class="token keyword">return</span> fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token string">'../package.json'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// write out the changes to the root packaage.json</span>
fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span><span class="token string">'./package.json'</span><span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>packageJson<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<p>I wired up the script on the post install process of the install lifecycle. Basically adding the following to the root <code>package.json</code> file.</p>
<pre class="language-json" tabindex="0"><code class="language-json"><span class="token punctuation">{</span>
<span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"postinstall"</span><span class="token operator">:</span> <span class="token string">"node ./computeCacheDirectories.js"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Now every time a developer runs <code>yarn install</code> they will compute the cache directories. The result is a mutation to the <code>package.json</code> that looks like the following.</p>
<pre class="language-json" tabindex="0"><code class="language-json"><span class="token punctuation">{</span>
<span class="token property">"cacheDirectories"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">"node_modules"</span><span class="token punctuation">,</span>
<span class="token string">"./packages/server/node_modules"</span><span class="token punctuation">,</span>
<span class="token string">"./packages/worker/node_modules"</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p>When we push changes to prod we get much better cache hits across our yarn workspace.</p>
Hosting dotnet core on Heroku2021-07-19T04:01:00Zhttps://blog.terrible.dev/blog/Hosting-dotnet-core-on-heroku/<p>I've been getting back into building scrappy little web apps for my friends. On top of this, I recently joined <a href="https://quala.io">a startup</a> and getting away from Enterprise class software has made me make a huge mind-shift. In the recent past when I wanted to build apps I was thinking Kubernetes, Helm Charts, etc. However, in small app, and startup land reducing the barriers to ship is very important.</p>
<!-- more -->
<p>Incase you are not familiar <a href="https://www.heroku.com">Heroku</a> is a platform to host webapps. They host a free version of Postgres DB, and Redis that is directly connected to your app with environment variables. Heroku has support for many languages, but one I saw missing from the list was dotnet.</p>
<p>To host apps on Heroku, you must know the basic <em>rules of Heroku</em></p>
<ol>
<li>Your app must listen on <code>$PORT</code> or <code>%PORT%</code> if you come from windows. Basically, any http listeners must listen to the port defined as an environment variable.</li>
<li>Postgres is free (to a point), redis is free, most other things cost money.</li>
<li>Logs must go to <code>stdout</code> which works well for us since that's the default behavior of asp.net core!</li>
<li>In dotnet core authentication cookies are encrypted and the key is usually placed in your home directory, but in Heroku your app could be moved to any machine at any moment. The filesystem needs to be stateless</li>
<li>Heroku gives you your Postgres connection string as <code>postgres://<username>:<password>@<host>:<port>/<database></code></li>
</ol>
<h2>Listening on $PORT</h2>
<p>Traditionally dotnet core apps listen for an environment variable called <code>ASPNETCORE_URLS</code> but in this case we need to override this behavior. In your <code>Program.cs</code> file you can make the following modification, which detects if <code>$PORT</code> is defined, and if it is to listen to all requests on that port.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">IHostBuilder</span> <span class="token function">CreateHostBuilder</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> args<span class="token punctuation">)</span> <span class="token operator">=></span>
Host<span class="token punctuation">.</span><span class="token function">CreateDefaultBuilder</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">ConfigureWebHostDefaults</span><span class="token punctuation">(</span>webBuilder <span class="token operator">=></span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> port <span class="token operator">=</span> Environment<span class="token punctuation">.</span><span class="token function">GetEnvironmentVariable</span><span class="token punctuation">(</span><span class="token string">"PORT"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>port<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
webBuilder<span class="token punctuation">.</span><span class="token function">UseUrls</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"http://*:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">port</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
webBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">UseStartup</span><span class="token generic class-name"><span class="token punctuation"><</span>Startup<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Using Postgres with Entity Framework</h2>
<p>On a <code>dotnet new mvc --auth individual</code> you are presented with the following block of code in <code>Startup.cs</code></p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddDbContext</span><span class="token generic class-name"><span class="token punctuation"><</span>ApplicationDbContext<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>options <span class="token operator">=></span>
options<span class="token punctuation">.</span><span class="token function">UseSqlite</span><span class="token punctuation">(</span>
Configuration<span class="token punctuation">.</span><span class="token function">GetConnectionString</span><span class="token punctuation">(</span><span class="token string">"DefaultConnection"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>This configures your app to use SqlLite as a DB, we need to switch this. Luckily the Postgres team has an awesome integration with entity framework. Run the following command to add their package to your project</p>
<p><code>dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL</code></p>
<p>Then simply swap the previous code block for the following, which will parse the database url from Heroku and setup a Postgres connection. You can use the following docker-compose file and <code>appsettings.Development.json</code> for local development.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token class-name"><span class="token keyword">var</span></span> databaseUrl <span class="token operator">=</span> Configuration<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetValue</span><span class="token generic class-name"><span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token string">"DATABASE_URL"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> databaseUri <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Uri</span><span class="token punctuation">(</span>databaseUrl<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> userInfo <span class="token operator">=</span> databaseUri<span class="token punctuation">.</span>UserInfo<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token char">':'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> builder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NpgsqlConnectionStringBuilder</span>
<span class="token punctuation">{</span>
Host <span class="token operator">=</span> databaseUri<span class="token punctuation">.</span>Host<span class="token punctuation">,</span>
Port <span class="token operator">=</span> databaseUri<span class="token punctuation">.</span>Port<span class="token punctuation">,</span>
Username <span class="token operator">=</span> userInfo<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
Password <span class="token operator">=</span> userInfo<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
Database <span class="token operator">=</span> databaseUri<span class="token punctuation">.</span>LocalPath<span class="token punctuation">.</span><span class="token function">TrimStart</span><span class="token punctuation">(</span><span class="token char">'/'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
TrustServerCertificate <span class="token operator">=</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddDbContext</span><span class="token generic class-name"><span class="token punctuation"><</span>ApplicationDbContext<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>options <span class="token operator">=></span>
options<span class="token punctuation">.</span><span class="token function">UseNpgsql</span><span class="token punctuation">(</span>builder<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><em>docker-compose.yml</em></p>
<pre class="language-yml" tabindex="0"><code class="language-yml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
<span class="token key atrule">postgres</span><span class="token punctuation">:</span>
<span class="token key atrule">image</span><span class="token punctuation">:</span> <span class="token string">'postgres:13'</span>
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token string">'6666:5432'</span>
<span class="token key atrule">environment</span><span class="token punctuation">:</span>
<span class="token key atrule">POSTGRES_PASSWORD</span><span class="token punctuation">:</span> <span class="token string">'password'</span>
<span class="token key atrule">POSTGRES_USER</span><span class="token punctuation">:</span> <span class="token string">'admin'</span></code></pre>
<p><em>appsettings.Development.json</em></p>
<pre class="language-json" tabindex="0"><code class="language-json"><span class="token punctuation">{</span>
<span class="token property">"DATABASE_URL"</span><span class="token operator">:</span> <span class="token string">"postgres://admin:password@localhost:6666/main"</span>
<span class="token punctuation">}</span></code></pre>
<h2>Encryption keys</h2>
<p>Ok so you've got the basics running, but you need to store your encryption keys. We can store them in the database using entity framework! Add this to your <code>startup.cs</code> <code>ConfigureServices</code> Method. Make sure you <code>dotnet add package Microsoft.AspNetCore.DataProtection.EntityFrameworkCore</code>. You'll also need to make sure your dbContext implements <code>IDataProtectionKeyContext</code></p>
<pre class="language-cs" tabindex="0"><code class="language-cs">
services<span class="token punctuation">.</span><span class="token function">AddDataProtection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token generic-method"><span class="token function">PersistKeysToDbContext</span><span class="token generic class-name"><span class="token punctuation"><</span>ApplicationDbContext<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h2>Database Migrations</h2>
<p>There are several ways to handle database migrations. For simple webapps you can configure your app to do a migration on startup. More complex apps should shell into the <code>ef</code> command line using <a href="https://devcenter.heroku.com/articles/release-phase">Heroku's procfile</a></p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Configure</span><span class="token punctuation">(</span><span class="token class-name">IApplicationBuilder</span> app<span class="token punctuation">,</span> <span class="token class-name">IWebHostEnvironment</span> env<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">using</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> scope <span class="token operator">=</span> app<span class="token punctuation">.</span>ApplicationServices<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetRequiredService</span><span class="token generic class-name"><span class="token punctuation"><</span>IServiceScopeFactory<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">CreateScope</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">using</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> ctx <span class="token operator">=</span> scope<span class="token punctuation">.</span>ServiceProvider<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetRequiredService</span><span class="token generic class-name"><span class="token punctuation"><</span>ApplicationDbContext<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ctx<span class="token punctuation">.</span>Database<span class="token punctuation">.</span><span class="token function">EnsureCreated</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ctx<span class="token punctuation">.</span>Database<span class="token punctuation">.</span><span class="token function">Migrate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Forwarded protocol</h2>
<p>Heroku sends an <code>X-Forwarded-Proto</code> header to tell your app what protocol a user is using. You'll want to add this to your <code>Configure</code> block before all other middleware</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> app<span class="token punctuation">.</span><span class="token function">UseForwardedHeaders</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">ForwardedHeadersOptions</span>
<span class="token punctuation">{</span>
ForwardedHeaders <span class="token operator">=</span> ForwardedHeaders<span class="token punctuation">.</span>XForwardedProto
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Getting your app in Heroku with containers</h2>
<p>There are 2 basic methods to getting your app live in Heroku. One is to push a docker container to Heroku, or use a Heroku buildpack to have Heroku build your app for you. I opted for the docker container.</p>
<p>I stole this sample dockerfile from the aspnet core docker docs.</p>
<pre class="language-dockerfile" tabindex="0"><code class="language-dockerfile"><span class="token instruction"><span class="token keyword">FROM</span> mcr.microsoft.com/dotnet/core/aspnet:3.1 <span class="token keyword">AS</span> base</span>
<span class="token instruction"><span class="token keyword">WORKDIR</span> /app</span>
<span class="token instruction"><span class="token keyword">EXPOSE</span> 80</span>
<span class="token instruction"><span class="token keyword">EXPOSE</span> 443</span>
<span class="token instruction"><span class="token keyword">FROM</span> mcr.microsoft.com/dotnet/core/sdk:3.1 <span class="token keyword">AS</span> build</span>
<span class="token instruction"><span class="token keyword">WORKDIR</span> /src</span>
<span class="token instruction"><span class="token keyword">COPY</span> [<span class="token string">"./MyApp.csproj"</span>, <span class="token string">"."</span>]</span>
<span class="token instruction"><span class="token keyword">RUN</span> dotnet restore <span class="token string">"MyApp.csproj"</span></span>
<span class="token instruction"><span class="token keyword">COPY</span> . .</span>
<span class="token instruction"><span class="token keyword">WORKDIR</span> <span class="token string">"/src"</span></span>
<span class="token instruction"><span class="token keyword">RUN</span> dotnet build <span class="token string">"MyApp.csproj"</span> -c Release -o /app</span>
<span class="token instruction"><span class="token keyword">FROM</span> build <span class="token keyword">AS</span> publish</span>
<span class="token instruction"><span class="token keyword">RUN</span> dotnet publish <span class="token string">"MyApp.csproj"</span> -c Release -o /app</span>
<span class="token instruction"><span class="token keyword">FROM</span> base <span class="token keyword">AS</span> final</span>
<span class="token instruction"><span class="token keyword">WORKDIR</span> /app</span>
<span class="token instruction"><span class="token keyword">COPY</span> <span class="token options"><span class="token property">--from</span><span class="token punctuation">=</span><span class="token string">publish</span></span> /app .</span>
<span class="token instruction"><span class="token keyword">ENTRYPOINT</span> [<span class="token string">"dotnet"</span>, <span class="token string">"MyApp.dll"</span>]</span>
</code></pre>
<p>I then found someone had made a <em>build a docker image and push to Heroku</em> GitHub action. All I had to do is make this a file in <code>.github/deployContainerToHeroku.yml</code>, turn on Github actions, and register my Heroku API key as a secret in GitHub</p>
<pre class="language-yml" tabindex="0"><code class="language-yml"><span class="token key atrule">name</span><span class="token punctuation">:</span> Deploy to Heroku.
<span class="token comment"># Run workflow on every push to master branch.</span>
<span class="token key atrule">on</span><span class="token punctuation">:</span>
<span class="token key atrule">push</span><span class="token punctuation">:</span>
<span class="token key atrule">branches</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>master<span class="token punctuation">]</span>
<span class="token comment"># Your workflows jobs.</span>
<span class="token key atrule">jobs</span><span class="token punctuation">:</span>
<span class="token key atrule">build</span><span class="token punctuation">:</span>
<span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest
<span class="token key atrule">steps</span><span class="token punctuation">:</span>
<span class="token comment"># Check-out your repository.</span>
<span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Checkout
<span class="token key atrule">uses</span><span class="token punctuation">:</span> actions/checkout@v2
<span class="token comment">### ⬇ IMPORTANT PART ⬇ ###</span>
<span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Build<span class="token punctuation">,</span> Push and Release a Docker container to Heroku. <span class="token comment"># Your custom step name</span>
<span class="token key atrule">uses</span><span class="token punctuation">:</span> gonuit/Heroku<span class="token punctuation">-</span>docker<span class="token punctuation">-</span>deploy@v1.3.3 <span class="token comment"># GitHub action name (leave it as it is).</span>
<span class="token key atrule">with</span><span class="token punctuation">:</span>
<span class="token comment"># Below you must provide variables for your Heroku app.</span>
<span class="token comment"># The email address associated with your Heroku account.</span>
<span class="token comment"># If you don't want to use repository secrets (which is recommended) you can do:</span>
<span class="token comment"># email: my.email@example.com</span>
<span class="token key atrule">email</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> secrets.HEROKU_EMAIL <span class="token punctuation">}</span><span class="token punctuation">}</span>
<span class="token comment"># Heroku API key associated with provided user's email.</span>
<span class="token comment"># Api Key is available under your Heroku account settings.</span>
<span class="token key atrule">Heroku_api_key</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> secrets.HEROKU_API_KEY <span class="token punctuation">}</span><span class="token punctuation">}</span>
<span class="token comment"># Name of the Heroku application to which the build is to be sent.</span>
<span class="token key atrule">Heroku_app_name</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span><span class="token punctuation">{</span> secrets.HEROKU_APP_NAME <span class="token punctuation">}</span><span class="token punctuation">}</span>
<span class="token comment"># (Optional, default: "./")</span>
<span class="token comment"># Dockerfile directory.</span>
<span class="token comment"># For example, if you have a Dockerfile in the root of your project, leave it as follows:</span>
<span class="token key atrule">dockerfile_directory</span><span class="token punctuation">:</span> ./src/MyApp
<span class="token comment"># (Optional, default: "Dockerfile")</span>
<span class="token comment"># Dockerfile name.</span>
<span class="token key atrule">dockerfile_name</span><span class="token punctuation">:</span> Dockerfile
<span class="token comment"># (Optional, default: "")</span>
<span class="token comment"># Additional options of docker build command.</span>
<span class="token key atrule">docker_options</span><span class="token punctuation">:</span> <span class="token string">"--no-cache"</span>
<span class="token comment"># (Optional, default: "web")</span>
<span class="token comment"># Select the process type for which you want the docker container to be uploaded.</span>
<span class="token comment"># By default, this argument is set to "web".</span>
<span class="token comment"># For more information look at https://devcenter.Heroku.com/articles/process-model</span>
<span class="token key atrule">process_type</span><span class="token punctuation">:</span> web
</code></pre>
<h2>Getting your app in Heroku with buildpacks</h2>
<p>Heroku has had this system called <em>buildpacks</em> which allow you to script the creation of the hosting environment of your app. Someone has done the dirty work and <a href="https://elements.Heroku.com/buildpacks/jincod/dotnetcore-buildpack">built a dotnet core buildpack</a> which can be used to deploy dotnet core apps to Heroku. To use this, create an app in Heroku, set your <a href="https://elements.Heroku.com/buildpacks/jincod/dotnetcore-buildpack">buildpack to the dotnet core buildpack</a> in settings. Connect your GitHub repo and Heroku will do the hard work for you!</p>
<h2>Finish</h2>
<p>I hope you liked this. Keep on hacking away!</p>
Accessibility Driven Development2020-08-07T09:27:00Zhttps://blog.terrible.dev/blog/Accessibility-Driven-Development/<p>I've been working at <a href="https://www.cargurus.com">CarGurus.com</a> for the last 2 years or so. One of the biggest journeys we've been undertaking is to take accessibility far more seriously. However with an engineering team way into the triple digits it gets harder and harder to scale accessibility knowledge.</p>
<!-- more -->
<p>Knowledge gaps aside CarGurus has a multitude of technologies UI are build with. The two major are <a href="https://freemarker.apache.org/">Freemarker</a> and <a href="https://reactjs.org/">React</a>. I manage one of our infrastructure teams, we build the tools and technologies to create the site with. This includes our component library, our build systems, linting tools, authentication systems, and core utilities for product development. When we first started really taking accessibility seriously we went to several teams in the business. Many of them did not have anyone with accessibility expertise.</p>
<blockquote>
<p>Our first approach was to teach accessibility. At the same time we worked with our brand marketing team to ensure our color pallet would be accessible from the start.</p>
</blockquote>
<p>After identifying advocates on every team we set out to streamline identifying accessibility issues. One approach I decided to take was to show borders around failing elements during development. I first heard of this idea years ago when GitHub released something it called <a href="https://github.com/github/accessibilityjs">accessibilityjs</a>. This script Github included in its pages and put a giant ugly red border around failing elements. I thought this was a really slick idea to point out issues during development.</p>
<blockquote>
<p>I was going to use accessibility JS until I found axe-core</p>
</blockquote>
<p>So <a href="https://www.deque.com/axe/">axe</a> is a technology built by deque to identify accessibility issues. This is a highly configurable piece of technology that includes libraries for developers, browser extensions, and bots you can scan sites with. Deque has open sourced the core technology of axe which is a JavaScript called <a href="https://github.com/dequelabs/axe-core">axe-core</a>.</p>
<blockquote>
<p>I first started out by writing a script to use axe-core and to add a 10px red border around elements, but I quickly ran into trouble</p>
</blockquote>
<p>First problem, I need to re-run axe every time the browser changes. If we click to open a nav-bar we'll need to rescan the page. Second problem, every-time we change the DOM the script would crash react apps, and finally axe-core is quite slow on large HTML documents.</p>
<h2>Mutation Observers</h2>
<p>So the first problem was easily solvable. The browser has an API called <a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver">Mutation Observer</a>. This is an API that lets you listen to changes to certain elements and fire a function when those elements change. In our case we wanted to listen to any changes to the <code><body></code> tag and all of its descendants.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">function</span> <span class="token function">scanForAccesibilityIssues</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* scan for issues */</span><span class="token punctuation">}</span>
<span class="token keyword">const</span> observer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MutationObserver</span><span class="token punctuation">(</span>scanForAccesibilityIssues<span class="token punctuation">)</span><span class="token punctuation">;</span>
observer<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'body'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">childList</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">subtree</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Shadow DOM</h2>
<p>Several UI frameworks such as React keep an in memory representation of the HTML document. The reason for this is when you want to change the UI in React. React will diff its current in-memory DOM with the next DOM and determine the most efficient way to actually apply the changes to the browser. Any application such as a browser extension, or our accessibility detector that edits the DOM outside of React's in-memory DOM will cause React to freak out and either crash of apply a change in an unexpected way. Luckily in recent years browsers have added a <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a>. This is essentially a DOM that is used to apply visual changes to a user, but sits outside the light DOM (or the regular DOM). However, not all HTML elements support The Shadow DOM. For us to apply the red border we need to use the shadow DOM, and if any elements do not support shadow then we have to apply the border to the parent element. I wrote a <a href="https://en.wikipedia.org/wiki/Recursion_(computer_science)#Tail-recursive_functions">recursive function</a> called <code>resolveClosestShadowRoot</code> which will walk up the DOM document and find the closest parent a target element has that supports shadow. You can tell if a node supports shadow because it will have a <code>.attachShadow</code> method. So we can simply access this variable and see if its defined or not.</p>
<pre class="language-js" tabindex="0"><code class="language-js">
<span class="token comment">/**
*
* @param {HTMLElement} node
* @returns
*/</span>
<span class="token keyword">function</span> <span class="token function">resolveClosestShadowRoot</span><span class="token punctuation">(</span><span class="token parameter">node</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>node<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>node<span class="token punctuation">.</span>attachShadow<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> node<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token function">resolveClosestShadowRoot</span><span class="token punctuation">(</span>node<span class="token punctuation">.</span>parentElement<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>After we identify which element to style we just have to apply the border. The code below is doing that by calling the attach shadow function and setting its innerHTML.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">const</span> resolvedNode <span class="token operator">=</span> <span class="token function">resolveClosestShadowRoot</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> shadowRoot <span class="token operator">=</span> resolvedNode<span class="token punctuation">.</span><span class="token function">attachShadow</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'open'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
shadowRoot<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token string">'<style>:host { outline: red solid 1rem; }</style><slot></slot>'</span><span class="token punctuation">;</span></code></pre>
<p>The <code><slot></slot></code> element is rendering the content of the light DOM. We still have to show the existing content, and the <code>:host</code> psudo-class selector is selecting the host of the shadow DOM.</p>
<h2>Debounce 🎉</h2>
<p>In web development we often use what's known as a "debounce" to delay doing something. The simple example is sometimes people click on a button multiple times, often on accident, sometimes intentionally. Before taking any action or taking multiple actions you might wait a moment before they stop clicking to do something. You wouldn't want to take the same action multiple times for each click. This is where debounce comes into play.</p>
<pre class="language-js" tabindex="0"><code class="language-js">
<span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">fn<span class="token punctuation">,</span> wait</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> timeout <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token function-variable function">next</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">clearTimeout</span><span class="token punctuation">(</span>timeout<span class="token punctuation">)</span><span class="token punctuation">;</span>
timeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>next<span class="token punctuation">,</span> wait<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>A debounce function accepts a function and a "wait time" or delay before being called to actually executing your function. To debounce a buttons onclick function you would pass its standard onclick function into the debounce function</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">onclick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> debouncedClick <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span>onclick<span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 500 milliseconds before the function is actually fired</span></code></pre>
<pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">debouncedClick</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span></code></pre>
<h2>The result</h2>
<p>So the result of all this is a function that listens to changes in the HTML document, waits 1 second for all the changes to finish applying, then scans the page for failing elements and uses The Shadow DOM to apply a red border around those elements. You can see a basic version of the code at <a href="https://gist.github.com/TerribleDev/51049146e00b36b0d8643f5e09d21ea8">this Github Gist</a>.</p>
<p>We log the Deque error object to the console which includes links to the failing elements. The result is whenever anyone develops new UI at CarGurus a giant ugly red border surrounds elements they don't write as accessible. This provides <strong>immediate</strong> feedback during the development process and prevents huge categories of accessibility issues from reaching production.</p>
<p><img src="https://blog.terrible.dev/blog/Accessibility-Driven-Development/1.jpg" alt="An example of a failing element"></p>
5 web perf tips for 20192019-02-23T06:32:00Zhttps://blog.terrible.dev/blog/5-web-performance-tips-for-2019/<p>As more and more of the world is getting online, a larger part of the internet community is using the internet on lower powered devices. Making websites fast is becoming paramount. Here are 5 tips to improving you web page's performance</p>
<!-- more -->
<h2>Brotli and gzip</h2>
<p>So incase you didn't know, when your browser makes a request to the server it sends along a header called <code>Accept-Encoding</code> This is a comma separated list of compression types your server can use to compress the data to the user. The common ones in the past have been <code>gzip, and deflate</code>. <a href="https://en.wikipedia.org/wiki/Brotli">Broli</a>, is a compression
algorithm invented by google to be a more efficient for the web. This has about a 35% effectiveness over gzip based on my own testing. This means your content will be almost 1/3rd smaller over the wire. Most browsers <a href="https://caniuse.com/#feat=brotli">support this already</a>. You can use cloudflare to serve Brotli (br) to your users, and most web servers support this today. Make sure your server is serving br, and at minimum gzip.</p>
<h2>Webp, JPEG 2000</h2>
<p>Images are among one of the largest types of files on the internet today, and picking the right file type is as important as getting your data structures right. In the past we told everyone to keep photography in <code>jpeg</code>, logos and screen shots in <code>png</code>. However google has come out with a new file format. One that is massively smaller than either <code>jpeg</code> or <code>png</code>, and that is <code>webp</code>. Webp is only supported on <a href="https://caniuse.com/#search=webp">chrome, edge and firefox</a>, but don't worry for IOS Safari you can use <code>JPEG 2000</code>. Sizing images is also a key concern, you can use srcset to size images appropriately, and you can use the picture element to select the right image given browser support.</p>
<pre class="language-html" tabindex="0"><code class="language-html">
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>picture</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>source</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image/webp<span class="token punctuation">"</span></span> <span class="token attr-name">srcset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>3.webp<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>an image showing the tiny png results<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>source</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image/jp2<span class="token punctuation">"</span></span> <span class="token attr-name">srcset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>3.jp2<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>an image showing the tiny png results<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>3.png<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>an image showing the tiny png results<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>picture</span><span class="token punctuation">></span></span>
</code></pre>
<h2>Lighthouse</h2>
<p>Ok so this is less of a trick to implement and more of a tool use use. Man I keep mentioning google, but they keep making amazing web stuff so here we are. Google has made this awesome performance tool called <a href="https://developers.google.com/web/tools/lighthouse/">lighthouse</a>. A version of this tool is built into chrome. Open the developer tools, and click the <code>audits</code> tab. That tool is lighthouse. You can install newer versions with <code>npm install -g lighthouse</code> or <code>yarn global add lighthouse</code>. Then just run <code>lighthouse --view <url></code> so this blog would be <code>lighthouse --view https://blog.terrible.dev</code>. You should be hit with a pretty in depth report as to how you can fix and improve your web pages. You can also have your CI system run lighthouse on every build. You can fail PR's if they reduce performance, or just track your accessibility over time.</p>
<h2>HTTP/2</h2>
<p>HTTP version 2 is a newer version of the http spec. Supported <a href="https://caniuse.com/#feat=http2">by all major browsers</a> this protocol offers compression of http headers, a <a href="https://en.wikipedia.org/wiki/HTTP/2_Server_Push">push feature</a> that lets you push files down to the browser before they are requested, <a href="https://en.wikipedia.org/wiki/HTTP_pipelining">http pipelining</a>, and multiplexing multiple requests over a single TCP connection. You can easily get http2 working if you let <a href="https://www.cloudflare.com/">cloudflare</a> front your http traffic, but you will still want to implement http2 in your server eventually.</p>
<h2>Service workers</h2>
<p>My last and probably favorite feature. <a href="https://developers.google.com/web/fundamentals/primers/service-workers/">Service Workers</a> are a worker that can stand in between your server and web page in the browser. They are mostly a proxy that let you do things like cache your content, and support offline capabilities. They are easy to implement, you need to have a <code>manifest.json</code> file which you can generate from Microsoft's <a href="https://www.pwabuilder.com/">PWA Builder</a>, and just serve traffic over https only. PWA Builder even has <a href="https://www.pwabuilder.com/serviceworker">pre-made service workers</a> for most scenarios so you don't even need to write your own. I use this for my blog to cache static content, preload blog posts, and provide offline support.</p>
Must have vscode plugins for front-end devs2019-02-06T00:00:00Zhttps://blog.terrible.dev/blog/VS-code-extensions-for-front-end-developers/<p>I've had a lot of people ask me about my choice of editors, and plugins. A while back I switched to vscode for all my programming work, for both front and back end. In the past I've blogged about <a href="https://blog.terrible.dev/VS-2017-best-extensions-on-launch/">the best plugins for visual studio</a> as a backend dev, but I thought I'd give you a more front-end angle</p>
<!-- more -->
<h2>Document this</h2>
<p>My first one, and in my opinion the most underrated is <a href="https://marketplace.visualstudio.com/items?itemName=joelday.docthis">document this</a>. So if you have ever had to write <a href="http://usejsdoc.org/">jsdoc</a> comments you can know how tedious it gets, and if you haven't, trust me you should. VSCode and most other editors can read <a href="http://usejsdoc.org/">jsdoc</a> comments above functions, and class declarations to improve the intellisense and type completion statements. Simply have your cursor over a function, invoke document this, and quickly you will be given jsdoc comments for your code.</p>
<p><img src="https://blog.terrible.dev/blog/VS-code-extensions-for-front-end-developers/document-this.gif" alt="Animated gif showing off document this"></p>
<h2>Import Cost</h2>
<p>Another extension I find vital to my every day is <a href="https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost">import cost</a>. This is a package, that leaves you little notes on the side of any import you have as to how big it will be. This package will even highlight the size text in red for large imports which you can configure. What I love about this package, is it tells me if the package I'm about to use is going to be very expensive size wise. That way I find out long before I commit the code, and my pages get slow.</p>
<p><img src="https://blog.terrible.dev/blog/VS-code-extensions-for-front-end-developers/import-cost.png" alt="a static image showing off import cost"></p>
<h2>ESlint and Prettier</h2>
<p>Hopefully both of these will not be new to you. ESLint is a linting tool that looks for potential errors in your code. Prettier is an opinionated style enforcer for your code. The <a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint">eslint</a> and <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">prettier</a> extensions for vscode can automatically show you problems in your code as you type, and can even fix your code on save. What I love about both of these tools, is together they make a great force for improving your code base. Prettier eliminates many debates over code style between team members, and eslint prevents you from shipping many bugs to production. These extensions can call out problems as you type, which decreases the feedback loops, and increases your productivity.</p>
<h2>Filesize</h2>
<p>As a web developer I spend a lot of my time looking at file size. Right now file sizes are ever inflating, and are causing pain for bandwidth constrained devices. I often download bundles, and inspect their compiled source, or just have to look at how big a file is on the filesystem. A big tool I have in my belt is <a href="https://marketplace.visualstudio.com/items?itemName=mkxml.vscode-filesize">filesize</a>. This is a crazy simple extension, but one that brings me joy everyday. The premise is simple, print the file size of the current file in the status bar at the bottom. Click on it, and you get a nice output of what its like gzipped, and the mime type. Dirt simple, but saved me a ton of time everyday!</p>
<p><img src="https://blog.terrible.dev/blog/VS-code-extensions-for-front-end-developers/filesize2.jpg" alt="a picture of the filesize plugin in action"></p>
<h2>Runner ups</h2>
<p>Here is a list of additional extensions I certainly couldn't live without</p>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense">path intellisense</a> - autocomplete file paths in various files (including html)</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense">npm intellisense</a> - autocomplete npm pages in imports</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=sidthesloth.html5-boilerplate">html 5 boilerplate</a> - dirt simple html boilerplate snippets</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=idleberg.icon-fonts">icon fonts</a> - Autocomplete for various icon fonts such as font awesome</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">git lens</a> - Show git history inline, along with other information from git</li>
</ul>
Compressing images with tinypng's CLI2019-01-23T15:50:00Zhttps://blog.terrible.dev/blog/Compressing-images-with-tinypng/<p>Ok so I'm really lazy, and I honestly think that has helped me a lot in this industry. I always try to work smarter, not harder. I take many screen shots for this blog, and I need to optimize them. Incase you didn't know many images are often larger than they need to be slowing the download time. However, I don't ever want to load them into photoshop. Too much time and effort!</p>
<!-- more -->
<p>At first I tried to compress images locally, but it took to long to run through all the images I had. So recently I started using a service called <a href="https://tinypng.com/">tiny png</a> to compress images. Now the website seems to indicate that you upload images, and you will get back optimized versions. However to me this takes too much time. I don't want the hassle of zipping my images uploading them, downloading the results. Again, lazy!</p>
<p>So I figured out they have a cli in npm. Easy to install, just use npm to globally install it. <code>npm install -g tinypng-cli</code>.</p>
<p>Now you have to call the cli, this is the flags I use <code>tinypng . -r -k YourKeyHere</code>. The period tells tinypng to look in the current directory for images, <code>-r</code> tells it to look recursively, or essentially to look through child directories as well, and the <code>-k YourKeyHere</code> is the key you get by logging in. On the free plan you get 500 compressions a month. Hopefully you will fall into the pit of success like I did!</p>
<p><img src="https://blog.terrible.dev/blog/img/Compressing-images-with-tinypng/3.png" alt="an image showing the tiny png results"></p>
Rebuilding this blog for performance2019-01-21T22:56:34Zhttps://blog.terrible.dev/blog/Rebuilding-this-blog-for-performance/<p>So many people know me as a very performance focused engineer, and as someone that cares about perf I've always been a bit embarrassed about this blog. In actual fact this blog as it sits now is <strong>fast</strong> by most people's standards. I got a new job in July, and well I work with an <a href="https://twitter.com/markuskobler">absolute mad lad</a> that is making me feel pretty embarrassed with his 900ms page load times. So I've decided to build my own blog engine, and compete against him.</p>
<!-- more -->
<h2>Approach</h2>
<p>Ok, so I want a really fast blog, but one that does not sacrifice design. I plan to pre-compute the HTML into memory, but I am not going to serve static files. In this case, I'll need an application server. I'm going to have my own CSS styles, but I'm hoping to be in the (almost) no-JS camp. Not that I dislike JS, but I want to do as much pre-computing as possible, and I don't want to slow the page down with compute in the client.</p>
<h2>Features</h2>
<p>This blog has a view to read a post. A home page with links to the last 10 blog posts and a pager to go back further in time. A page listing blogs by tags and links for each tag to posts.</p>
<h2>Picking Technologies</h2>
<p>So in the past my big philosophy has been that most programming languages and technologies really don't matter for most applications. In fact this use-case <em>could</em> and probably should be one of them, but when you go to extremes that I go, you want to look at benchmarks. <a href="https://www.techempower.com/benchmarks/">Tech empower</a> does benchmarks of top programming languages and frameworks. For my blog since it will be mostly be bytes in bytes out, precomputed, we should look at the plain text benchmark. The top 10 webservers include go, java, rust, c++, and C#. Now I know rust, go and C# pretty well. Since the rust, and go webservers listed in the benchmark were mostly things no one really uses, I decided to use dotnet. This is also for a bit of a laugh, because my competition hates dotnet, and I also have deep dotnet expertise I can leverage.</p>
<h2>Server-side approach</h2>
<p>So as previously mentioned we'll be precomputing blog posts. I plan to compute the posts and hand them down to the views. If we use completely immutable data structures we'll prevent any locking that could slow down our app.</p>
<h2>ASPNET/Dotnet Gotchas</h2>
<p>So dotnet is a managed language with a runtime. Microsoft has some <a href="https://docs.microsoft.com/en-us/aspnet/core/performance/performance-best-practices?view=aspnetcore-2.2">performance best practices</a>, but here are some of my thoughts.</p>
<ul>
<li>There is a tool called <a href="https://github.com/dotnet/coreclr/blob/master/Documentation/building/crossgen.md">cross gen</a> which compiles dll's to native code.</li>
<li>Dotnet's garbage collector is really good, but it struggles to collect long living objects. Our objects will need to either be ephemeral, or pinned in memory forever.</li>
<li>The garbage collector struggles with large objects, especially large strings. We'll have to avoid large string allocations when possible.</li>
<li>dotnet has reference types such as objects, classes, strings, and most other things are value types. <a href="https://blog.terrible.dev/c-strings/">Value types are allocated</a> on the stack which is far cheaper than the heap</li>
<li>Exceptions are expensive when thrown in dotnet. I'm going to always avoid hitting them.</li>
<li>Cache all the things!</li>
</ul>
<p>In the past we had to pre-compile razor views, but in 2.x of dotnet core, that is now built in. So one thing I don't have to worry about</p>
<h2>Client side page architecture and design</h2>
<p>So here are my thoughts on the client side of things.</p>
<ul>
<li>Minify all the content</li>
<li>Fingerprint all css/js content and set cache headers to maximum time</li>
<li>Deliver everything with brotli compression</li>
<li>Zopfli and gzip for fallbacks</li>
<li>Always use <code>Woff2</code> for fonts</li>
<li>Avoid expensive css selectors
<ul>
<li><code>:nth child</code></li>
<li><code>fixed</code></li>
<li>partial matching <code>[class^="wrap"]</code></li>
</ul>
</li>
<li>Use HTTP/2 for <strong>all requests</strong></li>
<li>Images
<ul>
<li>Use SVG's when possible</li>
<li>Recompile all images in the build to <code>jpeg 2000, jpeg xr, and webp</code></li>
<li>Serve <code>jpeg 2000</code> to ios</li>
<li><code>jpeg XR</code> to ie11 and edge</li>
<li>Send <code>webp</code> to everyone else</li>
</ul>
</li>
<li>PWA
<ul>
<li>Use a service worker to cache assets</li>
<li>Also use a service worker to prefetch blog posts</li>
<li>Offline support</li>
</ul>
</li>
<li>CDN
<ul>
<li>Use Cloudflare to deliver assets faster</li>
<li>Cloudflare's argo improves geo-routing and latency issues</li>
<li>Throw any expected 301's inside cloudflares own datacenters with workers</li>
</ul>
</li>
</ul>
<h2>Tools</h2>
<p>These are the list of tools I'm using to measure performance.</p>
<ul>
<li><code>lighthouse</code> - Built into chrome (its in the audit tab in the devtools), this displays a lot of performance and PWA improvements.</li>
<li><a href="https://webhint.io/">Web Hint</a> is like a linter for your web pages. The tool provides a ton of improvements from accessibility to performance</li>
<li>I really like <a href="https://tools.pingdom.com/">pingdom's</a> page load time tool.</li>
<li>Good ol' <a href="https://www.webpagetest.org/">web page test is also great</a></li>
<li>The chrome devtools can also give you a breakdown as to what unused css you have on the page</li>
</ul>
Measuring, Visualizing and Debugging your React Redux Reselect performance bottlenecks2019-01-15T03:04:56Zhttps://blog.terrible.dev/blog/Visualizing-your-react-redux-performance-bottlenecks/<p>In the battle of performance one tool constantly rains supreme, the all powerful profiler! In javascript land chrome has a pretty awesome profiler, but every-time I looked into our react perf issues I was always hit by a slow function called <code>anonymous function</code></p>
<!-- more -->
<h2>Using the chrome profiler</h2>
<p>So if you open the chrome devtools, you will see a tab called <code>performance</code>. Click on that tab. If you are looking into CPU bound workloads click the CPU dropdown and set yourself to 6x slowdown, which will emulate a device that is much slower.</p>
<p><img src="https://blog.terrible.dev/blog/Visualizing-your-react-redux-performance-bottlenecks/1.png" alt="An image showing the chrome devtools"></p>
<p>Press the record button, click around on your page, then click the record button again. You are now hit with a timeline of your app, and what scripts were ran during this time.</p>
<p>So what I personally like to do is find orange bars that often make up the bulk of the time. However I've often noticed the bulk of bigger redux apps are taken up by <code>anonymous functions</code> or functions that essentially have no name. They often look like this <code>() => {}</code>. This is largely because they are inside of <a href="https://github.com/reduxjs/reselect">reselect selectors</a>. Incase you are unfamiliar selectors are functions that cache computations off the redux store. Back to the chrome profiler. One thing you can do it use the <code>window.performance</code> namespace to measure and record performance metrics into the browser. If you expand the <code>user timings section</code> in the chrome profiler you may find that react in dev mode has included some visualizations for how long components take to render.</p>
<p><img src="https://blog.terrible.dev/blog/Visualizing-your-react-redux-performance-bottlenecks/3.png" alt="react user timings in chrome"></p>
<h2>Adding your own visualizations</h2>
<p>So digging into other blog posts, I found posts showing how to <a href="https://medium.com/@vcarl/performance-profiling-a-redux-app-c85e67bf84ae">visualize your redux actions</a> using the same performance API mechanisms react uses. That blog post uses redux middleware to add timings to actions. This narrowed down on our performance problems, but did not point out the exact selector that was slow. Clearly we had an action that was triggering an expensive state update, but the time was still spent in <code>anonymous function</code>. Thats when I had the idea to wrap reselect selector functions in a function that can append the timings. <a href="https://gist.github.com/TerribleDev/db48b2c8e143f9364292161346877f93">This gist is what I came up with</a></p>
<pre class="language-js" tabindex="0"><code class="language-js">
<span class="token keyword">import</span> <span class="token punctuation">{</span>createSelector<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'reselect'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> hasPerformanceApi <span class="token operator">=</span>
window <span class="token operator">&&</span>
window<span class="token punctuation">.</span>performance <span class="token operator">&&</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>measure <span class="token operator">&&</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>mark<span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token function-variable function">createFuncWithMark</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> callback</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> startMark <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-Startmark</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token keyword">const</span> endMark <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-EndMark</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span><span class="token function">mark</span><span class="token punctuation">(</span>startMark<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">callback</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span><span class="token function">mark</span><span class="token punctuation">(</span>endMark<span class="token punctuation">)</span><span class="token punctuation">;</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span><span class="token function">measure</span><span class="token punctuation">(</span><span class="token string">'♻️ '</span> <span class="token operator">+</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-Selector</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> startMark<span class="token punctuation">,</span> endMark<span class="token punctuation">)</span><span class="token punctuation">;</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span><span class="token function">clearMarks</span><span class="token punctuation">(</span>startMark<span class="token punctuation">)</span><span class="token punctuation">;</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span><span class="token function">clearMarks</span><span class="token punctuation">(</span>endMark<span class="token punctuation">)</span><span class="token punctuation">;</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span><span class="token function">clearMeasures</span><span class="token punctuation">(</span>startMark<span class="token punctuation">)</span><span class="token punctuation">;</span>
window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span><span class="token function">clearMeasures</span><span class="token punctuation">(</span>endMark<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> result<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">createMarkedSelector</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> <span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>hasPerformanceApi<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">createSelector</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>name <span class="token operator">||</span> <span class="token keyword">typeof</span> name <span class="token operator">!==</span> <span class="token string">'string'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'marked selectors must have names'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> callback <span class="token operator">=</span> args<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> funcWithMark <span class="token operator">=</span> <span class="token function">createFuncWithMark</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> callback<span class="token punctuation">)</span><span class="token punctuation">;</span>
args<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>funcWithMark<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">createSelector</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
<p>So how does this work exactly? Well its a library that wraps the function you pass to reselect that adds markers to the window to tell you how fast reselect selectors take to run. Combined with the previously mentioned blog post, you can now get timings in chrome's performance tool with selectors! You can also combine this with the <a href="https://medium.com/@vcarl/performance-profiling-a-redux-app-c85e67bf84ae">redux middleware</a> I previously mentioned to get a deeper insight into how your app is performing</p>
<p><img src="https://blog.terrible.dev/blog/Visualizing-your-react-redux-performance-bottlenecks/2.png" alt="a preview of selectors reporting their performance"></p>
<h2>So how do I use your gist?</h2>
<p>You can copy the code into a file of your own. If you use reselect you probably have code that looks like the following.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> computeSomething <span class="token operator">=</span> <span class="token function">createSelector</span><span class="token punctuation">(</span><span class="token punctuation">[</span>getState<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">state</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">/* compute projection */</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>You just need to replace the above with the following</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> computeSomething <span class="token operator">=</span> <span class="token function">createMarkedSelector</span><span class="token punctuation">(</span><span class="token string">'computeSomething'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>getState<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">state</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">/* compute projection */</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>its pretty simple, it just requires you to pass a string in the first argument slot. That string will be the name used to write to the performance API, and will show up in the chrome profiler. Inside vscode you can even do a regex find and replace to add this string.</p>
<pre><code>find: const(\s?)(\w*)(\s?)=(\s)createSelector\(
replace: const$1$2$3=$4createMarkedSelector('$2',
</code></pre>
Deploying a react app to azure blob storage websites with azure devops2018-11-09T04:02:59Zhttps://blog.terrible.dev/blog/Deploying-a-react-app-to-azure-blob-storage-websites-with-azure-devops/<p>Back in August of this year Microsoft <a href="https://azure.microsoft.com/en-us/blog/azure-storage-static-web-hosting-public-preview/">announced static websites for azure blob storage</a>. So this is the same feature AWS' S3 has had for years. Essentially make a blob storage folder public, and redirect <code>/</code> paths to <code>/index.html</code> internally. Also, register 404 pages. Before we had this we use to deploy our files to <code>App Service</code> or do some weirdness with functions to rewrite urls. For static pages this can really bring costs down in the cloud</p>
<!-- more -->
<p>So the big idea is simple. Upload files into a blob container, serve pages, profit! This obviously becomes less simple when you have to do the devops. So recently I've been using Azure devops more. Basically, vsts rebranded! I've been into this service lately, mostly because of the dual windows and linux build machines you can get. My other favorite in this space is <a href="https://circleci.com/">circleci</a>. Since we're using azure, and Azure Devops has great intergration with azure. I took a crack and using it to push my react app to blob storage.</p>
<h2>Build</h2>
<p>So an azure devops pipeline consists of 2 phases. Build, and release. To put this simply, build should generate our artifacts, and release should push them to production. Lets start with creating a simple react app with <code>npx create-react-app <appnamehere></code>. This should generate a react app in the current directory. Pro tip, you can use <code>--typescript</code> if you want typescript support.</p>
<p>Ok, the build here should be very simple. We need to do the following steps</p>
<ul>
<li>clone our project</li>
<li>install npm packages</li>
<li>run the unit tests</li>
<li>build the project</li>
<li>archive the project files</li>
</ul>
<p>To get started create a new build definition. Click get sources and configure your git repo. Next we need to do an npm install, this is pretty simple with the npm tasks in the gallery. Next we need to run <code>npm run test</code>. Pick the npm task, under command click custom and replace the command and arguments box with <code>run test</code>. Do the same after for the <code>build</code> phase. Add a step to zip the <code>build</code> directory, and finally add the publish artifact task with the path to your archive build file.</p>
<p><img src="https://blog.terrible.dev/blog/Deploying-a-react-app-to-azure-blob-storage-websites-with-azure-devops/1.PNG" alt="">
<img src="https://blog.terrible.dev/blog/Deploying-a-react-app-to-azure-blob-storage-websites-with-azure-devops/2.PNG" alt="">
<img src="https://blog.terrible.dev/blog/Deploying-a-react-app-to-azure-blob-storage-websites-with-azure-devops/3.PNG" alt="">
<img src="https://blog.terrible.dev/blog/Deploying-a-react-app-to-azure-blob-storage-websites-with-azure-devops/4.PNG" alt="">
<img src="https://blog.terrible.dev/blog/Deploying-a-react-app-to-azure-blob-storage-websites-with-azure-devops/5.PNG" alt=""></p>
<h2>Release</h2>
<p>The release phase is pretty simple. We first need to extract our files from the build. Then publish to azure using this azure cli upload batch command <code>az storage blob upload-batch --source out/build --destination $container_name --account-key $AZURE_STORAGE_KEY --account-name $AZURE_STORAGE_ACCOUNT</code>. In my case I'm using linux, and bash is injecting those variables from the environment. You need to register your storage key and storage account name as secure variables to your account.</p>
<p><img src="https://blog.terrible.dev/blog/Deploying-a-react-app-to-azure-blob-storage-websites-with-azure-devops/6.PNG" alt="">
<img src="https://blog.terrible.dev/blog/Deploying-a-react-app-to-azure-blob-storage-websites-with-azure-devops/7.PNG" alt=""></p>
The battle of the bulge. Visualizing your javascript bundle2018-10-17T17:19:18Zhttps://blog.terrible.dev/blog/Visualizing-your-javascript-bundle/<p>So incase you havn't been following me. I joined Cargurus in July. At cargurus we're currently working on our mobile web experience written in react, redux and reselect. As our implementation grew so did our time to first paint.</p>
<!-- more -->
<p>So I've been spending a lot of time working on our performance. One tool I have found invaluable in the quest for page perf mecca is <a href="https://www.npmjs.com/package/source-map-explorer">source-map-explorer</a>. This is a tool that dives into a bundled file, and its map. Then visualizes the bundle in a tree view. This view lets you easily understand exactly what is taking up space in the bundle. What I love about this tool is that it works with any type of bundled javascript file, and is completely de-void of any builds. So any bugs in your webpack config leading to duplicate files in a bundle will show up here.</p>
<h2>Getting started</h2>
<p>You get started by <code>npm install -g source-map-explorer</code> then just download your bundles, and sourcemaps. You can do this from production if you have them. Otherwise build bundles locally. <strong>Note</strong> You should always use this on minified code where any tree shaking and dead code elimination has occurred. In the command line run <code>source-map-explorer ./yourbundle.js ./yourbundle.js.map</code> Your browser should then open with a great tree view of what is inside your bundle. From here you can look to see what dependencies you have, and their sizes. Obviously, you can then decide to keep or throw them away.</p>
<p><img src="https://blog.terrible.dev/blog/Visualizing-your-javascript-bundle/1.png" alt="an example visualization"></p>
<p>Here is a great youtube video explaining it in detail!</p>
<p><img src="https://www.youtube.com/watch?v=7aY9BoMEpG8" alt="video"></p>
Creating a slack slash command with 0 code using Azure Logic Apps2018-09-19T21:14:41Zhttps://blog.terrible.dev/blog/Creating-a-slack-slash-command-with-0-code-using-Azure-Logic-Apps/<p>Ok so recently I was chatting on a slack, mostly sharing cat pictures, when I realized the CarGurus slack account did not have a <code>/cat</code> command. I knew immediately, this had to change!</p>
<!-- more -->
<p>So my vision was simple, write <code>/cat</code> in slack and a random cat appears! Slack has native functionality to extend the slash commands. You can find the custom integrations by clicking on your slack workspace name, and clicking <code>customize slack</code>. Then you can do a search for <code>slash commands</code>.</p>
<p><img src="https://blog.terrible.dev/blog/Creating-a-slack-slash-command-with-0-code-using-Azure-Logic-Apps/slack1.png" alt="a screen shot of the slack UI for adding a slash command"></p>
<p>So anyway, slash commands will call an http endpoint with either a POST or get. For mine I chose post. They expect a response within <code>300ms</code>, so not a lot of time! However in the post data slack provides a URL you can post back to with your response. That URL can be used for <code>3 seconds</code> tons of time for an api.</p>
<p>So I found <a href="http://aws.random.cat/meow">this api</a> which returns you a url of a random cat photo. Obviously, my first reaction was to just call it and paste the response in slack. Unfortunately slack expects messages to come back in a <a href="https://api.slack.com/docs/messages">specific json format</a>.</p>
<p>My first reaction was to make a azure function, when called from http will call the <a href="http://aws.random.cat/meow">random.cat</a> api, and then shape the data correctly for slack. Even though that is not much code, its certainly more work than I was willing to put in on a <code>lunch break</code> project.</p>
<p>Then I remembered <code>azure logic apps</code> poor choice of name, but the demo I saw a year ago looked interesting. Ok, so this is basically like if-this-then-that but more for developers. You can do all kinds of cool stuff with it, like trigger when a file is written to storage, and call a workflow of other serverless functions.</p>
<p>In my case I started out with the http trigger. I made a parallel branch. The first branch returns an <code>200</code> status code back to the caller. This is because slack requires a response within <code>300ms</code>. The second branch I added a http call to the random cat api, a parse json function to parse the results, and then another http call back to slack with the proper data. The Url to the slack api is a function call to <code>triggerFormDataValue('response_url')</code> which will parse out the response url from the posted data to our function's trigger. I called the slash command and huzzah! I got an image of a cat!</p>
<p><img src="https://blog.terrible.dev/blog/Creating-a-slack-slash-command-with-0-code-using-Azure-Logic-Apps/slack2.png" alt="an image of a cat from the random cat slash command"></p>
<p>Here is a quick view of my logic app workflow.</p>
<p><img src="https://blog.terrible.dev/blog/Creating-a-slack-slash-command-with-0-code-using-Azure-Logic-Apps/azure1.png" alt="a screen shot of a logic app workflow in azure"></p>
<p>The code view of my logic app looks like the following. The whole thing was pretty easy, and I did it over my lunch break!</p>
<pre class="language-json" tabindex="0"><code class="language-json">
<span class="token punctuation">{</span>
<span class="token property">"definition"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"$schema"</span><span class="token operator">:</span> <span class="token string">"https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#"</span><span class="token punctuation">,</span>
<span class="token property">"actions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"HTTP"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"inputs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"method"</span><span class="token operator">:</span> <span class="token string">"GET"</span><span class="token punctuation">,</span>
<span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"http://aws.random.cat/meow"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"limit"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"timeout"</span><span class="token operator">:</span> <span class="token string">"PT1S"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"runAfter"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Http"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"HTTP_2"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"inputs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"body"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"parse"</span><span class="token operator">:</span> <span class="token string">"full"</span><span class="token punctuation">,</span>
<span class="token property">"response_type"</span><span class="token operator">:</span> <span class="token string">"in_channel"</span><span class="token punctuation">,</span>
<span class="token property">"text"</span><span class="token operator">:</span> <span class="token string">"@body('Parse_JSON')?['file']"</span><span class="token punctuation">,</span>
<span class="token property">"unfurl_links"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token property">"unfurl_media"</span><span class="token operator">:</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"headers"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"Content-Type"</span><span class="token operator">:</span> <span class="token string">"application/json"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"method"</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
<span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"@{triggerFormDataValue('response_url')}"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"runAfter"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"Parse_JSON"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">"Succeeded"</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Http"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"Parse_JSON"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"inputs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"content"</span><span class="token operator">:</span> <span class="token string">"@body('HTTP')"</span><span class="token punctuation">,</span>
<span class="token property">"schema"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"file"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"string"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"object"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"runAfter"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"HTTP"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">"Succeeded"</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"ParseJson"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"Response"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"inputs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"statusCode"</span><span class="token operator">:</span> <span class="token number">200</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"kind"</span><span class="token operator">:</span> <span class="token string">"Http"</span><span class="token punctuation">,</span>
<span class="token property">"runAfter"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Response"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"contentVersion"</span><span class="token operator">:</span> <span class="token string">"1.0.0.0"</span><span class="token punctuation">,</span>
<span class="token property">"outputs"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"parameters"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"triggers"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"manual"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"inputs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"schema"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"kind"</span><span class="token operator">:</span> <span class="token string">"Http"</span><span class="token punctuation">,</span>
<span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Request"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
Managing and catering events2018-07-24T14:15:41Zhttps://blog.terrible.dev/blog/Managing-and-catering-events/<p>A few weeks ago I ran a 3 day event at Vistaprint. We had many engineers fly into our organization. These engineers are from both other countries, and even other companies. We essentially had a mini 3 day conference, and I had to run it! I learned quite a bit about running a conference.</p>
<!-- more -->
<!-- toc -->
<h2>Communication</h2>
<p>The biggest thing you need to do is communicate with your attendees early. Depending on the size of the population, and attendees you might consider having weekly conference calls where people can listen in, and ask questions. You should consider making a slack group. That way people can coordinate meetups, and get announcements.</p>
<p>Google docs, or some other shareable pages are very important. Make sure attendees can find, and view relevant information. Things to make sure you communicate early, and often.</p>
<ul>
<li>Address of venue
<ul>
<li>Instructions how to get to the venue, or what to do when the attendees arrive</li>
</ul>
</li>
<li>Schedule of event
<ul>
<li>Even if you just have placeholder text, get it out early!</li>
<li>Make sure you include addresses of any off site places you may go. People have loved ones, and they want to keep them updated</li>
</ul>
</li>
<li>Whom is running the event, and other staff they can contact</li>
<li>An email address to contact
<ul>
<li>Make sure you <strong>encourage</strong> people to reach out to you if they have special needs</li>
</ul>
</li>
<li>What hotels you recommend
<ul>
<li>Any any discounts if you can partner with a hotel.</li>
</ul>
</li>
</ul>
<h2>Speakers</h2>
<p>Organizing events is tough enough, but even harder if you are going to have speakers. Consider pairing up speakers with conference staff. See if you can preview the talks early, and let the speakers know if you are shooting for a specific theme. Don't force people into your theme too much, but you should try to couple the talks somehow to improve cohesion.</p>
<h2>Catering</h2>
<p>Ok, food is good. Your attendees will like having food. Your attendees will probably have special needs. At minimum you should have vegetarian options for all meals. Most people that eat meat won't mind eating vegetables, but vegetarians will definitely not want to eat meat.</p>
<p>You should vet your caterers a little. Ask any event coordinators for your venue if they have recommended, reliable companies. Read reviews, caterers will always over deliver. If you say you are hosting a party for 20 people, usually you get food for 23. For every 10 people you have attending, only ask for food for 9. So you have 20 people coming, buy for 18.</p>
<p>You should ask your attendees to <a href="https://blog.terrible.dev/blog/Managing-and-catering-events/">communicate</a> with you incase they have special dietary restrictions. Typically you don't have to worry about Gluten free, Vegan, allergies, etc, unless someone lets you know. You should, make them feel comfortable to speak up, but try to get that info in advance.</p>
<h2>Conference Rooms</h2>
<p>You are going to have to figure out which rooms you are in. Round rooms are great for round table discussions, rectangles are great for speaking. Not to say you need to pick one or the other. However you should consider U shaped seating for presentations, and oval, or circular for talks. If you plan on letting people have beverages, consider having tables in the room with some drinks. You should clearly mark, or let people know where the bathrooms are.</p>
<h2>Audio/Video</h2>
<p>Ok, Audio/Video is hard! You are going to probably book an event that has A/V. Your first mission is to find the aspect ratio for the AV system, and <a href="https://blog.terrible.dev/blog/Managing-and-catering-events/">communicate that outward</a> to your <a href="https://blog.terrible.dev/blog/Managing-and-catering-events/">speakers</a>. Their slides should hopefully be the same aspect ratio.</p>
<p>Next is <a href="https://en.wikipedia.org/wiki/Dongle">dongles</a> aka adapters. You need to find out from your AV vendor, what video connector they have. They probably have either <a href="https://en.wikipedia.org/wiki/HDMI">HDMI</a>, or <a href="https://en.wikipedia.org/wiki/VGA_connector">VGA</a>. You should make sure you have a bunch of dongles that adapt the AV system's video in, to your laptop's video out. You should have the following covered</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/HDMI">HDMI</a></li>
<li><a href="https://en.wikipedia.org/wiki/VGA_connector">VGA</a></li>
<li><a href="https://en.wikipedia.org/wiki/USB-C">USB-C</a></li>
<li><a href="https://en.wikipedia.org/wiki/Mini_DisplayPort">Mini DisplayPort</a></li>
<li><a href="https://en.wikipedia.org/wiki/DisplayPort">DisplayPort</a></li>
</ul>
<h2>Prayer rooms, and spaces</h2>
<p>Ok, not everyone has the same faiths and beliefs. Not everyone is you, sometimes people need quite places to sit. Some people get overwhelmed easily. First off, don't judge, just provide. You should find a small quite space where people can go pray. Where people can go meditate. You don't need anything other than a room. Find a room where people can go. You can call it a <code>reflection room</code>, say its open to all faiths, and all people. Make sure your words convey that its not just for prayer, but for all people that need a small quiet space.</p>
Writing an animated flyout hamburger menu2018-06-08T19:17:26Zhttps://blog.terrible.dev/blog/Writing-an-animated-flyout-hamburger-menu/<p>So I'm currently sitting on a plane at the moment. A recent project I started on was a <a href="https://nashua.fun">travel guide where I live</a>. Being on a plane without wifi for a long time is a quick wakeup to me how much I rely on the internet to code.</p>
<!-- more -->
<p>My page itself uses the minimalist Jekyll theme. I really like this theme's typography, and clean look. However its missing a key element for my page, and that is a menu. Without the ability to google I set off writing my own menu. No libraries, and that includes jquery! The only thing I relied on was a local copy of font awesome I had recently downloaded. So the first place I started was to make the flyout menu. Here is a screen shot of the results.</p>
<p><img src="https://blog.terrible.dev/blog/Writing-an-animated-flyout-hamburger-menu/menu.png" alt="screen shot showing expanded menu"></p>
<p>Seeing as I didn't have a button to toggle right away, I just called a few functions I wired up into the window for development purposes. I added the following html in the body tags. Notice a few things. First, I've used font-awesome 5 to get a circle with an <code>x</code> in it. This will be used to close the menu, if you don't want to make a selection. Then we have each link, and in my use-case I made these hash links.</p>
<pre class="language-html" tabindex="0"><code class="language-html">
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>nav</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hamNav<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">hideNav</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>i</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>closeNav fas fa-times-circle<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>i</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#item1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item 1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#item2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item 2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>nav</span><span class="token punctuation">></span></span>
</code></pre>
<p>So here is the css I generally used. Now I'm using <code>scss</code> so I can nest some variables. There are a few things worth mentioning. First off the navbar I called hamNav, because it was a hamburger style menu nav. The second is that the navbar's position is fixed, and it defaults to a width of 0, which means it won't really render any pixels on the screen. Finally, I've added a css transition of .5s This will cause the menu to animate out from the left side.</p>
<pre class="language-scss" tabindex="0"><code class="language-scss"><span class="token selector">.hamNav</span><span class="token punctuation">{</span>
<span class="token property">position</span><span class="token punctuation">:</span> fixed<span class="token punctuation">;</span>
<span class="token property">height</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token property">width</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token property">overflow-y</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
<span class="token property">overflow-x</span><span class="token punctuation">:</span> visible<span class="token punctuation">;</span>
<span class="token property">transition</span><span class="token punctuation">:</span> 0.5s<span class="token punctuation">,</span>
box-shadow 0.3s ease<span class="token punctuation">;</span>
<span class="token property">background</span><span class="token punctuation">:</span> #222<span class="token punctuation">;</span>
<span class="token property">top</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token property">left</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token property">z-index</span><span class="token punctuation">:</span> 9999999<span class="token punctuation">;</span>
<span class="token property">padding-top</span><span class="token punctuation">:</span> 8%<span class="token punctuation">;</span>
<span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
<span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
<span class="token selector">p,h1,h2,h3,h4,span,div,ul,li</span><span class="token punctuation">{</span>
<span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">ul </span><span class="token punctuation">{</span>
<span class="token property">padding-left</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token selector">li </span><span class="token punctuation">{</span>
<span class="token property">list-style-type</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token property">font-size</span><span class="token punctuation">:</span> 1.5em<span class="token punctuation">;</span>
<span class="token property">padding-bottom</span><span class="token punctuation">:</span> 4%<span class="token punctuation">;</span>
<span class="token property">margin-left</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token selector">a, a:visited </span><span class="token punctuation">{</span>
<span class="token property">color</span><span class="token punctuation">:</span> white
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
@media screen <span class="token operator">and</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 720px<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token selector"><span class="token parent important">&</span>.show</span><span class="token punctuation">{</span>
<span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
@media screen <span class="token operator">and</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 721px<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token selector"><span class="token parent important">&</span>.show</span><span class="token punctuation">{</span>
<span class="token property">width</span><span class="token punctuation">:</span> 40%<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token selector">.closeNav</span><span class="token punctuation">{</span>
<span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
<span class="token property">right</span><span class="token punctuation">:</span> 10%<span class="token punctuation">;</span>
<span class="token property">top</span><span class="token punctuation">:</span> 2%<span class="token punctuation">;</span>
<span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
<span class="token property">font-size</span><span class="token punctuation">:</span> 1.5em<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Now then I added a file with some JavaScript functions. these functions simply will add the <code>show</code> class to our menu bar. Once we add that class, we'll give the menu a width and thus cause it to animate out. You would be able to see this by running <code>toggle()</code> in the JavaScript console.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">function</span> <span class="token function">showNav</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">var</span> elem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByClassName</span><span class="token punctuation">(</span><span class="token string">"hamNav"</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
elem<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"show"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">hideNav</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">var</span> elem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByClassName</span><span class="token punctuation">(</span><span class="token string">"hamNav"</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
elem<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"show"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">toggle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">var</span> elem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByClassName</span><span class="token punctuation">(</span><span class="token string">"hamNav"</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>elem<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token string">"show"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
elem<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"show"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span><span class="token punctuation">{</span>
elem<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"show"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Ok, so I needed a button to open the menu. These days most websites have a small circular button on the right side, with the hamburger menu icon in it. Back to font awesome where I got a sweet hamburger icon, and I wrote the following html in the body.</p>
<pre class="language-html" tabindex="0"><code class="language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>header</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#hamMenu<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>navBtn<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">trigger</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>i</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fas fa-bars<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>i</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>header</span><span class="token punctuation">></span></span></code></pre>
<p>Ok this will give us an a link with a hamburger icon inside. Now we have to style the a link so it looks like a round button. Back to css!</p>
<pre class="language-scss" tabindex="0"><code class="language-scss"><span class="token selector">.navBtn</span><span class="token punctuation">{</span>
<span class="token property">position</span><span class="token punctuation">:</span> fixed<span class="token punctuation">;</span>
<span class="token property">background-color</span><span class="token punctuation">:</span> #222<span class="token punctuation">;</span>
<span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
<span class="token property">bottom</span><span class="token punctuation">:</span> 15%<span class="token punctuation">;</span>
<span class="token property">right</span><span class="token punctuation">:</span> 8%<span class="token punctuation">;</span>
<span class="token property">width</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span>
<span class="token property">height</span><span class="token punctuation">:</span> 50px<span class="token punctuation">;</span>
<span class="token property">z-index</span><span class="token punctuation">:</span> 100<span class="token punctuation">;</span>
<span class="token property">border-radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>
<span class="token property">vertical-align</span><span class="token punctuation">:</span> middle<span class="token punctuation">;</span>
<span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
<span class="token property">font-size</span><span class="token punctuation">:</span> 1.3em<span class="token punctuation">;</span>
<span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
<span class="token property">box-shadow</span><span class="token punctuation">:</span> 1px 1px 4px black<span class="token punctuation">;</span>
<span class="token selector"><span class="token parent important">&</span>:active, <span class="token parent important">&</span>:visited </span><span class="token punctuation">{</span>
<span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">i </span><span class="token punctuation">{</span>
<span class="token property">margin-top</span><span class="token punctuation">:</span> 31%<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Ok, so whats going on here. Well we're using border-radius to make our class round. We're giving it a width and height of <code>50px</code>. We're setting its position to fixed percentages off the bottom right. This will help make it scale better for different screen sizes. Finally we adjust the margin for the hamburger icon, and make the icon white.</p>
<p>This works great, except that the menu does not support the back button in the browser. I added the following snippet of javascript which made sure we cover that case.</p>
<pre class="language-js" tabindex="0"><code class="language-js"> <span class="token keyword">if</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>hash<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"hamMenu"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token function">showNav</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span><span class="token punctuation">{</span>
<span class="token function">hideNav</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>So thats basically it. Honestly, I'm happy with the way it came out. I'm sure there could be better way's to do this. With the overall lack of googling ability this is what I came up with, and I like it!</p>
Working with docker on windows 7, 82018-02-22T07:59:07Zhttps://blog.terrible.dev/blog/Working-with-docker-on-windows-7-8/<p>So its no secret I'm a docker fan. In-fact, I've been a fan of docker since the early betas. I work in an office, with a high amount of people running some form of windows, and I hear this quote quite a lot.</p>
<blockquote>
<p>Docker for windows only supports windows 10, you can't use docker on windows 7, 8, etc.</p>
</blockquote>
<!-- more -->
<p>Now people in the docker community know you can run docker on many operating systems. The docker toolkits for windows and mac provide GUI abstractions over the docker services. However, we can use the actual tools these GUI wrappers use to work with docker containers. In the early days of docker, a tool existed called <code>boot2docker</code>. This was replaced with a newer tool called <code>docker-machine</code>. These are the actual tools the docker toolkits use to provision linux virtual machines to help you work with containers.</p>
<h2>Setting up your environment</h2>
<p>You will need <code>docker</code>, <code>docker-machine</code>, and <code>docker-compose</code> in your path. These are simple executables, the easiest way to get them is to use <a href="https://chocolatey.org">chocolatey</a> a package manager for windows (think brew, apt-get, etc.). You will also need a hypervisor (tool that can run virtual machines). In this case I'm using Virtualbox, but you may use Hyper-V, etc. <a href="https://www.virtualbox.org/">Virtual box</a> is a lightweight hypervisor (it can run vm's) created by oracle.</p>
<pre class="language-powershell" tabindex="0"><code class="language-powershell">choco install <span class="token operator">-</span>y docker docker-machine docker-compose
choco install <span class="token operator">-</span>y virtualbox</code></pre>
<p>Ok, next you will need to use docker-machine to create you a virtual machine running Linux. We'll give it the name mydock, you can name it however you like.</p>
<pre><code>docker-machine create --driver virtualbox mydock
</code></pre>
<p>Now when we open a new terminal every time we'll need <code>docker-machine</code> to configure our shell with some environmental variables. The env command will spit out a script to set the variables for your shell. You can pipe this to <code>invoke-expression</code> in powershell, or copy and execute the output in <code>cmd.exe</code></p>
<p>powershell:</p>
<pre class="language-powershell" tabindex="0"><code class="language-powershell">docker-machine env mydock <span class="token punctuation">|</span> <span class="token function">invoke-expression</span></code></pre>
<p>Now you have done that, you should be up and running. Since you are running a virtual machine, its likely it will stop when you reboot your computer. You can start it with <code>docker-machine start mydock</code>.</p>
Taking time away2017-08-21T21:09:13Zhttps://blog.terrible.dev/blog/Taking-time-away/<p>In case you haven't notice, this blog has not gotten updates much this summer. Some people have even noticed the overall lack of activity on my GitHub. Emails have gone, several weeks unanswered.</p>
<!-- more -->
<blockquote>
<p>People have been reaching out to me, asking if I was ok. Some people seem to have thought I was having issues at home, or with my health.</p>
</blockquote>
<p>For those of you whom said something. I'd like to say, thanks for caring about me. Over the last 6 weeks, I have been on holiday. I take huge vacations every Summer. I use it as a time to relax, and reflect.</p>
<p><img src="https://blog.terrible.dev/blog/Taking-time-away/thumbnail.PNG" alt="my GitHub commit history"></p>
<blockquote>
<p>I was my worst enemy when it came to relaxing on holiday</p>
</blockquote>
<p>At one time when I took holidays. I use to bring my laptop, and just essentially coded from a remote location. I myself was the barrier to my own enjoyment. I would come back, and would never feel rested. Eventually I came up with some techniques to unplug, and I figured I'd share them with you.</p>
<h2>Notifications</h2>
<p>Some people have asked me how I <em>unplug</em>. To start I must tell you what gear I bring with me when I travel. I usually bring my cell phone, a surface tablet, and lately my Nintendo switch.</p>
<p>In android you can heavily curate which apps can send notifications <code>settings -> notifications -> turn off certain apps</code> I usually turn off all email applications, all e-commerce apps such as amazon. I log off any slack teams related to work. This means I do not get notifications for email, advertisements for sellers, or communications related to work.</p>
<h2>Do not disturb</h2>
<p>Most cell phones have a do not disturb feature. In android this works, very similar to iPhone. When I go on holiday I turn the feature on. I mark calls from close family as allowed. I also designate a select few co-workers as able to call me. Like most people in the software industry, I should be contactable incase of major disasters. However, I don't just let anyone call me. The people whom can call know they are standing between me and the business while I am away. They are people that should be able to handle most problems. I documented whom they are in my out of office message, and on an internal page about myself.</p>
<h2>Browsers</h2>
<p>I am an avid user of Firefox. Like chrome, Firefox lets you log into Firefox to sync history, bookmarks, and cookies. When I go on holiday I logoff my browsers, and then clear all local storage. This makes it hard for me to accidentally login to my email, or GitHub. By placing this barrier up, it prevents me from being my own enemy while I am gone. This ensures I don't rob myself of a holiday.</p>
<h2>Computer</h2>
<p>This is the most important part of the trip. Now I must have a computer for my own sanity. However, before leaving for my trip I wipe my laptop completely. I then do not install anything other than Firefox. No programming tools, no project documents, no nothing. I have no access to files, or ssh keys. This is again to place barriers upon myself. I'm going on holiday, not to sit around and work. I might put movies on my laptop, and Netflix. However I'm not about to load a bunch of work documents onto it.</p>
<h2>In closing</h2>
<p>I have had many people reach out. People have explained to me how burnt out they are. I've seen many friends jump employers. I can assert that <strong>you are your best advocate</strong>. You need to stand up, and shout when your are burnt out; Or try to get others to shout for you. Without proper rest, and time away, you will not be ready to tackle your businesses needs. Any business worth its weight, will gladly let you go on holiday, and any that do not, are not worth working for. <strong>Find employers that value you</strong> as a person. Those employers are not always the best paying, but being treated as a human being is head and shoulders above money. Your family, and your wellbeing are more important than the company you work for.</p>
Building dotnet core apps, and packages with gulp2017-05-04T16:59:43Zhttps://blog.terrible.dev/blog/Building-dotnet-core-apps-and-packages-with-gulp/<p>Here we are, its 2017 dotnet core is out, and finally dotnet has a proper cli. In a previous post <a href="https://blog.terrible.dev/Exploring-the-dotnet-cli/">we explored the new cli</a>. In short you can use the dotnet cli to build, test, package, and publish projects. However sometimes just using the cli is not enough. Sometimes, you land in a place where you have many projects to compile, test, and package.</p>
<!-- more -->
<p>You sometimes need a more complex tool to help you manage your versions, and set the right properties as part of your builds. This is where a tasking system like <a href="http://gulpjs.com/">gulp</a> can help. Now gulp is not the only task engines. There are Rake, Cake, MSBuild, etc. Plenty to pick from. I personally use gulp a lot, because I'm a web developer. I need a JS based system, to help me run the <a href="https://babeljs.io">babels</a>, and <a href="https://webpack.github.io/docs/">webpacks</a> of the world.</p>
<h2>Getting started</h2>
<p>So recently I've been working hard to add the dotnet cli's functionality to gulp. Essentially <a href="https://github.com/Janus-vistaprint/gulp-dotnet-cli">I authored</a> some gulp modules to help you build and package a dotnet application.</p>
<p>So to begin you should install a modern version of node (6+). Run <code>npm init</code> which will make you a package.json file. Now run <code>npm install --save-dev gulp gulp-dotnet-cli</code>. This will pull down gulp, and my plugin. Now we have to install the gulp cli to our path <code>npm install -g gulp-cli</code></p>
<h2>First gulp task</h2>
<p>To begin create a file called <code>gulpfile.js</code> in the root of your project. Add the following 2 lines.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">let</span> gulp <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token punctuation">{</span>restore<span class="token punctuation">,</span> build<span class="token punctuation">,</span> test<span class="token punctuation">,</span> pack<span class="token punctuation">,</span> publish<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp-dotnet-cli'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>The first line just requires in gulp, the second line pulls down my gulp module. My module has 5 actions. Restore which will run <code>dotnet restore</code> or essentially download nuget packages. Build which runs <code>dotnet build</code>, this compiles out the project. <code>Test</code> runs the unit tests. <code>pack</code> will convert a csproj to a nuget package, and <code>publish</code> will publish the project to the local file system. Each action has optional parameters <a href="https://github.com/Janus-vistaprint/gulp-dotnet-cli/blob/master/docs/index.md">documented here</a>.</p>
<p>Now lets make a restore task</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">let</span> gulp <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token punctuation">{</span>restore<span class="token punctuation">,</span> build<span class="token punctuation">,</span> test<span class="token punctuation">,</span> pack<span class="token punctuation">,</span> publish<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp-dotnet-cli'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'restore'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.csproj'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">restore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>This is simple, find all csproj files and run restore. You could also use sln files instead of csproj's.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">let</span> gulp <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token punctuation">{</span>restore<span class="token punctuation">,</span> build<span class="token punctuation">,</span> test<span class="token punctuation">,</span> pack<span class="token punctuation">,</span> publish<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp-dotnet-cli'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'restore'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.sln'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">restore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Now lets add a build.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">let</span> gulp <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token punctuation">{</span>restore<span class="token punctuation">,</span> build<span class="token punctuation">,</span> test<span class="token punctuation">,</span> pack<span class="token punctuation">,</span> publish<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp-dotnet-cli'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'restore'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.sln'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">restore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'build'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'restore'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token comment">//this could be **/*.sln if you wanted to build solutions</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.csproj'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Very easy, and simple. Glob up the csproj files and compile them out. In the build task, the array containing restore, is stating that build depends on restore.</p>
<h2>Nuget packages</h2>
<p>Ok so here we go, this is when we start doing cool things. We want to build all of our projects with a version number, and then make a nuget package with the same version. We want to build in <code>Release</code> mode, and we want all packages in an nupkgs directory. At the end we should push our nuget packages to a custom myget feed.</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">let</span> gulp <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> <span class="token punctuation">{</span>restore<span class="token punctuation">,</span> build<span class="token punctuation">,</span> test<span class="token punctuation">,</span> pack<span class="token punctuation">,</span> publish<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp-dotnet-cli'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> version <span class="token operator">=</span> <span class="token string">'1.0.0'</span><span class="token punctuation">;</span> <span class="token comment">//you could read a git tag here</span>
<span class="token keyword">let</span> configuration <span class="token operator">=</span> <span class="token string">'Release'</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'restore'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.sln'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">restore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'build'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'restore'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token comment">//this could be **/*.sln if you wanted to build solutions</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.csproj'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">version</span><span class="token operator">:</span> version<span class="token punctuation">,</span> <span class="token literal-property property">configuration</span><span class="token operator">:</span> configuration<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'pack'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'build'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.csproj'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">pack</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">version</span><span class="token operator">:</span> version<span class="token punctuation">,</span>
<span class="token literal-property property">configuration</span><span class="token operator">:</span> configuration<span class="token punctuation">,</span>
<span class="token literal-property property">output</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token function">cwd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'nupkgs'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//push nuget packages to a server</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'push'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'pack'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'nupkgs/**.nupkg'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">apiKey</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NUGET_API_KEY</span><span class="token punctuation">,</span> <span class="token comment">//my nuget api key from an environment variable</span>
<span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token string">'https://myget.org/f/myfeedurl'</span> <span class="token comment">//a custom nuget feed</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h2>Docker + Dotnet core + gulp</h2>
<p>Ok so lets say you have added a docker file to your projects directory, and you have added <code><None include="Dockerfile"></code> to your csproj's item group.</p>
<pre class="language-dockerfile" tabindex="0"><code class="language-dockerfile"><span class="token instruction"><span class="token keyword">FROM</span> microsoft/aspnetcore:1.1.1</span>
<span class="token instruction"><span class="token keyword">WORKDIR</span> /app</span>
<span class="token instruction"><span class="token keyword">COPY</span> . .</span>
<span class="token instruction"><span class="token keyword">ENTRYPOINT</span> [<span class="token string">"dotnet"</span>, <span class="token string">"DotnetTerra.dll"</span>]</span>
</code></pre>
<p>First we need a task to publish our website to a folder, compiled.</p>
<pre class="language-js" tabindex="0"><code class="language-js">gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'publish'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'restore'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span>
gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.csproj'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">publish</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">configuration</span><span class="token operator">:</span> configuration<span class="token punctuation">,</span>
<span class="token literal-property property">version</span><span class="token operator">:</span> version<span class="token punctuation">,</span>
<span class="token literal-property property">output</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token function">cwd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'output'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre>
<p>next we need to compile our docker container. run <code>npm install --save-dev child-process-promise</code> this is a simple package that converts all child process node calls to promises. Promises are like a callback, but with a nicer syntax. Note that here we are tagging the container with the same version as our package</p>
<pre class="language-js" tabindex="0"><code class="language-js">
<span class="token keyword">const</span> spawn <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'child-process-promise'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>spawn<span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'docker:compile'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'publish'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span>
<span class="token function">spawn</span><span class="token punctuation">(</span><span class="token string">'docker'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'build'</span><span class="token punctuation">,</span> <span class="token string">'-t'</span><span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">myapp-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>version<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token string">'output'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">stdio</span><span class="token operator">:</span><span class="token string">'inherit'</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>In total your file will probably look like this:</p>
<pre class="language-js" tabindex="0"><code class="language-js"><span class="token keyword">const</span> spawn <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'child-process-promise'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>spawn<span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span>restore<span class="token punctuation">,</span> test<span class="token punctuation">,</span> build<span class="token punctuation">,</span> publish<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp-dotnet-cli'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'restore'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'clean'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span>
gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.csproj'</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">restore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'build'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'restore'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span>
gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'**/*.csproj'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">read</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">build</span><span class="token punctuation">(</span>
<span class="token punctuation">{</span>
<span class="token literal-property property">configuration</span><span class="token operator">:</span> configuration<span class="token punctuation">,</span>
<span class="token literal-property property">version</span><span class="token operator">:</span> version
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'publish'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'build'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span>
gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token string">'src/DotnetTerra/DotnetTerra.csproj'</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">publish</span><span class="token punctuation">(</span>
<span class="token punctuation">{</span>
<span class="token literal-property property">configuration</span><span class="token operator">:</span> configuration<span class="token punctuation">,</span>
<span class="token literal-property property">version</span><span class="token operator">:</span> version<span class="token punctuation">,</span>
<span class="token literal-property property">output</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span><span class="token function">cwd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'output'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'docker:compile'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'publish'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span>
<span class="token function">spawn</span><span class="token punctuation">(</span><span class="token string">'docker'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'build'</span><span class="token punctuation">,</span> <span class="token string">'-t'</span><span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">myapp-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>version<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token string">'output'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">stdio</span><span class="token operator">:</span><span class="token string">'inherit'</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Gulp can easily lets you add more tasks, and you could easily create a task to tag and push the container.</p>
<h2>Conclusion</h2>
<p>In Conclusion, with this module you can easily package any dotnet core based project with gulp. This will work on any project that is compatible with the dotnet cli. By using a task framework like gulp you can ensure your artifacts are all tagged with the same versions, and have the same set of configurations. You can find documentation, and samples <a href="https://github.com/Janus-vistaprint/gulp-dotnet-cli">in github</a>.</p>
Precompiling razor views in dotnet core2017-04-04T09:28:26Zhttps://blog.terrible.dev/blog/Precompiling-razor-views-in-dotnet-core/<p>Recently I had heard <a href="https://github.com/aspnet/live.asp.net/blob/dev/src/live.asp.net/live.asp.net.csproj#L8">live.asp.net</a> had started to precompile the razor views. I figured I'd dig in and quickly figure out how to do it.</p>
<!-- more -->
<p>Honestly its quite simple. Add the <code>Microsoft.AspNetCore.Mvc.Razor.ViewCompilation</code> package to your project. You can do this through the dotnet cli <code>dotnet add package Microsoft.AspNetCore.Mvc.Razor.ViewCompilation</code> or through the visual studio package explorer <code>install-package Microsoft.AspNetCore.Mvc.Razor.ViewCompilation</code>.</p>
<p>Then simply add <code><MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish></code> and <code><PreserveCompilationContext>true</PreserveCompilationContext></code> to your csproj file's property group. Thats it. You will now precompile your razor views on publish. You should end up with something like the following.</p>
<pre class="language-xml" tabindex="0"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Project</span> <span class="token attr-name">Sdk</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Microsoft.NET.Sdk.Web<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>PropertyGroup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>TargetFramework</span><span class="token punctuation">></span></span>netcoreapp1.1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>TargetFramework</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>PreserveCompilationContext</span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>PreserveCompilationContext</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>MvcRazorCompileOnPublish</span> <span class="token attr-name">Condition</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">'</span>$(Configuration)' == 'Release'<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>MvcRazorCompileOnPublish</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>PropertyGroup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ItemGroup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>PackageReference</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Microsoft.AspNetCore<span class="token punctuation">"</span></span> <span class="token attr-name">Version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.1.1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>PackageReference</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Microsoft.AspNetCore.Mvc<span class="token punctuation">"</span></span> <span class="token attr-name">Version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.1.2<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>PackageReference</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Microsoft.AspNetCore.Mvc.Razor.ViewCompilation<span class="token punctuation">"</span></span> <span class="token attr-name">Version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.1.0<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>PackageReference</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Microsoft.AspNetCore.StaticFiles<span class="token punctuation">"</span></span> <span class="token attr-name">Version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.1.1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>PackageReference</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Microsoft.Extensions.Logging.Debug<span class="token punctuation">"</span></span> <span class="token attr-name">Version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.1.1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>PackageReference</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Microsoft.VisualStudio.Web.BrowserLink<span class="token punctuation">"</span></span> <span class="token attr-name">Version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.1.0<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ItemGroup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Project</span><span class="token punctuation">></span></span></code></pre>
<h2>A small step further</h2>
<p>Ok, so I usually compile my app in debug mode for my dev environment. This is for a few reasons, but mostly for debugging purposes. However I often build in release mode for my staging/release environments. We can add a condition to our Razor compilation to only compile in Release mode. This will give us the added benefit of only baking compiled razor for environments built outside of debug. <code><MvcRazorCompileOnPublish Condition="'$(Configuration)' == 'Release'">true</MvcRazorCompileOnPublish></code>. Thats it! Since MSBuild's xml is well thought out, we can alter its behaviors quite easily.</p>
Visual Studio 2017, best extensions on launch2017-03-24T18:35:13Zhttps://blog.terrible.dev/blog/VS-2017-best-extensions-on-launch/<p>When Visual studio 2015 launched, I wrote a blog post titled <a href="https://blog.terrible.dev/vs-2015-getting-resharper-experiance-without-resharper/">Resharper without Resharper</a>. This was clearly aimed at giving people the ability in 2015 to divorce themselves from the very expensive product. In writing the post however, I didn't realize people would just want a low down on cool vs2015 extensions.</p>
<!-- more -->
<p>Since the launch of 2017, I decided to put together my favorite extensions again.</p>
<h2>Recap</h2>
<p>Here were my mentioned plugins of 2015:</p>
<ul>
<li><a href="http://vsrefactoringessentials.com/">Refactoring Essentials</a> - Still valid in 2017, great set of refactors</li>
<li><a href="http://code-cracker.github.io/">Code Cracker</a> - Another one still valid in 2017, great package to do code analysis, and improvements</li>
<li><a href="http://www.codemaid.net/">Code Maid</a> - Great for cleaning up source code, I'd use this still</li>
<li><a href="https://vlasovstudio.com/continuous-formatting/">Continuous Formatting</a> - I wouldn't use this as much, stick with code maid. This is a paid product, and code maid is free.</li>
<li><a href="http://vswebessentials.com/">Web Essentials</a> - Still a top tool for any webdev's</li>
</ul>
<h2>Razor tooling extension</h2>
<p>Ok so, incase you didn't hear. The AspNet team was unable to get all the razor tooling done in time to ship with VS 2017! Don't fret though, they have published an extension called the <a href="https://marketplace.visualstudio.com/items?itemName=ms-madsk.RazorLanguageServices">Razor tooling extension</a>. This provides a very rich experience with razor, and will ultimately let you refactor multiple razor files with ease! The biggest feature of this, is the TagHelper tools. This extension understands what TagHelpers you have in scope, and appropriately highlights, them and auto-completes the properties.</p>
<h2>Project file tools</h2>
<p>Ok so this ones name is a little ambiguous. The <a href="https://marketplace.visualstudio.com/items?itemName=ms-madsk.ProjectFileTools">project file tools</a> extension allows your nuget packages to auto complete when editing the new csproj files, akin to what we had with project.json. In the new world, your nuget packages are declared inside the csproj, and this just provides intellisense on what packages, and version are available. This is an awesome experience, to keep me inside VS, and not in <a href="https://nuget.org">nuget.org</a></p>
<h2>Roslynator</h2>
<p>Ok, here is a cool one, both in name, and functionality. <a href="https://marketplace.visualstudio.com/items?itemName=josefpihrt.Roslynator2017">Roslynator</a> is another refactoring/code analysis plugin that uses roslyn under the hood. This provides over 170 different analyzers, and over 180 refactorings, all for c#. I've been using this extension for a little while, and I've been blown away! Both by refactoring features, and the overall performance. Extensions such as this one, usually are less performant. I never noticed any slowdowns, or had this plugin ever crash. You can turn on and off features, through an options dialog. Great <a href="https://github.com/JosefPihrt/Roslynator">documentation on github</a>, lots of options, and a cool name all add up to a sweat experience.</p>
<h2>Productivity Power Tools!</h2>
<p>Ok so I know I'm late to the game on this one. I'll be honest, I used this before, but didn't blog about it. <a href="https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.ProductivityPowerPack2017">Productivity Power Tools</a> is a cool extension and in this release, it just installs a bunch of separate extensions. They broke apart the 1 extension, and made this extension a meta extension. This is so the team could rev each individual component.</p>
<p>Some of my favorites are the <a href="https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MatchMargin">match margin</a> which when text is highlighted, shows all lines in the margin where the same text occurs. <a href="https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.CopyAsHtml">Copy as HTML</a> is a pretty cool extension that lets you copy in html, with proper formatting. Finally <a href="https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.AlignAssignments">Align Assignments</a> is my all time favorite in this bundle. This aligns multiple declarations so they are all formatted the same.</p>
<h2>Roaming extensions!</h2>
<p>The biggest new feature in vs 2017 is that your extensions can now "sync" between instances of VS. Under <code>tools -> Extensions and updates -> Roaming Extensions Manager</code> you can now pick extensions to "roam". This is an awesome tool, because you can now have the same development experience even under a brand new install! Your extensions finally go with you.</p>
<p><img src="https://blog.terrible.dev/blog/VS-2017-best-extensions-on-launch/extmgr.PNG" alt="roaming extension manager"></p>
<h2>Summary</h2>
<p>There are a ton of new extensions, go use them. Let me know in the comments below what your favorite extension is!!!!</p>
Making alexa skills in .net2017-03-13T15:32:56Zhttps://blog.terrible.dev/blog/Making-alexa-skills-in-net/<p>Ok so I've been in the alexa skills market recently, and obviously amazon wants you to use AWS Lambda for your skills. If you are like me, you have a ton of stuff in azure app service (the PaaS of azure). Azure app service supports nodejs, java, python, and of course .net. The two sdk's amazon ships (node, java) do not tie in with a web stack, and are obviously thought of as being used with Lambda.</p>
<!-- more -->
<p>When you don't host your code in aws, or use the alexa sdk's you must use crypto magic to authenticate the requests from amazon, are actually from amazon. I was going to use the ruby sdk's the community has put out, but I didnt see any code that verified requests. I noticed the <a href="https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET">alexa .net sdk</a> supports verifying requests from amazon, and since its .net I know it will work great in azure.</p>
<p>Getting Started:</p>
<p>Ok, so the alexa .net sdk is for the full framework only, and its built for webapi. The best way to get going is in visual studio <code>file -> new project -> ASP.NET Web Application .net framework</code> A dialog comes up, and I picked <code>Azure API App</code>.</p>
<p><img src="https://blog.terrible.dev/blog/Making-alexa-skills-in-net/dialog.PNG" alt="dialog picker"></p>
<p>Now you have an empty webapi project. We don't need swashbuckle/swagger so lets get rid of that</p>
<p>In the package manager console <code>Tools -> NuGet Package Manager -> Package Manager Console</code></p>
<p>run <code>uninstall-package Swashbuckle</code>
run <code>uninstall-package Swashbuckle.Core</code></p>
<p>delete <code>App_Start/SwaggerConfig.cs</code></p>
<p>now go to <code>WebApiConfig.cs</code> and delete this block of code, we'll stick with attribute routing only.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
config<span class="token punctuation">.</span>Routes<span class="token punctuation">.</span><span class="token function">MapHttpRoute</span><span class="token punctuation">(</span>
<span class="token named-parameter punctuation">name</span><span class="token punctuation">:</span> <span class="token string">"DefaultApi"</span><span class="token punctuation">,</span>
<span class="token named-parameter punctuation">routeTemplate</span><span class="token punctuation">:</span> <span class="token string">"api/{controller}/{id}"</span><span class="token punctuation">,</span>
<span class="token named-parameter punctuation">defaults</span><span class="token punctuation">:</span> <span class="token keyword">new</span> <span class="token punctuation">{</span> id <span class="token operator">=</span> RouteParameter<span class="token punctuation">.</span>Optional <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now Rename the <code>ValuesController</code> to <code>AlexaController</code> and delete all the methods in the file.</p>
<p>Your AlexaController should look like this:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token keyword">using</span> <span class="token namespace">System</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Collections<span class="token punctuation">.</span>Generic</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Linq</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Net</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Net<span class="token punctuation">.</span>Http</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Http</span><span class="token punctuation">;</span>
<span class="token keyword">namespace</span> <span class="token namespace">WebApplication6<span class="token punctuation">.</span>Controllers</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AlexaController</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ApiController</span></span>
<span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>First lets install the alexa sdk. <code>Install-Package AlexaSkillsKit.NET</code></p>
<p>The sdk requires us to make a class that inherits from speechlet. Speechlet, the base class gives us everything we need to make a skill. The base class has a bunch of methods we can override. We usually have to return a SpeechletResponse which is simply an object that describes to alexa what to say back. Usually this is just some simple text to read back to the user.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AlexaResponse</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Speechlet</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name">SpeechletResponse</span> <span class="token function">OnIntent</span><span class="token punctuation">(</span><span class="token class-name">IntentRequest</span> intentRequest<span class="token punctuation">,</span> <span class="token class-name">Session</span> session<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//this will fire when your users pick an intent for example if your bot is named tommy and you say alexa ask tommy whats the weather today this will fire the weather intent</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name">SpeechletResponse</span> <span class="token function">OnLaunch</span><span class="token punctuation">(</span><span class="token class-name">LaunchRequest</span> launchRequest<span class="token punctuation">,</span> <span class="token class-name">Session</span> session<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//this will fire on the root of your alexa skill</span>
<span class="token comment">//for example if your skill is named tommy, and you just say alexa ask tommy, alexa open tommy, alexa tommy. This will fire with no commands</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnSessionEnded</span><span class="token punctuation">(</span><span class="token class-name">SessionEndedRequest</span> sessionEndedRequest<span class="token punctuation">,</span> <span class="token class-name">Session</span> session<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnSessionStarted</span><span class="token punctuation">(</span><span class="token class-name">SessionStartedRequest</span> sessionStartedRequest<span class="token punctuation">,</span> <span class="token class-name">Session</span> session<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//there are mechanisms to handle sessions in the sdk if you need it.</span>
<span class="token punctuation">}</span></code></pre>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">SpeechletResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//a sample response</span>
OutputSpeech <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">PlainTextOutputSpeech</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Text <span class="token operator">=</span> <span class="token string">"Hi, my name is tommy"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
ShouldEndSession <span class="token operator">=</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Ok now we need to add an endpoint to take traffic from amazon on. Amazon will do a post with a json document to <code>/</code> so we need to allow that. We should also make a livecheck interface for get's and head requests.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AlexaController</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ApiController</span></span>
<span class="token punctuation">{</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Route</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HttpGet</span></span><span class="token punctuation">]</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HttpHead</span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token return-type class-name">IHttpActionResult</span> <span class="token function">root</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">Ok</span><span class="token punctuation">(</span><span class="token string">"Im Alive"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Route</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HttpPost</span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token return-type class-name">HttpResponseMessage</span> <span class="token function">Post</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">AlexaResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">GetResponse</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>Request<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>That is basically it. the SDK will handle verifying the requests from amazon, and will call the overriden methods to deal with your alexa skill. Now you can deploy this to something like azure app services, and register yours skill in <a href="https://developer.amazon.com">the developer console</a>. Once registered, the skill should be avalible to you assuming you signed into your alexa device with the same account. You can see <a href="https://github.com/TerribleDev/alexa-excuse.net">a working sample here</a>.</p>
Exploring the dotnet cli2017-03-07T21:30:38Zhttps://blog.terrible.dev/blog/Exploring-the-dotnet-cli/<p>Now that dotnet core tools have been released I thought it would be good to look into the dotnet cli. This is a new command line interface to build, manage, compile and run <code>dotnet core</code> based applications</p>
<!-- more -->
<h2>Getting started</h2>
<p>You will need to install the latest version of dotnet core. Simply install it at <a href="https://dot.net/">dot.net</a>. You can find installers for Mac, Windows, or Linux. You should be able to read the docs and get going.</p>
<h2>Now what?</h2>
<p>Like most command lines you can call <code>dotnet --help</code> and get a list of main functions.</p>
<pre><code>C:\projects\awesome> dotnet --help
.NET Command Line Tools (1.0.1)
Usage: dotnet [host-options] [command] [arguments] [common-options]
Arguments:
[command] The command to execute
[arguments] Arguments to pass to the command
[host-options] Options specific to dotnet (host)
[common-options] Options common to all commands
Common options:
-v|--verbose Enable verbose output
-h|--help Show help
Host options (passed before the command):
-d|--diagnostics Enable diagnostic output
--version Display .NET CLI Version Number
--info Display .NET CLI Info
Commands:
new Initialize .NET projects.
restore Restore dependencies specified in the .NET project.
build Builds a .NET project.
publish Publishes a .NET project for deployment (including the runtime).
run Compiles and immediately executes a .NET project.
test Runs unit tests using the test runner specified in the project.
pack Creates a NuGet package.
migrate Migrates a project.json based project to a msbuild based project.
clean Clean build output(s).
sln Modify solution (SLN) files.
Project modification commands:
add Add items to the project
remove Remove items from the project
list List items in the project
Advanced Commands:
nuget Provides additional NuGet commands.
msbuild Runs Microsoft Build Engine (MSBuild).
vstest Runs Microsoft Test Execution Command Line Tool.
</code></pre>
<p>Lets first make a new project. This is very simple, from the list of commands we clearly have a new command. Lets see what we have for options <code>dotnet new --help</code></p>
<pre><code>C:\projects\myproj> dotnet new --help
Template Instantiation Commands for .NET Core CLI.
Usage: dotnet new [arguments] [options]
Arguments:
template The template to instantiate.
Options:
-l|--list List templates containing the specified name.
-lang|--language Specifies the language of the template to create
-n|--name The name for the output being created. If no name is specified, the name of the current directory is used.
-o|--output Location to place the generated output.
-h|--help Displays help for this command.
-all|--show-all Shows all templates
Templates Short Name Language Tags
----------------------------------------------------------------------
Console Application console [C#], F# Common/Console
Class library classlib [C#], F# Common/Library
Unit Test Project mstest [C#], F# Test/MSTest
xUnit Test Project xunit [C#], F# Test/xUnit
ASP.NET Core Empty web [C#] Web/Empty
ASP.NET Core Web App mvc [C#], F# Web/MVC
ASP.NET Core Web API webapi [C#] Web/WebAPI
Solution File sln Solution
</code></pre>
<p>So it appears we can get a console app, class library, unit tests, aspnet core, webapp the list goes on and on. Lets do <code>dotnet new mvc</code>.</p>
<p>The results are a complete mvc application. Now lets restore the nuget packages with <code>dotnet restore</code>. Afterwards lets run the project with <code>dotnet run</code>. The results should be the app running on port 5000.</p>
<p><img src="https://blog.terrible.dev/blog/Exploring-the-dotnet-cli/mvc-project.PNG" alt="An mvc project"></p>
<p>Now I'd like to add my favorite statsd client <a href="https://github.com/TryStatsN/StatsN">StatsN</a>. This is as simple as running <code>dotnet add package StatsN</code>. To get a directory with our application ready to be ran we can run <code>dotnet publish</code> and one will be created in ./bin/Debug/netcoreapp1.1/publish/ If we want to compile in release mode we need to specify <code>dotnet publish -c Release</code>.</p>
<p>Finally we can even use the cli to create a solution file <code>dotnet new sln</code> and add we can add projects with <code>dotnet new sln add <MyProject></code></p>
<p>Overall the cli is simple and easy to use. The <code>--help</code> command works on all verbs no matter how deep, and can be very handy. The second major version of the CLI planned, includes the ability to globally install tools. This will allow any developer to extend the dotnet cli with their own code. Sometime soon you may be able to <code>dotnet tool install awesome</code> and then <code>dotnet awesome</code>.</p>
<p>Overall I'm both impressed, and speechless with how fast microsoft has moved its almost 20 year old platform into a very modern environment to work in. The new csproj files are easy to understand, and work 100% with my old csproj files. Backward compatibility means I can just move my stuff forward slowly, and don't have to port 10 years of work.</p>
VS 2017, and dotnet core tools. Today will be a historic day2017-03-07T21:09:05Zhttps://blog.terrible.dev/blog/VS-17-and-dotnet-core-tools-Today-will-be-a-historic-day/<p>Today marks the release of Visual Studio 2017, and with it the final release of the tools for dotnet core. This means as of today you can build, test, and deploy an application completely supported by microsoft. Not just the runtimes, but the tooling as well. The CLI for dotnet core has been finalized, and its awesome. The csproj system has been revitalized. New csproj's can be created, and are fully compatible with the old. Visual studio 2017 has finally released. This is probably the greatest version of visual studio ever created. Finally VS has gone from a slow, archaic editor, to a fast moving IDE. An IDE with a DevOps-First Cloud-First mentality. An IDE ready to tackle today's modern challenges.</p>
<!-- more -->
<h2>Visual studio 2017</h2>
<p>So I bet you are wondering, how is VS2017 improved. When you first boot the vs2017 installer you are immediately hit with a very sleek UI for the installer. The installer actually has reasonable install sizes for scenarios like nodejs only.</p>
<p><img src="https://blog.terrible.dev/blog/VS-17-and-dotnet-core-tools-Today-will-be-a-historic-day/vs.PNG" alt="vs 2017 installer"></p>
<p>VS2017 can understand which lines of code are linked to your unit tests. As you alter, or refactor code VS can run the tests. This can allow the editor to show checkmarks or red <code>x</code>'s This is huge as it can seemingly provide constant feedback to developers during development.</p>
<p>One of my huge annoyances with older versions of visual studio was the inability to edit csproj files. In the past to edit a csproj file you must "unload" the project, edit the file, and then reload the project. Traditionally this was a huge source of contention for me. I was unable to quickly edit my project files, and thus the build behavior. In the new version of visual studio, csproj files can be edited on the fly. No more mucking around loading, unloading, reloading projects. Just right click, edit, done.</p>
<h2>dotnet has a real CLI now!</h2>
<p>One of my biggest gripes about dotnet for many years was the overall lack of CLI tools. Everything was hidden behind black box GUI's and weird COM calls. Installing nuget packages felt like a second class citizen, and was almost not do-able outside visual studio.</p>
<p>I have a more <a href="https://blog.terrible.dev/Exploring-the-dotnet-cli/">extensive post on the subject</a>. I'd recomend you check it out. However here is a taste.</p>
<blockquote>
<p>Even during <code>project.json</code> days you could not just say install xyz package into my project. Instead you had to fumble around with files</p>
</blockquote>
<p>In the dotnet core cli you can say <code>dotnet add package <RandomPackageHere></code> and the package will promptly be installed into your project. No VS required, and no mucking about. This is the same as <code>npm install --save <RandomPackageHere></code>. Want a new web project? <code>dotnet new web</code> simple.</p>
<h2>In closing</h2>
<p>With these new announcements Microsoft is making a very bold push at once again being the top company for developers. They have listened to the feedback, they are rapidly evolving, and re-birthing themselves. Some have said over the last couple of years that they don't recognize this new Microsoft. I 100% agree with this sentiment. They have gone from having what appeared to be a legacy development system. To a modern cross platform technology stack. A stack that is rapidly being adopted by many developers. A stack that can truly be cloud native. Microsoft currently stands as the largest contributor to open source. Something just a few short years ago, they viewed as a bad idea. This astounding achievement did not come overnight, but has taken several years. However this new Microsoft will be a force to be reckoned with.</p>
Making a minimal webapp with dotnet core2017-03-02T01:11:18Zhttps://blog.terrible.dev/blog/making-a-minimal-webapp-with-dotnet-core/<p>Recently I wanted to make myself a short url host. Really, I made this not to make short urls, but to make memorable urls for myself.</p>
<!-- more -->
<blockquote>
<p>I wanted to say goto <a href="https://aka.terribledev.io/docker101">aka.terribledev.io/docker101</a> for my docker101 class</p>
</blockquote>
<p>This is clearly a very simple webapp. Basically a dictionary of path's to 301's. Probably the simplest WebApplication anyone can make. <a href="https://github.com/terribledev/aka.terribledev.io">So I made it</a>.</p>
<p>So, I'm sure you are wondering. Well why am I reading this blog? Well, my app does not use mvc, or any web framework. My app uses the mvc core 1.0 router as middleware. This was talked about a while back on an episode of <a href="https://live.asp.net">live.asp.net</a>.</p>
<p>I first just used the <a href="https://www.npmjs.com/package/generator-aspnet">aspnet yeoman generator</a>, asking for webapi. I then deleted the only controller I was given, and got rid of most of the mvc packages with the exception of <code>Microsoft.AspNetCore.Routing</code>. I then just modified my <code>Startup.cs</code> file to look like below.</p>
<p>Essentially I add the routing package to the container, and then have have the app use the router mapping <code>docker101</code> to the proper url. Easy right?</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token comment">// This method gets called by the runtime. Use this method to add services to the container.</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ConfigureServices</span><span class="token punctuation">(</span><span class="token class-name">IServiceCollection</span> services<span class="token punctuation">)</span>
services<span class="token punctuation">.</span><span class="token function">AddRouting</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Configure</span><span class="token punctuation">(</span><span class="token class-name">IApplicationBuilder</span> app<span class="token punctuation">,</span> <span class="token class-name">IHostingEnvironment</span> env<span class="token punctuation">,</span> <span class="token class-name">ILoggerFactory</span> loggerFactory<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
loggerFactory<span class="token punctuation">.</span><span class="token function">AddConsole</span><span class="token punctuation">(</span>Configuration<span class="token punctuation">.</span><span class="token function">GetSection</span><span class="token punctuation">(</span><span class="token string">"Logging"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
loggerFactory<span class="token punctuation">.</span><span class="token function">AddDebug</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">UseRouter</span><span class="token punctuation">(</span>a<span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">foreach</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> route <span class="token keyword">in</span> Routes<span class="token punctuation">.</span>RoutesDictionary<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
a<span class="token punctuation">.</span><span class="token function">MapGet</span><span class="token punctuation">(</span><span class="token string">"docker101"</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">handler</span><span class="token punctuation">:</span> <span class="token keyword">async</span> b<span class="token operator">=></span><span class="token punctuation">{</span>
b<span class="token punctuation">.</span>Response<span class="token punctuation">.</span><span class="token function">Redirect</span><span class="token punctuation">(</span><span class="token string">"https://blog.terrible.dev/Getting-started-with-docker-containers/"</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Ok, so what is the result? Well, extremely fast url parsing thanks to the mvc router, and a really lightweight application. Since we have no session, or even convention based action resolution. Our app is extremely thin, and fast.</p>
<p>So, thank Microsoft for really making the components mvc modular. This provides a very small, and lightweight service!</p>
Getting started with docker containers2017-02-18T16:16:46Zhttps://blog.terrible.dev/blog/Getting-started-with-docker-containers/<p>I've been starting to use docker, more and more recently. As this technology has grown many of my coworkers are getting more, and more interested in docker.
I put together <a href="https://github.com/TerribleDev/intro-to-docker">some materials</a> and a youtube video which may help some of you getting started with docker. If you don't like watching videos, check out the <code>story.md</code> file in the repo. That file has all the content covered. Honestly give me feedback if it helped or not. I might do more tutorials in the future for docker. Docker is such a new technology, and the surface area changes month to month.</p>
<br>
<!--more-->
<p><img src="https://www.youtube.com/watch?v=6EGyhDlr8rs" alt="video"></p>
StatsN a modern statsd client for dotnet core, and dotnet 4.52016-11-28T11:21:06Zhttps://blog.terrible.dev/blog/StatsN-A-modern-statsd-client-for-dotnet-core/<p><em>tl;dr <a href="https://github.com/TryStatsN/StatsN">click here</a></em></p>
<p>When we talk about capturing metrics in applications. One server/service that constantly is in all conversations monitoring, is <a href="https://github.com/etsy/statsd">statsd</a>. Incase you have never heard of it, statsd is a udp/tcp server that you send your in-code metrics to. These metrics get aggregated by statsd, and are forwarded to various backends. Some backends are services like <a href="https://www.librato.com/">librato</a> or <a href="https://www.sumologic.com/">sumologic</a>. Other times you are sending metrics to time series databases such as <a href="https://graphiteapp.org/">graphite</a> or god forbid <a href="https://graphiteapp.org/">influxdb</a>.</p>
<p>This boils down to in code you can say "log whenever this block of code is hit" or say "measure how long this function takes to execute". These stories come together to form pretty graphs, and rich alerts. All of this enabled by statsd.</p>
<!-- more -->
<p>In .net we have had 2 major statsd clients. There is <a href="https://github.com/Pereingo/statsd-csharp-client">StatsdClient</a>, which I have not used much in production, and then there is <a href="https://github.com/lukevenediger/statsd-csharp-client">StatsdCsharpClient</a>. Obviously the .Net community has followed in Microsoft's footsteps to name everything very literally.</p>
<p>I have used, and liked <a href="https://github.com/lukevenediger/statsd-csharp-client">StatsdCsharpClient</a> in the past. However with no core support, and a lack of movement to <a href="https://github.com/lukevenediger/statsd-csharp-client/issues/17#issuecomment-261921909">publish features that were pulled in 2 years ago</a>. I have generally given up on the project. This is not to say I don't like it. Honestly, I built some amazing apps, because of it. I was really interested in the <a href="https://github.com/Pereingo/statsd-csharp-client">StatsdClient</a>, but unfortunately it doesn't provide an API I can really enjoy. That project uses static classes/functions which are very hard to unit test as an outsider. This project stores configuration inside of 1 static class, making multi-tenancy virtually impossible. Even though the client didn't suit my needs, I still <a href="https://github.com/Pereingo/statsd-csharp-client/pull/65">ported it to core</a>.</p>
<p>Most stastd clients often catch all exceptions. The general attitude is that statsd clients should not blow up apps, no matter what. I agree with this approach, but I still wanted a way to get at those caught errors.</p>
<blockquote>
<p>I wanted a statsd client that was fast. That used Interfaces, and that didn't slow my code down. I wanted something that worked with .net core. What I wanted didn't exist.</p>
</blockquote>
<p>I really tried <a href="https://github.com/Pereingo/statsd-csharp-client/issues/64#issuecomment-261114334">working with the community</a>. The StatsdClient maintainers were into what I was selling. I however relized I would be breaking their library, and their customers for my own selfish desires. So I spend most of my last few weekends building a new Statsd Client. A client that is built with Dependency Injection in mind. A client that exposes its logs. A client that tries to be <strong>as fast as possible</strong>. This client is called <a href="https://github.com/TryStatsN/StatsN">StatsN</a>.</p>
<h2>Statsd clients, not as simple as you think</h2>
<p>Ok so I know what you are thinking. This can't be that complicated right? Well statsd has no rest endpoint. Statsd does not talk http, this is either a Udp, or Tcp connection. These are simple connections, with bytes being pumped over the wire. There are many gotchas in the land of socket reuse, and capturing them effectively is not simple. Building the metrics up, and pumping them over the wire in a manor that does not hinder the calling application is not as simple as one might believe. I spent quite some time in Linqpad making sure I was making the right decision. I always picked the decision that was faster, even if the code was/is uglier.</p>
<p>Writing a library that prevents throwing exceptions is no trivial matter. Infact this requires <a href="https://coveralls.io/github/TryStatsN/StatsN">lots of unit tests</a>, and I know I didn't hit all the lines of code in my testing. Getting everything right is tricky for sure!</p>
<h2>Gathering metrics with StatsN</h2>
<p>StatsN at its heart is has a simple api. Now to start you have to be running statsd somewhere (or you can use the NullChannel). In the past I used a <a href="https://github.com/hopsoft/docker-graphite-statsd">docker container</a> to run statsd + graphite. At the very least you can clone the statsd code, and run it local. Printing to The console is a backend for statsd.</p>
<p>We can construct a new stastd client with something like the following:</p>
<p><code>Install-Package StatsN</code></p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name">IStatsd</span> statsd <span class="token operator">=</span> StatsN<span class="token punctuation">.</span>Statsd<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">New</span><span class="token generic class-name"><span class="token punctuation"><</span>Udp<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>a<span class="token operator">=></span>a<span class="token punctuation">.</span>HostOrIp <span class="token operator">=</span> <span class="token string">"10.22.2.1"</span><span class="token punctuation">,</span> Port <span class="token operator">=</span> <span class="token number">8125</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">IStatsd</span> statsd <span class="token operator">=</span> StatsN<span class="token punctuation">.</span>Statsd<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">New</span><span class="token generic class-name"><span class="token punctuation"><</span>NullChannel<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>a<span class="token operator">=></span>a<span class="token punctuation">.</span>HostOrIp <span class="token operator">=</span> <span class="token string">"10.22.2.1"</span><span class="token punctuation">,</span> Port <span class="token operator">=</span> <span class="token number">8125</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// NullChannel pipes your metrics to nowhere...which can scale infinately btw</span>
</code></pre>
<p>Then we can log metrics.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
statsd<span class="token punctuation">.</span><span class="token function">TimerAsync</span><span class="token punctuation">(</span><span class="token string">"MyFunction.Timer"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token comment">/* code that will be timed */</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
statsd<span class="token punctuation">.</span><span class="token function">CountAsync</span><span class="token punctuation">(</span><span class="token string">"MyCounter"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Now Statsd clients should be used as singletons in applications. These objects create either a Udp, or Tcp client which can be reused.</p>
<p>So in your <code>startup.cs</code> file of your aspnet core app remember to register it appropriately.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation"><</span>StatsN<span class="token punctuation">.</span>IStatsd<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>provider <span class="token operator">=></span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">StatsN<span class="token punctuation">.</span>Statsd</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">StatsN<span class="token punctuation">.</span>StatsdOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
HostOrIp <span class="token operator">=</span> <span class="token string">"127.0.0.1"</span><span class="token punctuation">,</span>
Port <span class="token operator">=</span> <span class="token number">8125</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>You can then access it through the aspnet core DI container</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token return-type class-name">IActionResult</span> <span class="token function">Index</span><span class="token punctuation">(</span><span class="token class-name">StatsN<span class="token punctuation">.</span>IStatsd</span> statsd<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
statsd<span class="token punctuation">.</span><span class="token function">CountAsync</span><span class="token punctuation">(</span><span class="token string">"HomePage.Accessed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">View</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>The future of StatsN</h2>
<p>I hope to create additional instrumented things around StatsN. I have already started working on an <a href="https://github.com/TryStatsN/StatsN.MvcCore.ActionInstrumentation">MVC ActionFilter attribute</a>. I'm hoping the following would time your mvc/webapi actions and results</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Instrument</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"homepage.load"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token return-type class-name">IActionResult</span> <span class="token function">Index</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">View</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>I also plan on making a class that extends HttpClient so you can automatically instrument your http calls, how long it takes for your bytes to leave the wire, and how long it takes to download responses. These kinds of efforts really improve how developers instrument their applications for the future.</p>
<p>I hope you enjoy StatsN!</p>
Parsing cli arguments in dotnet core Console App2016-10-24T20:31:06Zhttps://blog.terrible.dev/blog/Parsing-cli-arguments-in-dotnet-core-Console-App/<p><strong>tl;dr</strong> view <a href="https://gist.github.com/TerribleDev/06abb67350745a58f9fab080bee74be1">this gist</a></p>
<p>So its 2016, and we are still making console apps/cli's. In fact I would say there has been a surge in popularity of these types of tools. I think we have come to the realization that buttons on forms are not automatable, and that the command line doesn't have to be scary.</p>
<p>I recently started writing an app in dotnet core, which is the new runtime for dotnet. In the past I have often used <a href="https://www.nuget.org/packages/CommandLineParser">command line parser</a>, but as of this writing it does not support core.</p>
<blockquote>
<p>I was really lost trying to find an arguments parsing library when I realized the dotnet cli was open sourced.</p>
</blockquote>
<p>After much struggle, failing to bingle. I started ripping through the Entity Framework, and dotnet cli's code hoping to find a gem. Thats when I stumbled across a <a href="https://blog.terrible.dev/blog/Parsing-cli-arguments-in-dotnet-core-Console-App/microsoft.extensions.commandlineutils">diamond</a>. You see many dotnet projects use <a href="https://www.nuget.org/packages/Microsoft.Extensions.CommandLineUtils/">Microsft.Extension.CommandLineUtils</a> to do cli parsing.</p>
<!-- more -->
<h2>A quick primer on the command line</h2>
<p>Console apps are just essentially apps that use the console as the UI. The primary way developers interact with CLI tools is through the console. Lets take the azure cli and break down how commands work as an interface.</p>
<pre><code>info: _ _____ _ ___ ___
info: /_\ |_ / | | | _ \ __|
info: _ ___/ _ \__/ /| |_| | / _|___ _ _
info: (___ /_/ \_\/___|\___/|_|_\___| _____)
info: (_______ _ _) _ ______ _)_ _
info: (______________ _ ) (___ _ _)
info:
info: Microsoft Azure: Microsoft's Cloud Platform
info:
info: Tool version 0.10.6
help:
help: Display help for a given command
help: help [options] [command]
help:
help: Log in to an Azure subscription using Active Directory or a Microsoft account identity.
help: login [options]
help:
help: Log out from Azure subscription using Active Directory. Currently, the user can log out only via Microsoft organizational account
help: logout [options] [username]
help:
help: Open the portal in a browser
help: portal [options]
help:
help: Manages the data collection preference.
help: telemetry [options]
help:
help: Commands:
help: account Commands to manage your account information and publish settings
help: acs Commands to manage your container service.
help: ad Commands to display Active Directory objects
help: appserviceplan Commands to manage your Azure appserviceplans
help: availset Commands to manage your availability sets.
help: batch Commands to manage your Batch objects
help: cdn Commands to manage Azure Content Delivery Network (CDN)
</code></pre>
<p>The azure cli has what many consider a noun verb syntax. For example if I run <code>azure webapp</code> I will have a list of actions to take on the webapp noun. I could run <code>azure webapp list</code> or <code>azure webapp start [appname]</code>. These are what we call Commands.</p>
<pre><code>
C:\Users\parne>azure webapp
help: Commands to manage your Azure webapps
help:
help: create a web app
help: webapp create [options] <resource-group> <name> <location> <plan>
help:
help: Stop a web app
help: webapp stop [options] <resource-group> <name>
help:
help: Start a web app
help: webapp start [options] <resource-group> <name>
help:
help: Stop and then start a web app
help: webapp restart [options] <resource-group> <name>
</code></pre>
<p>Now there are also optional things we can pass. These are usually called Parameters. Typically there are 3 kinds of parameters <code>SingleValue</code>, <code>NoValue</code>, <code>MultipleValue</code>.</p>
<p>For example if we were to create a webapp we could pass <code>--location <locationhere></code> which would be a single value parameter. If location could take more than one parameter, it would be considered a MultipleValue Parameter. Now I know what you are thinking, how can anything have no value? Well these types of parameters are often boolean values. For example if we wanted <code>azure webapp create</code> to output in json we could pass the <code>-- json</code> flag but we wouln't pass anything with it. Instead the presence of the flag would turn on the feature.</p>
<p>Now last note, apps return exit codes. Basically an integer representing either a success <code>0</code> or an error <code>>0</code> just be aware that command line tools should return a status code 0 if everything is ok.</p>
<h2>Ok I get it, now how do I parse things in dotnet</h2>
<p>Great, so circling back to the beginnings of my story. I needed a <strong>solid</strong> cli parser. One that can do commands n levels deep, auto parsing properties, and has a clean api. The cli parser for ef, and dotnet seems to fit that bill.</p>
<p>Create a console app (if you don't have one already) <code>dotnet new -t console</code></p>
<p>You should have something like this:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Program</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Main</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> args<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"Hello World!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Add the nuget package to your project <code>Install-Package Microsoft.Extensions.CommandLineUtils</code>.</p>
<p>Ok, now lets say we want to make a console that can create <code>snowballs</code>, and <code>catapults</code>. Then I guess we will let a <code>catapult</code> throw a snowball.</p>
<p>So in this instance we have 2 nouns; <code>catapult</code>, <code>snowball</code>. First we need to add these as "commands".</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Main</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> args<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> app <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Microsoft<span class="token punctuation">.</span>Extensions<span class="token punctuation">.</span>CommandLineUtils<span class="token punctuation">.</span>CommandLineApplication</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"catapult"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"snowball"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//give people help with --help</span>
app<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">Execute</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>So there is two things going on here. 1) we have added <code>--help</code> so a user can get some generated docs for this app, and the other is we have added catapult and snowball. You should be able to run <code>dotnet build && dotnet .\bin\Debug\netcoreapp1.0\YourApp.dll --help</code> and it should display the help menu</p>
<p>Now currently these are top level commands, but we want to give them subcommands. Starting with catapult lets add a command to <code>list</code> and a command to <code>add</code> a catapult.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Main</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> args<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> app <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Microsoft<span class="token punctuation">.</span>Extensions<span class="token punctuation">.</span>CommandLineUtils<span class="token punctuation">.</span>CommandLineApplication</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> catapult <span class="token operator">=</span> app<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"catapult"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"list"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"list catapults"</span><span class="token punctuation">;</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"b"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"add"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"Add a catapult"</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> arg <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"name of the catapult"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>arg<span class="token punctuation">.</span>Value<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//add snowballs somehow (not showing persistence here)</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"added </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">arg<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"snowball"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//give people help with --help</span>
app<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">Execute</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Ok great so when we run <code>app catapult list</code> we get a list back of catapult a, and b. We can add a new one. However when we run <code>app catapult</code> nothing happens. We should support <code>app catapult help</code>, <code>app catapult --help</code> or just <code>app catapult</code> so that users can get to help menus easily. So lets fix that.</p>
<p>Make your catapult declaration look like this:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token class-name"><span class="token keyword">var</span></span> catapult <span class="token operator">=</span> app<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"catapult"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">ShowHelp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//show help for catapult</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">//return error since we didn't do anything</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//show help on --help</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"help"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"get help!"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
catapult<span class="token punctuation">.</span><span class="token function">ShowHelp</span><span class="token punctuation">(</span><span class="token string">"catapult"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>So what we have here is, if we match catapult with no params, show the help and return a status code of 1 (since we didn't do anything). Also allow <code>--help, -? -h</code> and <code>help</code>. Now anyone using this subcommand will be able to get help.</p>
<p>Ok so now lets add <code>add</code> and <code>list</code> to snowballs.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> snowball <span class="token operator">=</span> app<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"snowball"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">ShowHelp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//show help for catapult</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">//return error since we didn't do anything</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//show help on --help</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
snowball<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"help"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"get help!"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
catapult<span class="token punctuation">.</span><span class="token function">ShowHelp</span><span class="token punctuation">(</span><span class="token string">"snowball"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
snowball<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"list"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"list snowballs"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
snowball<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"add"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"Add a snowball"</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> arg <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"name of the snowball"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>arg<span class="token punctuation">.</span>Value<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//add snowballs somehow</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"added </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">arg<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Now all that is left is to be able to let catapults throw snow.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"fling"</span><span class="token punctuation">,</span> config <span class="token operator">=></span><span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"fling snow"</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> ball <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"snowballId"</span><span class="token punctuation">,</span> <span class="token string">"snowball id"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> cata <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"catapultId"</span><span class="token punctuation">,</span> <span class="token string">"id of catapult to use"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token comment">//actually do something</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"threw snowball: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">ball<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string"> with </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">cata<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>ok now lets throw some snow!</p>
<pre class="language-console" tabindex="0"><code class="language-console">C:\projects\CommandLineParsing> dotnet .\bin\Debug\netcoreapp1.0\k.dll catapult --help
Usage: catapult [options] [command]
Options:
-? | -h | --help Show help information
Commands:
add Add a catapult
fling fling snow
help get help!
list list catapults
Use "catapult [command] --help" for more information about a command.
C:\projects\CommandLineParsing> dotnet .\bin\Debug\netcoreapp1.0\k.dll catapult add --help
Usage: catapult add [arguments] [options]
Arguments:
name name of the catapult
C:\projects\CommandLineParsing> dotnet .\bin\Debug\netcoreapp1.0\k.dll catapult add a
added a
C:\projects\CommandLineParsing> dotnet .\bin\Debug\netcoreapp1.0\k.dll catapult list
a
b
C:\projects\CommandLineParsing> dotnet .\bin\Debug\netcoreapp1.0\k.dll snowball add 1
added 1
C:\projects\CommandLineParsing> dotnet .\bin\Debug\netcoreapp1.0\k.dll catapult fling --help
Usage: catapult fling [arguments] [options]
Arguments:
snowballId snowball id
catapultId id of catapult to use
C:\projects\CommandLineParsing> dotnet .\bin\Debug\netcoreapp1.0\k.dll catapult fling a 1
threw snowball: a with 1</code></pre>
<p>Alright, one last feature. If we wanted to add an <code>--even-harder</code> parameter to the fling action we can do that!</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"fling"</span><span class="token punctuation">,</span> config <span class="token operator">=></span><span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"fling snow"</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> harderParam <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Option</span><span class="token punctuation">(</span><span class="token string">"--even-harder"</span><span class="token punctuation">,</span> <span class="token string">"fling snowballs at lightning speed!!!"</span><span class="token punctuation">,</span> CommandOptionType<span class="token punctuation">.</span>NoValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> ball <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"snowballId"</span><span class="token punctuation">,</span> <span class="token string">"snowball id"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> cata <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"catapultId"</span><span class="token punctuation">,</span> <span class="token string">"id of catapult to use"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>harderParam<span class="token punctuation">.</span><span class="token function">HasValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//actually do something</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"threw snowball: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">ball<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string"> with </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">cata<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string"> even harder!!!!"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//actually do something</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"threw snowball: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">ball<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string"> with </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">cata<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Ok great, now we get the result from <code>app.Execute();</code> we should exit the console with the same status code.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> result <span class="token operator">=</span> app<span class="token punctuation">.</span><span class="token function">Execute</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
Environment<span class="token punctuation">.</span><span class="token function">Exit</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Here is the full source as a <a href="https://gist.github.com/TerribleDev/06abb67350745a58f9fab080bee74be1#file-program-cs">gist</a>:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Main</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> args<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> app <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Microsoft<span class="token punctuation">.</span>Extensions<span class="token punctuation">.</span>CommandLineUtils<span class="token punctuation">.</span>CommandLineApplication</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> catapult <span class="token operator">=</span> app<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"catapult"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">ShowHelp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//show help for catapult</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment">//return error since we didn't do anything</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//show help on --help</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"help"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"get help!"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
catapult<span class="token punctuation">.</span><span class="token function">ShowHelp</span><span class="token punctuation">(</span><span class="token string">"catapult"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"list"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"list catapults"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"a"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"b"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"add"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"Add a catapult"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> arg <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"name of the catapult"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>arg<span class="token punctuation">.</span>Value<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//add snowballs somehow</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"added </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">arg<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
catapult<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"fling"</span><span class="token punctuation">,</span> config <span class="token operator">=></span><span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"fling snow"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> ball <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"snowballId"</span><span class="token punctuation">,</span> <span class="token string">"snowball id"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> cata <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"catapultId"</span><span class="token punctuation">,</span> <span class="token string">"id of catapult to use"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token comment">//actually do something</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"threw snowball: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">ball<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string"> with </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">cata<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> snowball <span class="token operator">=</span> app<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"snowball"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">ShowHelp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//show help for catapult</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment">//return error since we didn't do anything</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//show help on --help</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
snowball<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"help"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"get help!"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
catapult<span class="token punctuation">.</span><span class="token function">ShowHelp</span><span class="token punctuation">(</span><span class="token string">"snowball"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
snowball<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"list"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"list snowballs"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
snowball<span class="token punctuation">.</span><span class="token function">Command</span><span class="token punctuation">(</span><span class="token string">"add"</span><span class="token punctuation">,</span> config <span class="token operator">=></span> <span class="token punctuation">{</span>
config<span class="token punctuation">.</span>Description <span class="token operator">=</span> <span class="token string">"Add a snowball"</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> arg <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token function">Argument</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"name of the snowball"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
config<span class="token punctuation">.</span><span class="token function">OnExecute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=></span><span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrWhiteSpace</span><span class="token punctuation">(</span>arg<span class="token punctuation">.</span>Value<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//add snowballs somehow</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"added </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">arg<span class="token punctuation">.</span>Value</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//give people help with --help</span>
app<span class="token punctuation">.</span><span class="token function">HelpOption</span><span class="token punctuation">(</span><span class="token string">"-? | -h | --help"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> result <span class="token operator">=</span> app<span class="token punctuation">.</span><span class="token function">Execute</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
Environment<span class="token punctuation">.</span><span class="token function">Exit</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
Dockerize that old webforms app2016-10-19T00:20:49Zhttps://blog.terrible.dev/blog/dockerize-that-old-webforms-app/<p>So now that Windows server 2016 is <a href="https://blogs.technet.microsoft.com/hybridcloud/2016/10/12/another-big-step-in-hybrid-cloud-windows-server-2016-general-availability/">generally avalible</a> for the first time ever windows users can now use containers. Ok, so what exactly are containers? Well more or less they are virtual operating systems that <strong>share</strong> the same kernel as the host OS. In regular VM's the hardware is shared between machines, but containers go a step further and share the kernel of the OS. Why does this matter? Well because you are sharing an existing kernel that is already running, your startup times are instantanious. To put this in perspective, this is virtualization at the OS level.</p>
<p>On Linux, containers have been a thing for a long time. This technology is called LXC. Docker itself is a layer ontop of various container platforms embedded in operating systems.</p>
<!-- more -->
<h2>Getting started</h2>
<p>You can setup your windows 10 machine <a href="https://gist.github.com/TerribleDev/dd424d3d090bcf5634dcf8417411a081">with this script</a>. After docker starts, right click on it in the task bar and click Use Windows Containers. MSDN contains <a href="https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start_windows_server">docs</a> for server 2016.</p>
<p>So I have put an example project <a href="https://github.com/TerribleDev/docker-webforms">together on github</a> which may help you understand what is going on. Docker images are first compiled which essentially involves taking an existing image, maybe running some commands (like installing windows features), and pushing your files into the container. After the image is built we can run the container, and beyond that we can publish the image for deployment.</p>
<p>We define how the container is built with a <code>Dockerfile</code>. Take an existing webforms app, and in the web project add a file called <code>Dockerfile</code> with the following content</p>
<p>Dockerfile:</p>
<pre><code>FROM microsoft/aspnet
ARG site_root=.
ADD ${site_root} /inetpub/wwwroot
</code></pre>
<p>In this case the <code>Dockerfile</code> is pulling down the aspnet image from Dockerhub. This is a servercore image, with iis/aspnet installed. Docker is adding the content in the current directory to /inetpub/wwwroot which is where the app is ran from in the container.</p>
<p>Now compile your code and run the following in the root of your project directory</p>
<pre class="language-powershell" tabindex="0"><code class="language-powershell">docker build <span class="token operator">-</span>t mywebforms:0<span class="token punctuation">.</span>0<span class="token punctuation">.</span>1 <span class="token punctuation">.</span></code></pre>
<p>You should now have an docker image created! We can list the docker images with <code>docker images</code>. We can run the image with <code>docker run -d mywebforms:0.0.1</code></p>
<p>To see the website running in the container we need to find its ip address and then open a browser to the ip. You can use this powershell script to list running docker procs and their ip's</p>
<pre class="language-powershell" tabindex="0"><code class="language-powershell">docker inspect <span class="token operator">-</span>f <span class="token string">"{{ .NetworkSettings.Networks.nat.IPAddress }}"</span> $<span class="token punctuation">(</span>docker <span class="token function">ps</span> <span class="token operator">-</span>qa<span class="token punctuation">)</span></code></pre>
<h2>Ok so now what?</h2>
<h2>Plumbing in a CI system!</h2>
<p>Even legacy applications can be improved with some kind of build automation. Starting to automate msbuild/nuget and docker is a great start to really improving legacy projects. I am a web developer, so javascript is my bread and butter. that being said, its not for everyone. In <a href="https://github.com/TerribleDev/docker-webforms">my sample project</a> I used gulp to compose a build together. There are many tools including cake (c#), albacore (ruby), grunt (javascript). Honestly they all work about the same. I chose gulp, because I am using gulp in many of my projects currently.</p>
<p>In my sample I created a gulp file that takes in a version number (which could be passed by our CI system). Patches the AssemblyInfo.cs files, restores nuget packages, and compiles down a docker image to be used later. All with the simple command of <code>gulp build --version 1.0.0</code></p>
<p>The created docker image could easily be uploaded to some kind of storage.</p>
Use dotnet rc2 with appveyor2016-05-21T23:13:47Zhttps://blog.terrible.dev/blog/use-dotnet-rc2-with-appveyor/<p>dotnet CLI is currently in RC2, and while the train is fast approaching RTM, most tools are still catching up. <a href="https://blog.terrible.dev/blog/use-dotnet-rc2-with-appveyor/dot.net">dotnet</a> seems to have a documented cli based install for every platform except the good ol windows. That being said getting a windows based install/build is possible.</p>
<!-- more -->
<p>Place the following powershell as the before build step in appveyor. In short, download the installer, run it, and then restore your nuget packages. I got the flags for the installer by running the installer with /?</p>
<pre class="language-powershell" tabindex="0"><code class="language-powershell"> <span class="token punctuation">(</span><span class="token function">new-object</span> net<span class="token punctuation">.</span>webclient<span class="token punctuation">)</span><span class="token punctuation">.</span>DownloadFile<span class="token punctuation">(</span><span class="token string">'https://download.microsoft.com/download/4/6/1/46116DFF-29F9-4FF8-94BF-F9BE05BE263B/packages/DotNetCore.1.0.0.RC2-SDK.Preview1-x64.exe'</span><span class="token punctuation">,</span><span class="token string">'core.exe'</span><span class="token punctuation">)</span>
core<span class="token punctuation">.</span>exe <span class="token operator">/</span>install <span class="token operator">/</span>quiet <span class="token operator">/</span>norestart
dotnet restore
</code></pre>
<p>if you have solution files, and a project system them appveyor should build the project automatically. If you don't then set the build command to be <code>dotnet build .\path\to\your\proj</code></p>
<p>Since aspnet core builds to not emit dependent dll's appveyor's auto detect and run for tests doesn't work. Make sure you have added the test runner to your project.json and just run <code>dotnet test .\path\to\your\tests</code> as your test_script of your appveyor.yml file</p>
<p>You can find a working example <a href="https://github.com/TerribleDev/shodan.net">here</a></p>
<p>tl;dr appveyor.yml:</p>
<pre class="language-yml" tabindex="0"><code class="language-yml"><span class="token key atrule">version</span><span class="token punctuation">:</span> 1.0.<span class="token punctuation">{</span>build<span class="token punctuation">}</span>
<span class="token key atrule">configuration</span><span class="token punctuation">:</span> Release
<span class="token key atrule">before_build</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">ps</span><span class="token punctuation">:</span> <span class="token punctuation">></span><span class="token punctuation">-</span>
(new<span class="token punctuation">-</span>object net.webclient).DownloadFile('https<span class="token punctuation">:</span>//download.microsoft.com/download/4/6/1/46116DFF<span class="token punctuation">-</span>29F9<span class="token punctuation">-</span>4FF8<span class="token punctuation">-</span>94BF<span class="token punctuation">-</span>F9BE05BE263B/packages/DotNetCore.1.0.0.RC2<span class="token punctuation">-</span>SDK.Preview1<span class="token punctuation">-</span>x64.exe'<span class="token punctuation">,</span>'core.exe')
core.exe /install /quiet /norestart
dotnet restore
<span class="token key atrule">build</span><span class="token punctuation">:</span>
<span class="token key atrule">verbosity</span><span class="token punctuation">:</span> minimal
<span class="token key atrule">test_script</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">cmd</span><span class="token punctuation">:</span> dotnet test .\path\to\mytests
</code></pre>
Bringin' turbolinks to .net2016-03-13T18:46:48Zhttps://blog.terrible.dev/blog/Bringin-turbolinks-to-net/<p>For a while now I have been playing with rails, and rack webapps. If you are not familiar with these, they are webservers created in ruby. One of the features I ran into during my journey into ruby land is <a href="https://github.com/turbolinks/turbolinks-classic">Turbolinks</a>. Incase you are not familiar, Turbolinks is basically a simplified pjax, with a lot of flexibility. When you click on a link in a page with turbolinks, the link action is hijacked and the target page is loaded via ajax. The result of the ajax call (which is presumed to be html) will replace the document of the body tag. At the end of the day its a technology to load your server side pages via ajax.</p>
<!-- more -->
<h2>Why load your pages via ajax?</h2>
<p>Ok, so I know what you are thinking, why do this? This will prevent any use of <code>$(document).ready(()=>{})</code> and generally could cause some weird js behaviors. The answer is simple, page load times. We all know SPA's generally are slightly slower to load on first page, but subsequent pages are <strong>super</strong> fast. Part of what makes SPA's fast, is their lack of re-loading css, and boilerplate js for the page. That being said the SPA experience on older browsers, or older hardware leaves something to be desired.</p>
<p>Turbolinks hopes to provide a spa like experience, but with the control of a server side application. Basically rails authors drop the turbolinks.js file in with their other JavaScript files, and they install the server side middleware. There are haters, even in the rails community. Personally I think its a very interesting proposition, and I hate to see ruby be the only holders of this technology.</p>
<h2>In comes Turbolinks.Net</h2>
<p>I was working on an aspnet core 1.0 application, which had a lot of css. This css provided a very rich client experience, but at the cost that it was not fast to download, or parse. This project was more or less browser based art. We needed server side controls over the digital assets. A prototype react app we made, but was ultimately abandoned as it didn't perform as we would hope on older hardware. We really didn't want to write a spa for fear of the art to be stolen, and we wanted to provide a rich experience even for older hardware. I recalled back to my rails tinkering, and quickly made a middleware called <a href="https://github.com/TerribleDev/TurboLinks.Net">Turbolinks.Net</a>. This middleware provides the basic server side functionality for aspnet core 1.0 websites to use the TurboLinks technology. This really helped us maintain a server based application, but with a client rich experience.</p>
<h2>Why Turbolinks over pjax?</h2>
<p>Ok, so I have been asked this question a lot. I don't like getting into these debates, especially since I did not author either technology. In my experience pjax requires much more configuration. I like a <code>batteries included</code> model where it does things by default, but I can change the defaults. Pjax doesn't fit into that model, unlike turbolinks. Also, turbolinks has a huge community, and has companies behind it. The rewrite, known as <a href="https://github.com/turbolinks/turbolinks">TurboLinks 5</a> looks awesome, and even more intriguing than previous versions. I'm not going to sit here and sell you on it, that is <a href="http://stackoverflow.com/a/14251289/3671357">what stack overflow is for</a>, I'm just going to say I <i class="fa fa-heart"></i> TurboLinks.</p>
Announcing gulp-nuget-restore2016-02-24T14:58:04Zhttps://blog.terrible.dev/blog/Announcing-gulp-nuget-restore/<p>So recently I have thought about build tools. We have many tools including <a href="https://github.com/cake-build/cake">cake</a>, <a href="https://github.com/sakeproject/sake">sake</a>, <a href="https://github.com/Albacore/albacore">albacore</a>, and even MSBUILD. Most of these tools work well, infact they work flawlessly. I am a web developer, and I work on a team of web developers. Most of our work is in JavaScript land, with tools like React, backbone, etc. We love ES6, and we want to use things like babel. This ultimately causes us to have 2 build engines. The first being a proprietary version of albacore, and the second being gulp.</p>
<!-- more -->
<p>I love Gulp, I also love Grunt. They both have a place in the JavaScript community, and the tool itself doesn't matter, but what does is the fact that we <strong>have</strong> to use them. We already have multiple languages in our ecosystem, so drinking in ruby just for builds seems like a hard sell. Ideally we would want, and love to use JavaScript for everything. I started working on our builds in gulp, and I wrote a <a href="https://github.com/TerribleDev/gulp-nuget-restore">gulp plugin</a> to do nuget restores. This plugin pairs well with the <a href="https://github.com/hoffi/gulp-msbuild">msbuild</a> plugin.</p>
<p>Feel free to try it out, and <a href="http://twitter.com/terribledev">tweet</a> at me if you like it.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> gulp <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span>'gulp'<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> nugetRestore <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span>'gulp<span class="token operator">-</span>nuget<span class="token operator">-</span>restore'<span class="token punctuation">)</span><span class="token punctuation">;</span>
gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span>'<span class="token keyword">default</span>'<span class="token punctuation">,</span> function <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> gulp<span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span>'<span class="token punctuation">.</span><span class="token operator">/</span>path<span class="token operator">/</span>to<span class="token operator">/</span>MySlnFile<span class="token punctuation">.</span>sln'<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">nugetRestore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
Fixing your build after updating all nuget packages2016-02-12T17:21:05Zhttps://blog.terrible.dev/blog/Fixing-your-build-after-updating-all-nuget-packages/<p>So if you are like one of my co-wokers whom are newer to <code>.net</code> land you probably thought</p>
<blockquote>
<p>"hey it would be good just to update all my nuget packages".</p>
</blockquote>
<p>Then you quickly ran into issues.</p>
<!-- more -->
<p>The issue we saw was that in the references all the nuget packages were appearing as if they were not installed. We checked the path to them in the csproj and they looked good. One thing that took us a while to hunt down is that the .net compilers do not update very well.</p>
<p><code>Microsoft.Net.Compilers</code> and <code>Microsoft.CodeDom.Providers.DotNetCompilerPlatform</code> both have a lot of custom markup that gets injected in the csproj. This presumably is so that roslyn can be used instead of the traditional c# compiler.</p>
<p>We found many of the following with the old version that was since updated during the global update</p>
<pre class="language-xml" tabindex="0"><code class="language-xml">
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Import</span> <span class="token attr-name">Project</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props<span class="token punctuation">"</span></span> <span class="token attr-name">Condition</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Exists('..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
</code></pre>
<p>To get around the issue we opened the csproj in notepad++ Controled + H the old package name in this case <code>Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0</code> and replaced it with the updated package we were using (found in the packages.conf) <code>Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.1</code></p>
<p>We made sure we did this to both of the previously mentioned packages. Once complete everything seemed to compile again.</p>
The wix toolset tl;dr2016-02-12T01:00:00Zhttps://blog.terrible.dev/blog/The-wix-toolset-tl-dr/<p>So recently I have had the (some would say unfortuate) time learning wix. Specifically I am trying to better understand windows installers, mostly to install webapps into IIS with MSI's. This is mostly due to the unfortunate situation where I constantly do work for windows things. I would recommend reading the docs on the <a href="http://wixtoolset.org">wixtoolset</a> website, but if you are still having a trouble understanding how the tools come together, you can read this.</p>
<p>Windows Installer Xml toolset or Wix for short, has been around since the early 2000's. The toolset is one of the great mechanisms to create MSI's. A while back I <a href="https://blog.terrible.dev/binding-ssl-certs-on-windows-installer-xml-wix-deployed-web-applications/">blogged</a> about how to use them to install ssl certs in IIS. Until recently when I fit the tools together in my head, I couldn't figure out how they work. So here is the tl;dr</p>
<!-- more -->
<h2>tools</h2>
<p>The wix tools are command line tools, but they do have good integrations with msbuild. That being said you can invoke them right from gulp, or rake if you want.</p>
<h4>Heat</h4>
<p>Heat is known as the "Harvester" tool. In a wsx file you will reference components, and files. Often instead of baking paths to specific files, you will use heat to grab whole directories.
When you call heat.exe you can include some parameters, which are well covered <a href="http://wixtoolset.org/documentation/manual/v3/overview/heat.html">in the docs</a>. Ultimately this will export wixobj files which will be used in the generation of your MSI.</p>
<h4>Candle</h4>
<p>Candle, also known as the compiler. Candle is a tool that converts your wxs files into wixobj files. This will "compile" the xml. This is the place where you can include wix extensions such as the IIS extension.</p>
<h4>Light</h4>
<p>Light is the "Linker" tool. You can think of the "Linker" as the thing that gathers everything outputted by heat, and candle into an MSI database. If you include a cabnet in your wix file it should place your heat files inside the MSI directly. This tool "Links" the wixobj metadata to ultimately produce an MSI.</p>
<h2>Combining the tools</h2>
<p>Essentially you have to combine the tools. Heat will harvest directories, candle will compile your wxs file, and light will pull it all together. You call them in that order. In a future sequel to this blog post I will provide some recipes how you can integrate this into a CI build with tools such as jenkins.</p>
Commiting a new file to git, through the github api2016-01-08T21:51:00Zhttps://blog.terrible.dev/blog/Commiting-a-new-file-to-github-through-the-github-api/<p>Recently I have been working on an application that basically has a github bot (aka user) fork a repo, commit some files, and submit a PR against someone's repo. When it came down to actually making a new git commit through the github API, I had quite a hard time. I figured it out with some help from a ruby <a href="http://mattgreensmith.net/2013/08/08/commit-directly-to-github-via-api-with-octokit/">tutorial</a>, and now I'm going to show you how to do it.</p>
<!-- more -->
<h2>Getting things going</h2>
<p>Before we start, we need 2 things.</p>
<ol>
<li>Install the <a href="https://www.nuget.org/packages/Octokit/">Octokit nuget package</a>.</li>
<li>Get a credential token</li>
<li>You can get a token for a logged in user via <a href="http://www.oauthforaspnet.com/providers/github/">oauth for .net</a></li>
<li>Or you can get a token for yourself (personal access token) by going to settings=>personal access tokens at github</li>
</ol>
<h2>The Code</h2>
<p>Ok so I'm going to walk you through the code...don't want to wait? scroll to the bottom (<a href="https://blog.terrible.dev/blog/Commiting-a-new-file-to-github-through-the-github-api/">or click here</a>).</p>
<h4>Forking the target repo</h4>
<p>The first thing we need our user to do is create our github client object.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token comment">//Create our Client</span>
<span class="token class-name"><span class="token keyword">var</span></span> client <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">GitHubClient</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">ProductHeaderValue</span><span class="token punctuation">(</span><span class="token string">"OurProgramName"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Credentials <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Credentials</span><span class="token punctuation">(</span><span class="token string">"YourCredentialTokenHere"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
<p>Then we should fork our target repo</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> fork <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>Repository<span class="token punctuation">.</span>Forks<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>owner<span class="token punctuation">,</span> repoName<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewRepositoryFork</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Afterwards we need to get the last commit for the default branch. You can replace fork.DefaultBranch with an actual branch name if you wish.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> refs <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Reference<span class="token punctuation">.</span><span class="token function">GetAll</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//Get the latest commit for the default branch</span>
<span class="token class-name"><span class="token keyword">var</span></span> lastestCommit <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Reference<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token string">"heads/"</span> <span class="token operator">+</span> fork<span class="token punctuation">.</span>DefaultBranch<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//Get the commit object for the "latest" commit in the default branch</span>
<span class="token class-name"><span class="token keyword">var</span></span> baseCommit <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Commit<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> lastestCommit<span class="token punctuation">.</span>Object<span class="token punctuation">.</span>Sha<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Now we need to make the data, and the commit.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token comment">//Create the data</span>
<span class="token class-name"><span class="token keyword">var</span></span> blob <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Blob<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewBlob</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Content <span class="token operator">=</span> <span class="token string">"I Am The Body of the file"</span><span class="token punctuation">,</span> Encoding <span class="token operator">=</span> EncodingType<span class="token punctuation">.</span>Utf8 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> genTree <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewTree</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> BaseTree <span class="token operator">=</span> baseCommit<span class="token punctuation">.</span>Tree<span class="token punctuation">.</span>Sha <span class="token punctuation">}</span><span class="token punctuation">;</span>
genTree<span class="token punctuation">.</span>Tree<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewTreeItem</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Type <span class="token operator">=</span> TreeType<span class="token punctuation">.</span>Blob<span class="token punctuation">,</span> Mode <span class="token operator">=</span> <span class="token string">"100644"</span><span class="token punctuation">,</span> Sha <span class="token operator">=</span> blob<span class="token punctuation">.</span>Sha<span class="token punctuation">,</span> Path <span class="token operator">=</span> <span class="token string">"OurNewFile.md"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> newTree <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Tree<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> genTree<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//make the commit</span>
<span class="token class-name"><span class="token keyword">var</span></span> commitSha <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Commit<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewCommit</span><span class="token punctuation">(</span><span class="token string">"Commit Message Huzzahhh"</span><span class="token punctuation">,</span> newTree<span class="token punctuation">.</span>Sha<span class="token punctuation">,</span> refs<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>Object<span class="token punctuation">.</span>Sha<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>This line creates the content of the file you wish to add (note the Content property)</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> blob <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Blob<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewBlob</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Content <span class="token operator">=</span> <span class="token string">"I Am The Body of the file"</span><span class="token punctuation">,</span> Encoding <span class="token operator">=</span> EncodingType<span class="token punctuation">.</span>Utf8 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>...and this line puts it into OurNewFile.md in a new tree (which I honestly don't know much about)</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
genTree<span class="token punctuation">.</span>Tree<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewTreeItem</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Type <span class="token operator">=</span> TreeType<span class="token punctuation">.</span>Blob<span class="token punctuation">,</span> Mode <span class="token operator">=</span> <span class="token string">"100644"</span><span class="token punctuation">,</span> Sha <span class="token operator">=</span> blob<span class="token punctuation">.</span>Sha<span class="token punctuation">,</span> Path <span class="token operator">=</span> <span class="token string">"OurNewFile.md"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Then we actually make the commit</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> commitSha <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Commit<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewCommit</span><span class="token punctuation">(</span><span class="token string">"Commit Message Huzzahhh"</span><span class="token punctuation">,</span> newTree<span class="token punctuation">.</span>Sha<span class="token punctuation">,</span> refs<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>Object<span class="token punctuation">.</span>Sha<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Now we have to update our fork with our new commit</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Reference<span class="token punctuation">.</span><span class="token function">Update</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token interpolation-string"><span class="token string">$"heads/</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">fork<span class="token punctuation">.</span>DefaultBranch</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ReferenceUpdate</span><span class="token punctuation">(</span>commitSha<span class="token punctuation">.</span>Sha<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Then submit the PR!!!!</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token comment">//submit the pr</span>
<span class="token keyword">await</span> client<span class="token punctuation">.</span>PullRequest<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>owner<span class="token punctuation">,</span> repoName<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewPullRequest</span><span class="token punctuation">(</span><span class="token string">"Add New File!!!!"</span><span class="token punctuation">,</span> <span class="token interpolation-string"><span class="token string">$"</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login</span><span class="token punctuation">}</span></span><span class="token string">:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">fork<span class="token punctuation">.</span>DefaultBranch</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> fork<span class="token punctuation">.</span>DefaultBranch<span class="token punctuation">)</span> <span class="token punctuation">{</span> Body <span class="token operator">=</span> <span class="token string">"OMG I'm A PR!!!!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h2>The actual code huzzah!!!!</h2>
<p><a name="source"></a></p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">async</span> <span class="token return-type class-name">Task</span> <span class="token function">CommitThings</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span></span> owner<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">string</span></span> repoName<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">//Create our Client</span>
<span class="token class-name"><span class="token keyword">var</span></span> client <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">GitHubClient</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">ProductHeaderValue</span><span class="token punctuation">(</span><span class="token string">"OurProgramName"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Credentials <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Credentials</span><span class="token punctuation">(</span><span class="token string">"YourCredentialTokenHere"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token comment">//get the repos for our token</span>
<span class="token class-name"><span class="token keyword">var</span></span> repos <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>Repository<span class="token punctuation">.</span><span class="token function">GetAllForCurrent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//if we already have this repo we should delete it (that way we get a fresh copy)</span>
<span class="token class-name"><span class="token keyword">var</span></span> existingRepo <span class="token operator">=</span> repos<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>a <span class="token operator">=></span> a <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> a<span class="token punctuation">.</span>Name<span class="token punctuation">.</span><span class="token function">Equals</span><span class="token punctuation">(</span>a<span class="token punctuation">.</span>Name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>existingRepo <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">await</span> client<span class="token punctuation">.</span>Repository<span class="token punctuation">.</span><span class="token function">Delete</span><span class="token punctuation">(</span>existingRepo<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> existingRepo<span class="token punctuation">.</span>Name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//create the fork</span>
<span class="token class-name"><span class="token keyword">var</span></span> fork <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>Repository<span class="token punctuation">.</span>Forks<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>owner<span class="token punctuation">,</span> repoName<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewRepositoryFork</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//Get all references</span>
<span class="token class-name"><span class="token keyword">var</span></span> refs <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Reference<span class="token punctuation">.</span><span class="token function">GetAll</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//Get the latest commit for the default branch</span>
<span class="token class-name"><span class="token keyword">var</span></span> lastestCommit <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Reference<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token string">"heads/"</span> <span class="token operator">+</span> fork<span class="token punctuation">.</span>DefaultBranch<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//Get the commit object for the "latest" commit in the default branch</span>
<span class="token class-name"><span class="token keyword">var</span></span> baseCommit <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Commit<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> lastestCommit<span class="token punctuation">.</span>Object<span class="token punctuation">.</span>Sha<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//Create the data</span>
<span class="token class-name"><span class="token keyword">var</span></span> blob <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Blob<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewBlob</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Content <span class="token operator">=</span> <span class="token string">"I Am The Body of the file"</span><span class="token punctuation">,</span> Encoding <span class="token operator">=</span> EncodingType<span class="token punctuation">.</span>Utf8 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> genTree <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewTree</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> BaseTree <span class="token operator">=</span> baseCommit<span class="token punctuation">.</span>Tree<span class="token punctuation">.</span>Sha <span class="token punctuation">}</span><span class="token punctuation">;</span>
genTree<span class="token punctuation">.</span>Tree<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewTreeItem</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Type <span class="token operator">=</span> TreeType<span class="token punctuation">.</span>Blob<span class="token punctuation">,</span> Mode <span class="token operator">=</span> <span class="token string">"100644"</span><span class="token punctuation">,</span> Sha <span class="token operator">=</span> blob<span class="token punctuation">.</span>Sha<span class="token punctuation">,</span> Path <span class="token operator">=</span> <span class="token string">"OurNewFile.md"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> newTree <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Tree<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> genTree<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//make the commit</span>
<span class="token class-name"><span class="token keyword">var</span></span> commitSha <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Commit<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewCommit</span><span class="token punctuation">(</span><span class="token string">"Commit Message Huzzahhh"</span><span class="token punctuation">,</span> newTree<span class="token punctuation">.</span>Sha<span class="token punctuation">,</span> refs<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>Object<span class="token punctuation">.</span>Sha<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> client<span class="token punctuation">.</span>GitDatabase<span class="token punctuation">.</span>Reference<span class="token punctuation">.</span><span class="token function">Update</span><span class="token punctuation">(</span>fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login<span class="token punctuation">,</span> fork<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> <span class="token interpolation-string"><span class="token string">$"heads/</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">fork<span class="token punctuation">.</span>DefaultBranch</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ReferenceUpdate</span><span class="token punctuation">(</span>commitSha<span class="token punctuation">.</span>Sha<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//submit the pr</span>
<span class="token keyword">await</span> client<span class="token punctuation">.</span>PullRequest<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span>owner<span class="token punctuation">,</span> repoName<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">NewPullRequest</span><span class="token punctuation">(</span><span class="token string">"Add New File!!!!"</span><span class="token punctuation">,</span> <span class="token interpolation-string"><span class="token string">$"</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">fork<span class="token punctuation">.</span>Owner<span class="token punctuation">.</span>Login</span><span class="token punctuation">}</span></span><span class="token string">:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">fork<span class="token punctuation">.</span>DefaultBranch</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> fork<span class="token punctuation">.</span>DefaultBranch<span class="token punctuation">)</span> <span class="token punctuation">{</span> Body <span class="token operator">=</span> <span class="token string">"OMG I'm A PR!!!!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
Bringing configuration management to the underconfigured2015-12-19T13:24:47Zhttps://blog.terrible.dev/blog/Bringing-configuration-management-to-the-underconfigured/<p>I spend much of my time at Vistaprint just being a normal developer. In fact its over 75% of what I do. I am a Web Developer, however with my background in ops I have spent more and more time at Vistaprint doing configuration management, and coaching other teams how to approach the subject.</p>
<!-- more -->
<p>Over the last year I have been hired at a few different startups to be a consultant, providing this knowledge to others. I have worked on both Linux, and Windows environments, and I have noticed <strong>especially</strong> windows shops are <strong>not</strong> doing configuration management. To say the least either sets of developers forget about the many dependencies their apps have. Programs are dependent on many things, DNS gateways, LDAP servers (maybe), certain native libraries, runtimes, etc. Declaring these dependencies inside of a configuration management tool like Chef, Puppet, Salt, etc. really provides better insight, and increased flexibility.</p>
<p>I worked for a ruby shop recently, and the first thing I said was "what version of ruby do you have installed on your servers" I got back "well I have ruby 2.1.4 on my machine". We did some quick checking and 1.9.3 was running in prod (a version that is <strong>out of support</strong>). I asked if they could use containers, but due to reasons I won't get into, they were unable to use them. I spent a week at the mentioned startup, and by the end of the week I had a very flexible set of puppet modules, and manifests that built out their whole environment. Dependencies declared, and developer machines provisioned in the same way. The impact of this change didn't hit them right away, but several weeks later I got a slack notification saying the following.</p>
<blockquote>
<p>Hey man we just created new database servers with puppet and it took less than a few hours to wire everything up! We also updated ruby in prod and it was a snap. Puppet R0x0rs</p>
</blockquote>
<p>Now I don't put this quote in just to brag about how amazing I am (I mean we all know I am right?). I put it here to show that if you start declaring dependencies in ways developers can consume, the rate of change that will occur is tremendous. Git provides a fantastic change management system, and amazing continuous deployment from a mainline trunk. Changes to puppet files, and thus changes to production can be easily tracked though Source Control Management. Bugs arisen from installations of said packages can be found quickly, and reverting these changes are a snap.</p>
<p>Bringing traditionally ops things to developers by using tooling developers will be able to use, will ultimately bridge the ops-dev gap we all have.</p>
Just got a Nexus 5x2015-12-05T20:55:45Zhttps://blog.terrible.dev/blog/Just-got-a-Nexus-5x/<p>Just got a new phone last week, and its one of the new Nexus phones</p>
<!-- excerpt -->
<p>I recently bought a Nexus 5x from our favorite search engine, Google. Incase you didn't know I am an Android fanboy, to really specify I am an apple hater. Outside of iPhones my options are *droid or Windows Phone. Every time I have used someone else's windows phone I am honestly stricken at how great it is, but I stuck with what I know and love, which is android.</p>
<h2>Why Nexus?</h2>
<p>As you all are aware there are a large number of Android devices in the ecosystem that is android. The flagship phones of this year seem to be the Galaxy S6, LG G4, and various other phones that are not <code>Nexus</code> phones. The competitor to these phones in the Nexus line would have to be the Nexus 6p; Which is larger, and more powerful than the 5x.</p>
<h3>UI</h3>
<p>My huge gripe about non nexus phones, is that they are not really Android. Well they are, but they usually come with a ton of weird apps, and a non-stock UI. The UI that google ships for Android stock is fantastic. The OS looks crisp, clean, and somewhat futuristic without being tacky. Other UI's such as TouchWiz cannot even compete, and yet these manufacturers insist on adding this experience to their phones.</p>
<h3>Updates and security</h3>
<p>There is no doubt that Nexus phones get updates much faster than non-nexus phones. Incase you were not aware, Nexus phones get their updates pushed directly from google. These phones often receive more updates than non-nexus phones, which have to get updated though the manufacturer, working in tandem with the carrier. Google around yourself, and find out which phones got updated to Lollipop, or even Marshmallow. Most of the nexus phones have been kept up to date.</p>
<p>The updates are not just about features. Updates contain security fixes. At the end of the day a Smartphone is really just a computer that can place phone calls. Like any other computer, smartphones are susceptible to hacks and can be compromised. Updates can often contain security enhancements to reduce the surface area of attack to these phones, allowing your personal information to be stored safely.</p>
<h2>Review?</h2>
<p>Ok so I should actually review the phone right?</p>
<p>The Nexus 5x is the sequel to a phone (Nexus 5) that was a cheap phone that really competed with phones twice its price. The 5x fails to live up to that a little as the specs are at best what a good phone was last year. That being said this phone is extraordinary in both performance, size, and quality.</p>
<p>The 5x is about as fast as most Android phones. The camera is a 12 MP camera that takes pretty solid pictures. The battery life seems to last roughly 24 hours for me just doing daily activities on the phone. The fingerprint scanner can wake the phone from sleep, and is located in the centre on the back. This is a very convenient place that is usually where my index finger lands. This Nexus phone gets GPS locks every time, and never seems to stop performing beautify. Other phones such as the 6p would probably out perform it if you sat them side by side, but day to day you wouldn't notice any slowness in the 5x. Overall I'd say its a good buy for the value.</p>
<h2>The future</h2>
<p>I'd really love to see a day when manufacturers would stop putting custom UI's ontop of Android. I'd love to see a day where all Android phones get updates direct from google. Until that time we must live with what we have, which is a weird market place in Android land. iOS users do not have to worry about such things, and I believe the same needs to happen for Android.</p>
Migrating Ghost blog to hexo2015-11-28T15:32:57Zhttps://blog.terrible.dev/blog/Migrating-Ghost-blog-to-hexo/<p>I recently ported my ghost blog to hexo, and it was pretty easy.</p>
<!-- excerpt -->
<p>Checkout my other hexo blogs:</p>
<ul>
<li><i class="fa fa-cloud fa-6"></i> <a href="https://blog.terrible.dev/Hosting-hexo-in-azure-webapps/">Hosting hexo in Azure webapps</a></li>
<li><i class="fa fa-user"></i> <a href="https://blog.terrible.dev/Why-I-moved-from-Ghost-to-Hexo/">Why I moved from Ghost to Hexo</a></li>
</ul>
<h2>Getting Started with hexo</h2>
<p>To get started with hexo run the following commands:</p>
<ul>
<li><code>npm install -g hexo-cli</code></li>
<li><code>hexo init</code></li>
<li><code>npm install</code></li>
</ul>
<p>This will drop many files, and folders. The primary one we are going to talk about is the <code>_config.yml</code>. You will want to start by filling out the <code>_config.yml</code> file. Name your blog, give a descripton, etc.</p>
<h2>Porting your blogs over</h2>
<p>To get your data over you will need to go to this url: <code>http://yourblog.com/ghost/settings/labs/</code> and click the export button. Place the json file at the root of your hexo blog, then run.</p>
<ul>
<li><code>npm install hexo-migrator-ghost --save</code></li>
<li><code>hexo migrate ghost NameOfYourExportFile.json</code></li>
</ul>
<p>Your posts should drop in the posts folder, but the tags will need fixing. Open atom (or another editor that can do find replace in a directory) and replace <code>tags: |</code> with <code>tags:</code> in all the files.</p>
<p>Now that it is done we need to fix the paths to your images. Download your images (if you are using <code>azure</code> you can get them via ftp), and place the folder in the source directory.</p>
<p>Now run <code>hexo server</code>, browse to port 4000. Your blogs should appear.</p>
<h2>Backward compat. urls</h2>
<p>We need to make some modifications to make sure the urls are backward compatible.</p>
<p>Set the tag_dir to tag, in ghost the path to tags is /tag.</p>
<p>if your post urls were just /Title then put <code>:title/</code> in the permalink setting. Otherwise adjust the urls for the proper date format.</p>
<h4>RSS</h4>
<p>You will want to have an rss feed. You will want to <code>npm install hexo-generator-feed --save</code></p>
<p>You can then add the following to your config.yml</p>
<pre class="language-yml" tabindex="0"><code class="language-yml"><span class="token key atrule">feed</span><span class="token punctuation">:</span>
<span class="token key atrule">type</span><span class="token punctuation">:</span> rss2
<span class="token key atrule">path</span><span class="token punctuation">:</span> rss
<span class="token key atrule">limit</span><span class="token punctuation">:</span> <span class="token number">0</span></code></pre>
<p>If you were like me you registered your ghost rss feed to <code>/rss </code>instead of <code>/rss.xml</code>. I have no perfect answer to fix this, but I used azure's Url redirect to redirect <code>/rss</code> to <code>/rss.xml</code>.</p>
<pre class="language-xml" tabindex="0"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>configuration</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>system.webServer</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rewrite</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rules</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rule</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>SpecificRewrite<span class="token punctuation">"</span></span> <span class="token attr-name">stopProcessing</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>match</span> <span class="token attr-name">url</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>^rss$<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>action</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Rewrite<span class="token punctuation">"</span></span> <span class="token attr-name">url</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>public/rss.xml<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>rule</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>rules</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>system.webServer</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>configuration</span><span class="token punctuation">></span></span></code></pre>
<p>If you are using github pages you can use the <code>jekyll-redirect-from</code> gem.</p>
Hosting hexo in azure webapps2015-11-26T16:20:42Zhttps://blog.terrible.dev/blog/Hosting-hexo-in-azure-webapps/<p>If you have read this blog for any length of time, you know I am a fan of Azure. I thought about using github pages with hexo, but github pages only supports 1 doman name. I could start 301 redirecting my other domains, but I really didn't want to do that.</p>
<!-- more -->
<h2>Building in azure</h2>
<p>In case you didn't know Azure Webapps have their own build engine called kudu. To get started install the cross plat azure cli. <code>npm install azure-cli -g</code></p>
<p>Generate your deploy.cmd (or sh if you prefer)
<code>azure site deploymentscript</code></p>
<p>Do not configure anything in the deployment section of your config.yml, this will cause it to publish to the public folder.</p>
<p>The only command you should have to do is hexo generate. Add one of the following to your deploy.cmd or deploy.sh depending on which language you generated (you will want to do this after the script npm installs).</p>
<p>deploy.sh:
<code>eval ./node_modules/.bin/hexo generate</code></p>
<p>deploy.cmd
<code>.\node_modules\.bin\hexo.cmd generate</code></p>
<p>We just need to configure IIS. Drop a file called web.config at the root of your blog. Add the following markup.</p>
<pre class="language-xml" tabindex="0"><code class="language-xml">
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>configuration</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>system.webServer</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>staticContent</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.mp4<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video/mp4<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.m4v<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video/m4v<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.ogg<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video/ogg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.ogv<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video/ogg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.webm<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video/webm<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.oga<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>audio/ogg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.spx<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>audio/ogg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.svg<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image/svg+xml<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.svgz<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image/svg+xml<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>remove</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.eot<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.eot<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>application/vnd.ms-fontobject<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.otf<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>font/otf<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.woff<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>font/x-woff<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>mimeMap</span> <span class="token attr-name">fileExtension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.woff2<span class="token punctuation">"</span></span> <span class="token attr-name">mimeType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>font/x-woff<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>staticContent</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rewrite</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rules</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rule</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Add trailing slash<span class="token punctuation">"</span></span> <span class="token attr-name">stopProcessing</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>match</span> <span class="token attr-name">url</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>(.*[^/])$<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>conditions</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>add</span> <span class="token attr-name">input</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{REQUEST_FILENAME}<span class="token punctuation">"</span></span> <span class="token attr-name">matchType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IsFile<span class="token punctuation">"</span></span> <span class="token attr-name">negate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>add</span> <span class="token attr-name">input</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{REQUEST_FILENAME}<span class="token punctuation">"</span></span> <span class="token attr-name">matchType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IsDirectory<span class="token punctuation">"</span></span> <span class="token attr-name">negate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>add</span> <span class="token attr-name">input</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{REQUEST_FILENAME}<span class="token punctuation">"</span></span> <span class="token attr-name">pattern</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>(.*?)\.[a-zA-z1-9]+$<span class="token punctuation">"</span></span> <span class="token attr-name">negate</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>conditions</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>action</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Redirect<span class="token punctuation">"</span></span> <span class="token attr-name">redirectType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Permanent<span class="token punctuation">"</span></span> <span class="token attr-name">url</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>{R:1}/<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>rule</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rule</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>RouteToPublicDirectory<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>action</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Rewrite<span class="token punctuation">"</span></span> <span class="token attr-name">url</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>public{REQUEST_URI}<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>rule</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>rules</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>rewrite</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>system.webServer</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>configuration</span><span class="token punctuation">></span></span>
</code></pre>
<p>This markup will redirect all requests to the public folder, and it will enable newer fonts (like woff). This will also force a trailing slash. Now git commit the project and have azure pick up the files from github/bitbucket/git, etc.</p>
<p>If you need to see a complete example of this, grab the <a href="https://github.com/TerribleDev/blog.tparnell.io">code for this blog</a>.</p>
Why I moved from Ghost to Hexo2015-11-26T01:36:56Zhttps://blog.terrible.dev/blog/Why-I-moved-from-Ghost-to-Hexo/<p>Blogging right? I can't believe I somehow stuck with it all this time. Even when I took a long break I still kinda blogged. I got started after being <s>convinced</s> inspired by a <a href="http://blog.normmaclennan.com">coworkers</a> passion to start blogging. To say the least he, and I have very similar tastes, and he turned me on to ghost, and the ghostium theme. After a year and a half of Ghost blogging I have left Ghost.</p>
<!-- more -->
<h2>Why I still love Ghost</h2>
<p>I was a huge supporter of Ghost from the start. Especially, since at the time my options were Jekyll, Wordpress, or Ghost. I hopped on when it was very new (I think I was on the second release of ghost). Ghost was the engine to really popularize the minimalist blog editor experience. The editor panel is just a editor on the left and a preview pane on the right. When compared to something like wordpress, Ghost really shines as the minimalist approach.</p>
<p>Ghost has plenty of customization options, fantastic themes, and a great community. I want <strong>everyone</strong> to know that I still like ghost, and I would still recommend it.</p>
<h2>Why I left Ghost</h2>
<p>So I run all my applications in Azure. Now that I really understand how continuous deployments work I really want to make it easier to host things.</p>
<h4>Lack of updating</h4>
<p>One of my major problems with Ghost over the last 1.5+ years is the overall lack of releases. We have hardly seen many new features, and promised analytics dashboards have become a thing we don't talk about. I remember seeing a screen cap of ghost with pie charts and traffic graphs outlining a possible, but still not delivered future. The platform has gotten better, but no new major features have really come out.</p>
<h4>Server runtime with no server features</h4>
<p>Some things I were really hoping for with ghost were dynamic features. Blog's are basically a static website, once the html has been generated, so the only reason to incur a server runtime is when you are going to have advanced server features (auto translations, scheduled publishes, etc). Since static site generators like hexo are just ran off the CLI, I can easily setup scheduled publishing with a basic bash script, and CircleCI.</p>
<h2>Why Hexo?</h2>
<p>In today's open source, modern world there are <strong>many</strong> static site generators spanning the ecosystem. I'd like to say that I just asked my <a href="https://blog.normmaclennan.com">coworker</a>, and I'd be lying if I said I hadn't.</p>
<p>I was looking at Octopress (aka Jekyll), Hugo, and a few others. I found some awesome themes for Jekyll, but I landed on Hexo. Ruby gems really bother me. You can have 5 different versions of a gem installed on your machine and unless you prefix your commands with <code>bundle exec</code> any random one could be used. I'm a fan of golang, but JavaScript just lends itself for easily plug-ability (as do most dynamic languages). Also Hexo has great documentation, a pretty cool community, and is straightforward to use.</p>
<h2>Why I would still recommend Ghost</h2>
<p>I would say ghost is still an incredible to use blog engine. For people intimidated by CLI tools, or who don't understand how SCM works, ghost is for you. Ghost is a very minimal, easy to use blog engine. I never felt held back by ghost, and I always felt inspired to write when using it. Ghost performs well and the community is awesome.</p>
How the ASP.NET team made the web framework I have always wanted2015-11-14T12:42:42Zhttps://blog.terrible.dev/how-the-asp-net-team-dived-into-my-head-and-made-the-webframework-i-have-always-wanted/<p>So I know I do a lot of blogging about C#, or JavaScript, but I actually do a lot of nodejs apps as well as other languages. For a very long time I have not found the stack of my dreams. .NET has always been very close but there were multiple things about the app model that I was not a fan of. I think NancyFX has been the closest framework to my dreams in .NET land.</p>
<!-- more -->
<h2>.NET 4x and my gripes</h2>
<p>.NET 4x is the current generation of the application model. Made over 15 years ago, it makes a lot of assumptions about development that are not true today. No builtin dependency injection, and the ASP.NET pipeline being baked into IIS, it is less than fun to work with.</p>
<h4>JS frameworks</h4>
<p>So the first huge gripe for me in asp 4.x land is when I go file->New I get a project that has bootstrap from nuget. The first time I saw this I was fine with it, however as bower got more mature I really started to hate it. You can't delete the js file and restore it at build time so you have to add toxicity to your git repo by holding onto the file.</p>
<h4>CS proj (and javascript)</h4>
<p>I really enjoy using Atom, or Webstorm for Javscript. Visual studio is not in my mind when working on JavaScript applications. However when I work on SPA's for ol' .NET the files would have to have a csproj reference if I wanted to make a web deploy package that contained the file. The only other <a href="https://blog.terrible.dev/using-bower-and-grunt-with-a-net-app/">route I found</a> was to make some special MSBUILD tasks that included adding a whole folder as content at build time. This was fine until I'd work with someone whom really liked using VS for programming and none of my files were in the csproj.</p>
<h4>Webapi vs MVC</h4>
<p>I'm not going to go into too much detail on this, but if you have worked in .net at all you know the pains of webapi and MVC. Webapi was a separate framework that looked really similar as MVC to host rest APIs. They had similar functionality with action filters, but when you would try to use a webapi actionfilter for MVC you wouldn't be able to without your class inheriting from both interfaces and thus requiring additional work. They had very similar models but ultimately different implementations and namespaces making working with them both a pain.</p>
<h4>Windows</h4>
<p>I am a long time Linux guy. I love having tail, grep, awk, sed, and the various other tools that come by default in the bourne shell. I often enjoy using zsh. I really wanted to love .NET, because I really do enjoy writing C#, but not supporting linux was a huge bummer for a long time. My <a href="https://blog.terrible.dev/how-the-asp-net-team-dived-into-my-head-and-made-the-webframework-i-have-always-wanted/normmaclennan.com">coworker </a> and I had a site about mono and how to <a href="https://github.com/maclennann/usemono-net/wiki/Getting-Started-with-Mono">get started</a>. We were self hosting Nancy in Nginx and it was awesome, but we couldn't use anything that didn't have great support at work. When containers started to get big, all my colleagues writing Java were showing me their ECS clusters while I was (and still am) over here hoping that IIS would install under 2 minutes in EC2. I have many problems with windows, beyond those gripes, but I won't go into them here. To say the least I will be keeping ubuntu on my machine from now on.</p>
<h2>The future and .NET 5x</h2>
<p>.NET 5 is a huge reboot over the existing application model. Self hosting on a web server called <a href="https://github.com/aspnet/KestrelHttpServer">Kestrel</a> This application model has <strong>many</strong> distinctions which I always wanted.</p>
<h4>Choices</h4>
<p>The whole thing is built on one simple philosophy, and this philosophy I LOVE. This is that if you want something you can include it, if you don't want something you can exclude it. For example if you really want static files then include the static files package, if you don't then don't include it. This approach allows people to really juice the performance of their application, and was the basis for NodeJS development. Also with MacOS and Linux support, your choice has now extended past Windows.</p>
<h4>Dependency Injection</h4>
<p>The Application Model has a built in dependency injector that works very well. If you need something get it from the DI container. If you controllers need things just have a constructor that requires those types, the DI container will take care of it for you. No more downloading Autofac and messing around trying to set that kind of thing up.</p>
<h4>Modern Javascript support</h4>
<p>All of your client side javascript (bower packages, etc) can go into a folder called wwwroot. This folder takes on the root path at runtime, and everything is always included which means using bower to get deps is 100% possible. You need minification? Use what the JS community has.</p>
<h4>No more csproj</h4>
<p>So its 5pm on a friday. I have just added a file to my project, git committed, and the build failed. I go and realize that I forgot to save my csproj file and thus the build is missing a file. This happens to me more than I dare to admit. In the future everything works off the local disk, no more csproj xml, thus no more failed builds for ceremonious xml files.</p>
<p>Overall the future looks really bright for .NET I really hope they can escape the mentality of .NET == windows and hopefully get some more traditional Linux people on the stack.</p>
Securing AWS Elasticsearch Service with .NET NEST API (and why I love open source)2015-11-07T01:41:18Zhttps://blog.terrible.dev/securing-aws-elasticsearch-service-and-nest-api/<p>Around 6 months ago I started a project, and part of that project was to move us away from an old search tool to use elasticsearch.</p>
<!-- more -->
<p>For those of you whom are unfamiliar <a href="https://www.elastic.co/">elasticsearch</a> is a web service over <a href="https://lucene.apache.org/core/">Lucene</a> which provides a document database that can perform complex transforms on text specifically designed for search. Elasticsearch does things like stop word removal and <a href="https://www.elastic.co/guide/en/elasticsearch/guide/current/controlling-stemming.html">stemming</a> to provide a fantasic way to perform searches.</p>
<p>I was browsing my twitter feed one day and I saw this thread.</p>
<blockquote class="twitter-tweet" lang="en"><p lang="en" dir="ltr"><a href="https://twitter.com/jdcooke0117">@jdcooke0117</a> Like off the bottom of the charts? Because you couldn't even run ES before but now you can?</p>— Norm MacLennan (@nromdotcom) <a href="https://twitter.com/nromdotcom/status/649723904563396608">October 1, 2015</a></blockquote>
<p>I got curious as ES usually stands for Elasticsearch, and I quickly found out that AWS <a href="https://aws.amazon.com/blogs/aws/new-amazon-elasticsearch-service/">announced</a> Elasticsearch as service.</p>
<p>This was pretty huge for me since a few months before I struggled to string together some code that someone else at my company wrote to get elasticsearch working in AWS, and to be honest it was not fun. Managing elasticsearch in AWS is far from great.</p>
<p>We started out with a basic 'domain' (which is AWS' term for an elasticsearch cluster) and we got up and running pretty fast. The 'domains' seemed to have almost all the API's we needed, and it worked with the <a href="http://nest.azurewebsites.net/">NEST client</a>.</p>
<p>When we were just trying it out we didn't bother securing it, but when we needed to secure the instance, we realized things were not so fun. AWS lets you block access by ip which doesn't help because EC2 instances have different ip addresses as the time, or you can use IAM roles, except you can't just target existing machines you have to sign the requests.</p>
<p>Eventually we bit the bullet and decided to sign our requests to the cluster. Unfortunatly the SDK doesn't provide a utility to sign any ol' http requests. I started digging through the AWS docs to figure out how to sign requests, and I was getting worried, as the docs do not make it seem easy to pull off. As an act of desperation I dived into nuget and just typed aws elasticsearch, which I then stumbled across a <a href="https://github.com/bcuff/elasticsearch-net-aws">project that was published only days before</a>.</p>
<p>This project totally saved my bacon. Brandon's library plugged right into the .NET sdk, and auth'd our requests to aws without us having to figure out all that crypo. Within moments of finding it I filed an <a href="https://github.com/bcuff/elasticsearch-net-aws/issues/1">issue</a> thanking Brandon as it really helped me out.</p>
<p>The Elasticsearch service offering by Amazon is pretty awesome. Like any platform its less flexible then hosting the instances yourself. You have to live with the plugins they ship, but on the plus side you get a full cluster, with monitoring, and a knob to turn up instances, or storage space without having to worry about the details.</p>
Wiring up client side logs into c#/node.js logging frameworks2015-11-01T08:22:07Zhttps://blog.terrible.dev/wiring-up-client-side-logs-into-c-sharp-logging-frameworks<p>Around a year ago I joined a new team where I work, and this team was starting to undertake a full rewrite of their code. We were going from a full c#/mvc app to a tiny c# api, and a very big SPA.</p>
<p>Early one one of the <strong>huge</strong> things to do was to make sure that our JavaScript error logs could land in our Log4Net infrastructure. I started to write something to do just that, and as I was coding I quickly realized this was less trivial that it sounded. We had something internal we could use, but it was tied to a lot of other code that we didn't want to pull in.</p>
<p>I started Bingling around and I stumbled across <a href="http://jsnlog.com/">jsnlog</a>. JSN log lets you quickly wire up your client side logs to your server. I have been able to get PR's into the <a href="https://github.com/mperdeck/jsnlog">code base</a> and the guy behind it has been very friendly to me when I have had questions.</p>
<!-- more -->
<p>When you install the nuget package it drops this into your app_start.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">using</span> <span class="token namespace">System</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Routing</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Mvc</span><span class="token punctuation">;</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token target keyword">assembly</span><span class="token punctuation">:</span> <span class="token class-name">WebActivatorEx<span class="token punctuation">.</span>PostApplicationStartMethod</span><span class="token attribute-arguments"><span class="token punctuation">(</span>
<span class="token keyword">typeof</span><span class="token punctuation">(</span><span class="token type-expression class-name">EmptyLog4Net<span class="token punctuation">.</span>App_Start<span class="token punctuation">.</span>JSNLogConfig</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"PostStart"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token keyword">namespace</span> <span class="token namespace">EmptyLog4Net<span class="token punctuation">.</span>App_Start</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">JSNLogConfig</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">PostStart</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Insert a route that ignores the jsnlog.logger route. That way,</span>
<span class="token comment">// requests for jsnlog.logger will get through to the handler defined</span>
<span class="token comment">// in web.config.</span>
<span class="token comment">//</span>
<span class="token comment">// The route must take this particular form, including the constraint,</span>
<span class="token comment">// otherwise ActionLink will be confused by this route and generate the wrong URLs.</span>
<span class="token class-name"><span class="token keyword">var</span></span> jsnlogRoute <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Route</span><span class="token punctuation">(</span><span class="token string">"{*jsnloglogger}"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">StopRoutingHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
jsnlogRoute<span class="token punctuation">.</span>Constraints <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">RouteValueDictionary</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token string">"jsnloglogger"</span><span class="token punctuation">,</span> <span class="token string">@"jsnlog\.logger(/.*)?"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
RouteTable<span class="token punctuation">.</span>Routes<span class="token punctuation">.</span><span class="token function">Insert</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> jsnlogRoute<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The whole thing is a html handler, so this code just simply makes sure the handler gets the first route.</p>
<p>When you are going to render a page you have to inject this razor:</p>
<p><code>@Html.Raw(JSNLog.JavascriptLogging.Configure())</code> and the jsnlog javascript file.</p>
<p>Then whenever you want to log anything client side you can do the following.</p>
<pre class="language-javascript" tabindex="0"><code class="language-javascript"><span class="token constant">JL</span><span class="token punctuation">(</span><span class="token string">"jsLogger"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fatal</span><span class="token punctuation">(</span><span class="token string">"client log message"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>You can also set jsnlog as the global js error handler.</p>
<pre class="language-javascript" tabindex="0"><code class="language-javascript">window<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">errorMsg<span class="token punctuation">,</span> url<span class="token punctuation">,</span> lineNumber<span class="token punctuation">,</span> column<span class="token punctuation">,</span> errorObj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Send object with all data to server side log, using severity fatal,</span>
<span class="token comment">// from logger "onerrorLogger"</span>
<span class="token constant">JL</span><span class="token punctuation">(</span><span class="token string">"onerrorLogger"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fatalException</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token string-property property">"msg"</span><span class="token operator">:</span> <span class="token string">"Exception!"</span><span class="token punctuation">,</span>
<span class="token string-property property">"errorMsg"</span><span class="token operator">:</span> errorMsg<span class="token punctuation">,</span> <span class="token string-property property">"url"</span><span class="token operator">:</span> url<span class="token punctuation">,</span>
<span class="token string-property property">"line number"</span><span class="token operator">:</span> lineNumber<span class="token punctuation">,</span> <span class="token string-property property">"column"</span><span class="token operator">:</span> column
<span class="token punctuation">}</span><span class="token punctuation">,</span> errorObj<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Tell browser to run its own error handler as well</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The docs are quite good, and it seems to work fine as a commonjs module (since we browserify things). The tool is super configurable through the web.config, and you can change the url it logs to.</p>
<pre class="language-xml" tabindex="0"><code class="language-xml">
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>configuration</span><span class="token punctuation">></span></span>
...
<span class="token comment"><!-- Example of web.config based configuration --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>jsnlog</span> <span class="token attr-name">maxMessages</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>5<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>logger</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mylogger<span class="token punctuation">"</span></span> <span class="token attr-name">level</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>INFO<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ajaxAppender</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>myappender<span class="token punctuation">"</span></span> <span class="token attr-name">batchSize</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>logger</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mylogger2<span class="token punctuation">"</span></span> <span class="token attr-name">appenders</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>myappender<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>jsnlog</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>configuration</span><span class="token punctuation">></span></span>
</code></pre>
<p>JSNLog is a great way to get your client side logs into your server infrastructure fast. The library has fantastic support for node, and every major <a href="https://www.nuget.org/packages?q=jsnlog">.NET logging framework</a>. Someone in the community even made a php plugin! The <a href="https://github.com/mperdeck/jsnlogSimpleWorkingDemos">examples</a> are endless</p>
<p>Overall I am really pleased with JSNLog, it filled a need that I needed, and it meant I was able to focus on what I did best, not figure out how logging worked.</p>
<hr>
Moving from beta 7 to beta 8 in ASP.NET 5 (MVC 6)2015-10-18T14:16:59Zhttps://blog.terrible.dev/moving-from-beta-7-to-beta-8-in-asp-net-5-mvc-6/<p>So Beta 8 was recently <a href="http://blogs.msdn.com/b/webdev/archive/2015/10/15/announcing-availability-of-asp-net-5-beta8.aspx">announced</a>, and I thought I'd update <a href="http://dotnetmashup.azurewebsites.net">DotNetMashups</a> to beta 8.</p>
<p>In case you havn't been paying attention, recently it was announced that <a href="https://github.com/aspnet/Announcements/issues/69">helios</a> was no longer a thing. Helios was the loader for ASP.NET 5 in IIS. Instead they are using the <a href="https://azure.microsoft.com/en-us/blog/announcing-the-release-of-the-httpplatformhandler-module-for-iis-8/">http Platform Handler</a> to proxy the connections to <a href="https://github.com/aspnet/KestrelHttpServer">kestrel</a>.</p>
<p>So I thought that this was going to be a difficult update. I loaded the <a href="https://github.com/aspnet/Announcements/milestones/1.0.0-beta8">announcements repo</a> in my browser and got to work. You can view the <a href="https://github.com/TerribleDev/DotNetMashup/pull/8/files">Pull request here</a>.</p>
<!-- more -->
<p>The first thing I did was update my visual studio tools, do a <code>dnvm update</code>, then update my packages to use beta8. I then ran into was 2 build errors in my startup.cs It seemed that <code>app.UseErrorPage();</code> was renamed to <code>app.UseDeveloperExceptionPage();</code> which seems like a sensible rename. The second thing was that <code>app.UseErrorHandler("/Home/Error");</code> became <code>app.UseExceptionHandler("/Home/Error");</code> again 100% sensible.</p>
<p>I deleted my hosting.ini, I changed my web command from using <code>"web": "Microsoft.AspNet.Hosting --config hosting.ini"</code> to <code>"web": "Microsoft.AspNet.Server.Kestrel"</code> and I set my web.config to look like the following. That was basically it. Overall really simple!</p>
<pre class="language-xml" tabindex="0"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>configuration</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>system.webServer</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>handlers</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>add</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>httpPlatformHandler<span class="token punctuation">"</span></span> <span class="token attr-name">path</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>*<span class="token punctuation">"</span></span> <span class="token attr-name">verb</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>*<span class="token punctuation">"</span></span> <span class="token attr-name">modules</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>httpPlatformHandler<span class="token punctuation">"</span></span> <span class="token attr-name">resourceType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Unspecified<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>handlers</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>httpPlatform</span> <span class="token attr-name">processPath</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>%DNX_PATH%<span class="token punctuation">"</span></span> <span class="token attr-name">arguments</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>%DNX_ARGS%<span class="token punctuation">"</span></span> <span class="token attr-name">stdoutLogEnabled</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span> <span class="token attr-name">startupTimeLimit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>3600<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>system.webServer</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>configuration</span><span class="token punctuation">></span></span>
</code></pre>
Why I avoid switch statements in c++2015-10-04T16:26:38Zhttps://blog.terrible.dev/why-i-avoid-cplusplus-switch-statements/<p>So one thing that kills me a lot in c++ is the switch statement. As you all know switch statements look like the following.</p>
<pre class="language-cpp" tabindex="0"><code class="language-cpp"><span class="token keyword">auto</span> s <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">switch</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token number">0</span><span class="token operator">:</span>
<span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">:</span>
<span class="token function">doSomething1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<!-- more -->
<p>Now the first thing that bothers me about C++ switch statements is that, you can fall through a case. What I mean by that is that if <code>case 0</code> did not have a <code>break;</code> statement, you will go directly into the next case (and execute <code>doSomething1()</code>)</p>
<p>This often bites me in particular, becase I forget to add the <code>break;</code></p>
<h3>Switching on strings</h3>
<p>In c++ strings are not supported as a type. Strings in c++ are actually char Arrays, which means that the switch statement cannot infer switching on strings like Java or C#.</p>
<p>So ultimately switching on strings cannot be done, and if/else if is what has to be used for strings.</p>
<p>So I can't use <code>switch</code> except for the other common types, and I can shoot myself in the foot with the behavior of the switch. So I avoid it completely.</p>
c++, when should I use the stack or heap?2015-10-04T15:58:18Zhttps://blog.terrible.dev/c-strings/<p>So I have started learning c++ recently, and as a .NET/Java developer I always want to write the following code.</p>
<p><code>var s = new myClass()</code>.</p>
<p>In c++ you have to manage memory yourself, there is no garbage collector.</p>
<p>If you do not use the new keyword <code>var s = myClass()</code> you will create that class and assign it to on the <code>stack</code>.</p>
<p>Any stack variables will be cleaned at the end of the block, so in this case s will be cleaned. However if you use <code>var s = new myClass()</code> s will be allocated onto the <strong>heap</strong> and must be deleted, otherwise memory leaks will occur.</p>
<p>To clean the variable you must call <code>delete</code> when you are done with the variable, this will cause the memory in the heap to be cleaned.</p>
<!-- more -->
<p>Now this comes back to <em>what is a stack and heap</em> I wrote a <a href="https://blog.terrible.dev/value-types-vs-reference-types-in-c-and-why-it-matters/">blog post</a> about value and reference types in c# and this talk touches on a lot of the same subject. Basically a stack in c++ is a 1mb scratch pad of memory, that is really fast to access. The heap is a larger pool of memory for dynamic allocation, but can be slower to access.</p>
<p>So I was thinking to myself, well when should I allocate on the stack vs heap. The stack is limited in size, and if you go over that size you will cause a stack overflow. Also I want my c++ app to be fast, so I would like to allocate on the stack often, and I don't have to worry about cleaning up stack objects. That being said the heap is still quite fast so I shouldn't avoid the heap.</p>
<p>Consider any or all of the following rules to put objects into the stack. <strong>Note:</strong> You don't need to meet all of them.</p>
<h4>Stack Allocate:</h4>
<ul>
<li>Immutable</li>
<li>Under 32 bytes (Ideally around 16 bytes)</li>
<li>It won't require being put into heap often</li>
<li>Short Lived</li>
<li>Embedded in other objects</li>
</ul>
Less Pager duty, more Yak duty. My (Strange) DevOps (rant) story.2015-09-28T05:34:03Zhttps://blog.terrible.dev/less-pager-duty-more-yak-duty-my-strange-devops-rant-story/<p>Growing up I always wanted to work with electronics, and as soon as I could work I was working with a computer. I currently work as a Software Engineer at <a href="http://vistaprint.com">Vistaprint</a>. I work on the Gallery team, which is an agile development team that works on our platform to display products in a gallery (hence the name). Before I joined the gallery team, I spent most of my career doing ops things.</p>
<!-- more -->
<p>When I started working in the industry I was really interested in working with scaled out infrastructure. Any large compute things I had an interest in, which lead me to be more or less an 'Ops' person. Over the course of this period I did quite a bit of networking, VMware, and LDAP administration. My first real gig was working for a school district. Staff, and students combined was 6000, and we quickly realized the only way for our team of 3 to be effective was to write code. This was my first real introduction into programming (yup, I was a late bloomer to programming).</p>
<p>I always thought programming was something done by PhD types, and I never thought I'd be smart enough to do it. I didn't have the privilege of going to a great University. In fact I got my degree while working in the Industry, this left me with a lot of insecurities early on in my career. I am a creative person, and I always thought I'd be good as a full stack Web Developer. I tried to learn JavaScript in 2005, and decided that programming was too hard, not realizing that js, and the DOM API's were working against me.</p>
<p>I think the first time programming really 'clicked' for me was when I needed to create a script to move around 1000 users from one OU to another in Active Directory. I quickly started Googling on the ol' Bing, and I managed to whip something together with the multitudes of knowledge out there.</p>
<blockquote>
<p>This was the first time that I had a real taste of the power programming can unlock, and that power was intoxicating.</p>
</blockquote>
<p>Over the course of my ops career I started creating a lot of tooling to pursue the goal of faster, more flexible infrastructure. During this time I noticed that some of my colleagues really started acting different around me.</p>
<blockquote>
<p>All of a sudden, I felt very alienated from the rest of the operations community, but I wasn't being embraced by most of the developers either.</p>
</blockquote>
<p>I think a lot of the culture issues quickly I faced subsided when we had <em>Insert large amount</em> of copies of the Phoenix Project floating around the office.</p>
<p>While I working on a team with <a href="https://www.linkedin.com/profile/view?id=15269002">Sarah Flint</a>, and <a href="https://www.linkedin.com/profile/view?id=75343021">Matt Alioto</a> called Automation Task Force (that is the actual name). One of my good friends <a href="http://nickpirollo.net/">Nicholas Pirollo</a> mentioned I should join the gallery team. This was further reinforced by <a href="https://www.linkedin.com/pub/drew-ditto/52/786/927">Drew Ditto</a> the lead developer. As someone who spent their entire career in ops, and never thought about being a Software Engineer. I was immediately skeptical if I could even add value to their team. I took the risk, and plunged into what is basically a new career.</p>
<p>The one amazing thing about Vistaprint...erm..Cimpress is the fluidity at which people can grow, and change their careers (and I'm not getting paid to write this either). I've grown a ton over the last 4 years already. Within a month of saying "sure I'll come work for you guys" I was on their team, and was already working on some major changes that I probably shouldn't hint about.</p>
<p>My being on this team has certainly helped things move a little. A lot of ops people have come to me for dev-centric questions, and I have been increasingly helpful in providing them a perspective of what developers at Cimpress want. While also telling the people on my (new) team, how to structure requests to the ops teams, and how we can make our application(s) more accessible to our operations brethren. That being said I didn't write this to give you the typical 'DevOps' story, but unfortunately as I write this it is slowly turning out this way.</p>
<p>I feel that I have matured a lot. I have really started to understand the problems developers around me face, when they have little domain knowledge on what would be more traditional IT things. I am not really good at understanding human relationships, but this move as certainly made me realize how two groups of very similar people can be different. The one thing that has really irked me lately is both of these groups of people have more things in common, than differences. Yet both groups seem hell bent to point out each others failings.</p>
<p>I guess my whole point in this whole thing is to try to gain someone else's perspective. That is probably what mixed Developer/Ops teams try to gain. Lets be honest dev's and op's have more or less a symbiotic relationship. Even with every cloud technology at you command, you will still need ops people once you get to a certain scale, and ops people cannot administrate systems that don't do anything. Lets come together and get along, for the good of <strong>OUR</strong> industry.</p>
<p><strong>tl;dr</strong> I was a sysadmin, now a dev. Why Can't we all get along?</p>
How .ToLookup() Saved me 4 hours a week, and got me some high praise from my boss2015-09-14T13:36:08Zhttps://blog.terrible.dev/how-tolookup-saved-me-4-hours-a-week-and-got-me-some-high-praise-from-my-boss/<p>I recently created a small utility that is ran in jenkins to create indicies in <a href="https://www.elastic.co/webinars/get-started-with-elasticsearch?elektra=home&storm=banner">ElasticSearch</a>.</p>
<p>The first versions took around 5 hours to index our massive data into elasticsearch. This was still better than the 9 hours, our old solution took, so no one was complaining.</p>
<p>One of the major slowdowns was a <code>.Where()</code> on a <code>List<T></code>. When I wrote the tool this TODO was written</p>
<blockquote>
<p>//TODO: use some kind of key lookup here, but we need non-unique keys and Dictionaries are unique only</p>
</blockquote>
<!-- more -->
<p>Basically I was doing <code>.Where(a=>a.Id == SomeVal)</code>, and from what I can tell in the <a href="http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,141">source</a> <code>.NET</code> was doing this by looping over the whole collection. People smarter than me would point out that this is an <code>O(n)</code> operation.</p>
<p>What caused the bottleneck was this <strong>huge</strong> collection (I'm talking in the realm of 8000+ entities) we were looping over. I <strong>knew</strong> we wanted to do key lookups, but I cannot know every little thing in the BCL (Base Class Library). The only collection I knew of for key lookups (dictionary) was for <strong>unique keys</strong> only. This was a problem, as my keys were not unique.</p>
<p>One day while looking at some of the linq extensions I found the <a href="https://msdn.microsoft.com/en-us/library/system.linq.enumerable.tolookup(v=vs.90).aspx">ToLookup()</a> extension which converted the current collection to an <a href="https://msdn.microsoft.com/en-us/library/bb460184(v=vs.90).aspx">Lookup</a> class.</p>
<p>After reading the documentation I knew this was the perfect collection for me. Essentially it groups multiple entities by key, which means it returns a collection of your results grouped on the keys. This would transform my <code>O(n)</code> operation to an <code>O(1)</code> operation. Eventually I landed on something like this.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> col <span class="token operator">=</span> hugeCollection<span class="token punctuation">.</span><span class="token function">ToLookup</span><span class="token punctuation">(</span>a<span class="token operator">=></span>a<span class="token punctuation">.</span>id<span class="token punctuation">,</span> a<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> lookupResults <span class="token operator">=</span> col<span class="token punctuation">[</span>IdToLookup<span class="token punctuation">]</span>
</code></pre>
<p>This ultimately lead to our application's run time going from 5 hours to 40 minutes. Now really this didn't save me 4 hours as much as it saved jenkins, but it did allow changes we made into elasticsearch faster which means we could make more changes, and tighten our feedback loops.</p>
Drastically altering view behaviors using custom DisplayFor templates C# MVC2015-09-13T16:08:47Zhttps://blog.terrible.dev/custom-mvc-display-templates-2/<p>One feature that I think is highly under-documented in the C# MVC framework is custom <code>DisplayFor</code> and <code>EditorFor</code> Templates.</p>
<p>By simply making folders in your views folder called <code>DisplayTemplates</code> and <code>EditorTemplates</code> you can use the <code>DisplayFor(a=>a.TypeHere)</code> and <code>EditFor(a=>a.TypeHere)</code> with any custom types you so choose.</p>
<!-- more -->
<pre><code>-Controllers
-Views
-- Home
---- DisplayTemplates
------ CustomTypeName.cshtml
</code></pre>
<p>So I thought to myself how this would be useful, and I have come up with a demo in <a href="https://github.com/TerribleDev/CSharp-MVC-Plugin-Views">github</a></p>
<p>Essentially it goes like this. I have a bootstrap grid that we could fill with multiple tiles. This would be good if you were to show a gallery of images, and perhaps certain tiles would have different behavior. In my example I have 1 tile that displays an image, and another tile that displays some text.</p>
<p>I created an interface called <code>ITile</code> and had my ImageTile, and TextTile inherit from this interface.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ImageTile</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ITile</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> src <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TextTile</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ITile</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> Text <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ViewModel</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token return-type class-name">ICollection<span class="token punctuation"><</span>ITile<span class="token punctuation">></span></span> Tiles <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>So my controllers simply creates these tile objects. The main view loops over the tiles and calls a partial view that looks like this.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
@model <span class="token return-type class-name">DisplayTemplateExample<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Models<span class="token punctuation">.</span>ITile</span>
@Html<span class="token punctuation">.</span><span class="token function">DisplayFor</span><span class="token punctuation">(</span>a<span class="token operator">=></span>a<span class="token punctuation">)</span>
</code></pre>
<p>Then I created 2 templates in <code>Views/Shared/DisplayTemplates</code> One named ImageTile.cshtml, and the other named TextTile.cshtml <strong>note:</strong> the razor file names have to line up with the type name.</p>
<p>Then in each of these views I have different html returned</p>
<pre><code>@model DisplayTemplateExample.Web.Models.ImageTile
<a href="#" class="thumbnail">
<img src="@Model.src" />
</a>
</code></pre>
<pre><code>@model DisplayTemplateExample.Web.Models.TextTile
<div class="thumbnail">@Model.Text</div>
</code></pre>
<p>Ok so I'm sure you are now thinking whats the point? My point is that our entire view infrastructure, has no idea the items in the <code>ITile</code> collection will create different html. This allows the Controllers to add or change the downstream behavior based on SessionContext, or anything you wish. The ultimate thing this empowers is the ability to create a <em><strong>pluggable</strong></em> view infrastructure where the type inheritance control what occurs in the view layer. The huge downside is the debugging experience is not stellar.</p>
Fixing: Could not load file or assembly 'Microsoft.Dnx.Host.Clr'2015-09-09T14:08:18Zhttps://blog.terrible.dev/fixing-could-not-load-file-or-assembly-microsoft-dnx-host-clr-2/<p>So I recently ran into this error where the latest bits could not load Microsoft.Dnx.Host.Clr here is what I did to fix it.</p>
<!-- more -->
<ul>
<li>Followed the instructions from the <a href="https://github.com/aspnet/Announcements/issues/51">beta7 announcements</a></li>
<li>Installed the <a href="http://www.microsoft.com/en-us/download/details.aspx?id=48222">latest web tools</a> <strong>warning</strong>: there are multiple MSI's in that link. Install the WebToolsExtensions</li>
<li>Updated my runtime <code>dnvm upgrade -u -r clr</code></li>
<li>Made sure my project was set to use the latest runtime</li>
<li>Updated my nuget packages <code>dnu restore</code></li>
</ul>
<p>Afterwards everything seemed to work.</p>
Avoid the Godclass2015-09-05T13:28:12Zhttps://blog.terrible.dev/avoid-the-godclass/<p>I joined a team earlier this year, who own a core set of pages on our website. This part of the site makes us <strong>buckets</strong> of money, and was written by people whom are clearly smarter than me. However every platform is not without its quirks.</p>
<p>Most of the code is C# MVC but a lot of the problems with the platform are more historic architecture, and less <code>.NET</code> specific.</p>
<!-- more -->
<h4>Dependency Management</h4>
<p>The early creators of the platform had a model we will call WidgetModel. WidgetModel, initially was a basic representation of our view layer before templating. Over the course of many short deadlines, poor management, and continuous growth, the model became more than a simple model.</p>
<p>To say the least, parts of the application state ends up being stored in this model, along with Session data. WidgetModel gets passed around everywhere, and way more than half of the codebase took a dependency on the model. Any changes to this model require major application refactors.</p>
<p>I even found SprocketFactory that took in a WidgetModel and added itself to WidgetModel, then called a function in WidgetModel that needed a dependency to SprocketFactory. Just take a moment to grok how terrible that is.</p>
<h4>Contexts</h4>
<p>So I'm sure you are thinking, well WidgetModel not great but atleast you can use it always right? <strong>wrong</strong></p>
<p>Our application was originally a WebForms application, that was <s>transformed</s> pummeled into an MVC architecture. Our version of MVC still has weird ViewState crazyness, and was ultimately bolted on.</p>
<p>WidgetModel has very <strong>deep</strong> dependencies to certain session context objects. These objects are largely <strong>unavailable</strong> in an API request. So WidgetModel must not be used in an API.</p>
<h4>DI, Not always your friend</h4>
<p>Now when I first started I thought it would still be ok, because they must get their dependencies from somewhere. Most paradigms I see in .NET dependencies are given through constructors.</p>
<p>However this was not the case. I found the following in all classes that needed WidgetModel.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token return-type class-name">WidgetModel</span> GodModelRARRRR
<span class="token punctuation">{</span>
<span class="token keyword">get</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> RandomDependencyContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Get</span><span class="token generic class-name"><span class="token punctuation"><</span>WidgetModel<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Basically they got WidgetModel from a dependency injector in a property getter. So whenever someone writes code for our API 3/4 times while developing someone calls a class that calls a class that wants WidgetModel really badly, that causes our whole application to blow up.</p>
<h4>Solving this Problem</h4>
<p>We didn't have the scope to re-write everything. Rewriting most of the code was a year long project by itself. We also needed to keep parts of our app. Our attitude was simple,</p>
<blockquote>
<p>Rewrite as an SPA.</p>
</blockquote>
<p>If we are entirely a JavaScript SPA, and we only call API's we won't be able to accidentally take a dependency on WidgetModel. This approach is leading us to delete WidgetModel all together. The 1/4 of the app that didn't have the dependency to WidgetModel was actually maintainable.</p>
<p>The great part about this was, we could burn down most of our code, while keeping a huge chunk that was actually quite maintainable.</p>
Razor Websites, lightweight C# web coding2015-09-03T21:56:34Zhttps://blog.terrible.dev/razor-websites-super-lightweight-c-webdev/<p>I was exploring around github, and I stumbled upon an interesting project called <a href="https://github.com/madskristensen/miniblog">Miniblog</a> which was a lightweight blog engine written in c#. The thing that immediately stood out to me was the lack of a <code>.csproj</code> file.</p>
<blockquote>
<p>As I dug around the code I realized this was not a Web App, which most of us were familiar with, but a websites project. I then suddenly realized that the whole thing only used razor!</p>
</blockquote>
<p>I am a huge fan of <a href="http://nancyfx.org/">Nancyfx</a> because its much more lightweight than the MVC framework created at Microsoft. To say the least I am a massive fan of small tools, and micro frameworks. So when I realized this whole thing was powered by razor only I was immediately impressed.</p>
<p>I decided to dig around on the internet to see if anyone else was talking about this. I found out quickly that it has been possible for <a href="http://www.hanselman.com/blog/ExploringASPNETWebPagesAFullyfeaturedMiniBlogUsingJustRazor.aspx">some time</a>, but I didn't find many references about it.</p>
<p>The one thing that bummed me out about the Miniblog example was that it was not a web app. You can use nuget packages will websites, but you cannot make references to other projects in the solution. This was a problem for me, and unlike websites, web app's are precompiled which reduces application startup time.</p>
<!-- more -->
<h2>Why use Razor Websites?</h2>
<p>The biggest reason to use razor websites, is the speed. Razor websites have almost no routing code, and are much more lightweight than a full framework. They are good for small projects, but for complex data access applications a more robust framework should be used.</p>
<h2>Creating a razor website as a web app project</h2>
<p>To create a razor website as a web app project, first create an empty web project, and then just add the following nuget packages.</p>
<pre class="language-xml" tabindex="0"><code class="language-xml">Microsoft.AspNet.Razor
Microsoft.AspNet.WebPages
Microsoft.Web.Infrastructure
</code></pre>
<p>Now you can drop razor files anywhere. Your routes will be the location of your razor pages, so for instance your home page should be <code>Index.cshtml</code> and it should be at the root of your web project. If you had a file called about.cshtml on the root, the route would be <code>/about</code> if it were in a subfolder it would be <code>/subfolder/about</code>.</p>
<p>I even did some tricks where I put razor files in a folder called <code>api</code> and had logic in those views to deserialize the request body to models, and place them in a datastore. This gave the illusion that my ajax calls were somehow hitting some complex API.</p>
<h2>Things to note</h2>
<p>The <code>@model</code> will not work in razor. You can pass an object to another view during a render, and that file can get the object with <code>this.Model</code></p>
<p>If you return something other than text remember to set the content type, and don't hesitate to write directly to the output stream.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token keyword">this</span><span class="token punctuation">.</span>Response<span class="token punctuation">.</span>ContentType <span class="token operator">=</span> <span class="token string">"application/json"</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>Response<span class="token punctuation">.</span><span class="token function">Write</span><span class="token punctuation">(</span>Newtonsoft<span class="token punctuation">.</span>Json<span class="token punctuation">.</span>JsonConvert<span class="token punctuation">.</span><span class="token function">SerializeObject</span><span class="token punctuation">(</span>Database<span class="token punctuation">.</span>Data<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
Navigating the JavaScript waters in 20152015-09-01T23:39:41Zhttps://blog.terrible.dev/navigating-the-javascript-waters-in-2015/<p>In this last year I have done much more JavaScript development than I have before. The landscape, and tools have exploded over the last few years. Gone are the days of JQuery widgets, and come forth have advanced virtual dom libraries, JavaScript servers, and multiple package managers. Along with new language features.</p>
<!-- more -->
<h2>Node.js and io.js</h2>
<p>Right now there are two versions of Node.js. Although fairly soon the code bases will <a href="http://thenextweb.com/dd/2015/06/16/node-js-and-io-js-are-settling-their-differences-merging-back-together/">merge back together</a>.</p>
<p>For those of you whom don't know, node.js is a server side JavaScript environment. io.js was a recent fork of the node.js code base to include newer language features, and updated versions of V8.</p>
<p>In the long run both of these runtimes will merge to make the Node Foundation. In the short term I'd stick with node, unless you have a compelling reason to use io.</p>
<h2>Package Management</h2>
<ul>
<li>
<p><a href="http://bower.io/">Bower</a> - Simple package manager to download files and place them on the file system.</p>
</li>
<li>
<p><a href="http://jspm.io/">jspm</a> - Client side focused package manager</p>
</li>
<li>
<p><a href="https://www.npmjs.com">npm</a> - Package manager mostly focused on shipping CommonJS modules, mostly for node.js</p>
</li>
</ul>
<h2>Modules</h2>
<p>Modules are a pattern that encapsulates JavaScript code so scripts do not have to rely on the global namespace, but instead reference the file definitions.</p>
<ul>
<li>CommonJS essentially defines module patterns with the use of an exports object.</li>
<li><a href="http://requirejs.org/docs/whyamd.html">AMD</a> is a module definition designed for files to be downloaded separately, with the browser in mind.</li>
</ul>
<h2>Great libraries to mention</h2>
<p>These are some of the libraries I have liked. I'm sure I am leaving out many great others.</p>
<ul>
<li><a href="https://babeljs.io/">Babel</a> - ES6 to ES5 transpiler. People use this to write ES6 code, and have it recompile to ES5 for use with older browsers.</li>
<li><a href="http://facebook.github.io/react/">ReactJS</a> Client-Side framework for building UI's. Reacts strength is a Virtual DOM system that figures out what to alter in the UI, and just alters those elements, instead of altering the whole document.</li>
<li><a href="https://lhorie.github.io/mithril/">Mithril</a> - Client Side MVC with Virtual DOM diff system (akin to ReactJS)</li>
<li><a href="https://github.com/wayfair/tungstenjs">Tungstenjs</a> Virtual DOM system using Mustache server side, with plugins for backbonejs and ambersandjs client side.</li>
<li><a href="http://browserify.org/">Browserify</a> A library that bundles commonJS modules into a file for use with the browser.</li>
<li><a href="http://gruntjs.com/">Grunt</a> JavaScript task runner similar to Ant or Rake</li>
<li><a href="http://gulpjs.com/">Gulp</a> Much like grunt, a JavaScript task framework much like Rake</li>
</ul>
Saying goodbye to my VPS (..and my opinions of cloud providers)2015-08-10T22:05:18Zhttps://blog.terrible.dev/saying-goodbye-to-my-vps/<p>I have used <a href="http://linode.com">Linode</a> for quite a long time now. My blog was hosted on linode, as was my StarBound server. My linode was the CentOS Pet I always wanted. Full of manual Fail2Ban configs, I make sure I fed my VPS every day. I even used cowsay to give me a cool message from my pet every login.</p>
<p>The major reason I moved my things away from Linode, was not the devops story itself. I could have stuck with linode, and used chef or something to manage my former friend. I decided to host everything in <a href="http://azure.com">Azure Web apps</a>. Now before I give you my long ramblings why I like azure; I must tell you. I put everything in azure, because my MSDN gave me free credits. There was no huge scientific analysis behind this. The simple fact that I got free money in Azure was the <strong>only</strong> reason why I started using it.</p>
<!-- more -->
<h2>PaaS: Enabling Small Services</h2>
<p>I really like Platform as a Service solutions. They don't work for everything, but I have hosted countless apps in <a href="http://heroku.com">Heroku</a>, <a href="https://aws.amazon.com/">ElasticBeanstalk</a>, <a href="http://azure.com">Azure Web apps</a>, and even <a href="https://pages.github.com/">Github Pages</a>. This blog is hosted on PaaS, my hubot is hosted on PaaS, and even the things I do at work are on a PaaS Solution.</p>
<p>I don't think PaaS is new. I recall going to <s>freewebs</s> <a href="http://webs.com">webs.com</a> in the mid 2000's and uploading my html pages. They took care of the hosting. What I do believe is new, is the pivot on this idea to use SCM, and automatic build tools to constantly push these changes. These types of solutions really empower the <a href="https://en.wikipedia.org/wiki/Unix_philosophy">unix philosophy</a> of making small tools, by simplifying the deployment process.</p>
<p>We really need to move toward a new agile world, and that includes tools that enable fast development, and deployment.</p>
<h2>Why I was on Linode</h2>
<p>I love linode, and when I signed up, Digital Ocean was just getting popular. There are other competitors like RamNode, and you could consider Azure/AWS a competitor as well. The price on Linode is cheaper than AWS, and Azure. The VM's are <strong>really</strong> fast. I am not going to give you metrics, just take my word for it. I ran an Insurgency server with 64 players on a 2 core linode, and the same machine in AWS could not keep up.</p>
<p>I tried Digital Ocean, and they were good. Actually for $5, they were very good. I end up sticking with Linode, because their support is fantastic. I recall filing tickets at 2am and getting a reply within 10 minutes. I also recall the reply being 1000% better than anything I got at AWS, or Azure.</p>
<blockquote>
<p>My Linode never went down in the 600 days I had it, except for the 1 day where they turned it off to double my hardware for free (and I knew about it).</p>
</blockquote>
<h2>Why I left Linode</h2>
<p>So my over-arching reason I left Linode was because I wanted to push out changes to my blog really fast. I wanted the ability to make small changes to the html quickly. However, to do this on Linode I would have to construct my own deployment tier, even with <a href="https://circleci.com/">Circle CI</a> backing me up I knew it wouldn't be trivial.</p>
<blockquote>
<p>I wanted to Focus on what made me special, and not deal with yak shaving a deployment system.</p>
</blockquote>
<h2>AWS vs Azure</h2>
<p>I see a lot of these blog posts. I'll leave the metrics to <a href="http://www.infoworld.com/article/2610403/cloud-computing/ultimate-cloud-speed-tests--amazon-vs--google-vs--windows-azure.html">other people</a>. I am a huge azure fan, and honestly this is probably going to be a biased review. That being said we use AWS where I work, and it is a <strong>very</strong> robust platform.</p>
<h3>AWS</h3>
<p>So I actually quite like AWS. OpsWork has recently made me want to use AWS more, and ElasticBeanstalk is overall ok. My huge gripe with AWS is that I find getting started quite difficult. AWS requires you create lots of security groups, instance groups, VPS configs, etc. to get started, and to be honest its annoying.</p>
<p>The UI is quite clunky, in fact I use the CLI to avoid the abysmal UI, and good luck finding all the dependent objects of a parent. P.S. the permissions in AWS are terrible, unless you work at a company where everyone has full access.</p>
<p>On the plus side the instances spin up quite quick, they are well priced, and you can get what feels like unlimited compute. The storage system (S3) is quite user friendly, and well priced.</p>
<p>ElasticBeanstalk is alright, but AWS doesn't really have a good Github -> ElasticBeanstalk story. Also some of the features are only available in US data centres.</p>
<h3>Azure</h3>
<p>Azure is my favorite. Web Apps are really good at hosting web applications in PHP, Java, Nodejs and .NET. I've had some problems hosting node in azure, but every few weeks it seems to get easier, and easier. The UI is great, except sometimes I feel its not responsive enough (some slow load times). Also Azure only has DNS management through the CLI, which is annoying so most people use Simple DNS.</p>
<p>The actual VM's are quite good, but without picking up the phone you cannot ask for an absurd amount of compute. Blob storage is quite good, and azure has a very cheap no-SQL PaaS that has the <a href="http://www.troyhunt.com/2013/12/working-with-154-million-records-on.html">fastest query times ever</a>.</p>
<p>Also Microsoft is surprisingly open with how Azure runs under the hood. They say its all IIS, with ISAPI modules, and Hyper-V. They have the <a href="http://azure.microsoft.com/en-us/documentation/videos/azure-friday/">azure friday</a> podcast where they de-mystify the whole platform, and the <a href="https://github.com/projectkudu/kudu">kudu deployment system</a> is open source.</p>
<h3>Overall</h3>
<p>Overall I love azure more, but AWS is still very good. I feel like AWS has more granular controls, but Azure tends to get in your way less. Pick your poison, because its all the same. That being said use what you <strong>like</strong> not what everyone is using.</p>
VS 2015, Getting Resharper Experience Without Resharper2015-08-09T14:25:49Zhttps://blog.terrible.dev/vs-2015-getting-resharper-experiance-without-resharper/<p><em><a href="https://blog.terrible.dev/VS-2017-best-extensions-on-launch/">click here</a> for vs2017</em></p>
<p>Resharper has long dominated the c# landscape as the tool of tools. Roslyn shipping with VS 2015, the quick actions light bulb, and the community analyzers, all combine to produce a resharper-like experience.</p>
<!-- more -->
<h2>Showing Overloads/Param Info</h2>
<p>Automatically showing documentation for parameters, and overloads for some reason is always off for me. To get the parameters information you must turn it in in <code>Text Editor -> Lanuage -> General -> Parameter Info</code> The parameter info should show auto-magically, but you can also type <kbd>Control</kbd> +<kbd>Shift</kbd>+<kbd>Space</kbd> to invoke the dialog.</p>
<p><img src="https://blog.terrible.dev/content/images/2015/08/paramInfoExample.png" alt=""></p>
<p><img src="https://blog.terrible.dev/content/images/2015/08/paramInfoSetting.PNG" alt=""></p>
<h2>Refactoring</h2>
<p>Refactoring is a <strong>huge</strong> part of Resharper. I recently stumbled across a [fantastic] refactoring extension called <a href="http://vsrefactoringessentials.com/">Refactoring Essentials</a></p>
<p>You can install this into your project as a nuget package or install it as a visual studio extension.</p>
<p>Refactoring Essentials does not just include refactors, but it also includes a bunch of code quality analyzers, and adjustments.</p>
<h2>Code Analysis</h2>
<p>There are 2 fantastic code analyzers I really enjoy. The first is <a href="http://code-cracker.github.io/">Code Cracker</a> Code cracker has lots of refactorizations to produce higher quality, more readable code.</p>
<p>The second one I like is the <a href="https://www.nuget.org/packages/Microsoft.CodeAnalysis.FxCopAnalyzers/">FxCop</a> analyzer produced by the Roslyn team. This one uses rules from FxCop to produce refactors to suit best practices in the CLR.</p>
<h2>Auto Format</h2>
<p>I have had good luck with the <a href="https://vlasovstudio.com/continuous-formatting/">Continuous Formatting</a>, but its a paid product. If you don't want to pay for code formatting, I'd suggest using the <a href="http://www.codemaid.net/">Code Maid</a> Extension. Both extensions are fantastic, and I think Code Maid does a really good job at reorganizing code. To say the least I have both extensions installed.</p>
<h2>Working without resharper</h2>
<p>The first thing that I realized is that intellisense does not auto complete as many classes as resharper. I notice that resharper auto completes classes even without any <code>using</code> statement in the current file. However the new Roslyn quick actions will suggest using things from different namespaces if the names are close enough.</p>
<p><img src="https://blog.terrible.dev/content/images/2015/08/usingStatementExample.png" alt=""></p>
<h3>Invoking the Light bulb</h3>
<p>I find the best way to invoke the light bulb is by hitting <kbd>Control</kbd>+<kbd>.</kbd> you can then hit <kbd>Enter</kbd> to select the action in the list.</p>
<h2>Other Extensions I cannot live without</h2>
<p>This is an additional list of VS extensions that make me happy.</p>
<ul>
<li><a href="http://www.ndepend.com/">NDepend</a> Paid product, totally worth it. view my <a href="https://blog.terrible.dev/must-have-tool-ndepend/">blog post about it</a></li>
<li><a href="https://visualstudiogallery.msdn.microsoft.com/06f39a31-20ce-408c-afee-8a02b484db1c">Sando Code Search</a> Great little code search tool</li>
<li><a href="http://vswebessentials.com/">Web Essentials</a> Great web tools for vs</li>
<li><a href="https://visualstudiogallery.msdn.microsoft.com/3b329021-cd7a-4a01-86fc-714c2d05bb6c">Web Compiler</a> auto web compiler (less, js, etc.)</li>
<li><a href="https://visualstudiogallery.msdn.microsoft.com/d4e9939d-baac-43d4-bece-960eb57e02c1">C# Methods code snippets</a> method code snippets</li>
</ul>
<p>Let me know what your favourite VS tools are below.</p>
Why I love bitbucket, and why I (almost) never use it.2015-07-12T01:50:33Zhttps://blog.terrible.dev/why-i-love-bitbucket-and-why-i-almost-never-use-it/<p>Github has become the defacto online source hosting provider. More projects than ever before use github, and it has become a predominate force in the open source community. I use github quite a bit, and I love it.</p>
<!-- more -->
<h2>What is bitbucket?</h2>
<p>If you are unfamiliar, bitbucket is <a href="https://www.atlassian.com/">Atlassian's</a> version of github. Bitbucket provides online hosting of code. Free public repo's, and it even stands apart from github by providing free private repos.</p>
<h2>What makes bucket so good?</h2>
<p>I am a huge fan of controlling releases through version control branches. I also enjoy tools that prevent me from doing the wrong thing.</p>
<p>When I use github, and I want to have other developers work with me on a repository, I have to give them access to the repo. Unless you are an organization, giving someone access gives them full commit access on every branch, which can be detrimental.</p>
<p>Bitbucket allows for branch permissioning, which is a feature that I really believe in. For example if you wish to lock down release branches from commits directly, you can do that. Github on the other hand does not allow this level of control, unless you have organizational rights.</p>
<p>Bitbucket has the ability to prevent history re-writes including force pushes, which jenkins developers <a href="https://news.ycombinator.com/item?id=6713742">found out</a> was a feature they wish they had.</p>
<h2>Why I don't use bitbucket (often)</h2>
<p>So overall I love bitbucket, except I hardly use it. Most of the coding I do, I open source. I want people to find my code, and contribute to it. Anyone can work open source projects in bitbucket, but the platform does not provide a great way for people to discover repositories. To put it simply, bitbucket was ment for people working in teams, while Github was ment for social coding.</p>
<p>If I work on a startup, or something where I have a real team. We will use bitbucket, and even pay for additional features. I have taken advantage of the free repos in bitbucket, quite a bit.</p>
<p>Overall, both services are pretty solid. Use what will work best for you, not what everyone is currently using.</p>
Tip Badges in ghost2015-04-04T19:31:04Zhttps://blog.terrible.dev/tip-badges-in-ghost/<p>So I am a huge fan of ghost, and I love providing my content free of charge. That being said server hosting costs money.</p>
<p>I added a tips badge to the bottom of my blog posts (see below) to try to offset the costs.</p>
<!-- more -->
<p>How I did this was simple. I signed up for a <a href="https://gratipay.com">gratipay</a> account. Once signed in I went to the widgets section of my profile and found my badge.</p>
<p><img src="https://blog.terrible.dev/content/images/2015/04/Capture.PNG" alt=""></p>
<p>I took the image tag and wrapped it around an <code>a</code> tag that will link to my profile.</p>
<pre class="language-xml" tabindex="0"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://gratipay.com/TommyParnell<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://img.shields.io/gratipay/TommyParnell.svg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
</code></pre>
<p>I then went into my themes folder at <code>content/themes/ghostium</code> where I found a file called <code>post.hbs</code></p>
<p>I scrolled to where I found the part that the author website url is injected. I then added in the badge from gratify</p>
<p><strong>Before</strong></p>
<pre class="language-xml" tabindex="0"><code class="language-xml">
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>post-author-website<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>author.website<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nofollow<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>author.website<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span>
</code></pre>
<p><strong>After</strong></p>
<pre class="language-xml" tabindex="0"><code class="language-xml"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>post-author-website<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>author.website<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nofollow<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>author.website<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://gratipay.com/TommyParnell<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://img.shields.io/gratipay/TommyParnell.svg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span>
</code></pre>
<h2>Badge at the top of the page</h2>
<p>if you want the badge at the top of the page you can add the code explained above before the <code>post</code> handelbars tag in the post.hbs file</p>
Using Bower with a traditional MVC.NET app (While thinking about vNext).2015-03-24T01:44:29Zhttps://blog.terrible.dev/using-bower-and-grunt-with-a-net-app/<p>Where I work .NET rules supreme. Personally I really don't care that much about the technology so long as it supports really good workflows. One of my major issues with nuget is that is very opinionated.</p>
<!-- more -->
<p>In nuget, js script files always end up dumping out to a <code>Scripts</code> folder, and while you can maintain your own scripts elsewhere, nuget just is not really great for client side JS as a whole.</p>
<h2>Why Bower?</h2>
<p>One of the major reasons I do not like nuget for js, is because nuget was built for .net assemblies. This means the rest of the development community outside of .net has to either put their things in nuget, or just not worry about it. What usually ends up happening is someone in the .net community decides to maintain pushing a js package into nuget. This is clearly known at MSFT since the vNEXT templates ship with bower as default. Bower is a package management written on top of npm, that supports pushing script files into a directory. Simple right?</p>
<h2>Show me code.....</h2>
<p><strong>The Goal:</strong> Try to maintain the same folder structure as current vNEXT templates on current .net applications. Use bower instead of nuget.</p>
<pre><code>wwwroot/
-lib/
--jquery/
---css/
---js/
Controllers/
Models/
</code></pre>
<p>So the first thing we need to do is define our bower task. Now I literally ripped the following off the vNEXT template. Essentially how this works is we define a grunt task to use bower and define the output folder. I am dumping the output from bower in a wwwroot/lib folder, just as the vNEXT projects are going to go.</p>
<p><strong>Gruntfile.js</strong></p>
<pre class="language-javascript" tabindex="0"><code class="language-javascript">
<span class="token comment">/// <binding BeforeBuild='bower' /></span>
<span class="token comment">// This file in the main entry point for defining grunt tasks and using grunt plugins.</span>
<span class="token comment">// Click here to learn more. http://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409</span>
module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">grunt</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
grunt<span class="token punctuation">.</span><span class="token function">initConfig</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">bower</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">install</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">targetDir</span><span class="token operator">:</span> <span class="token string">"wwwroot/lib"</span><span class="token punctuation">,</span>
<span class="token literal-property property">layout</span><span class="token operator">:</span> <span class="token string">"byComponent"</span><span class="token punctuation">,</span>
<span class="token literal-property property">cleanTargetDir</span><span class="token operator">:</span> <span class="token boolean">false</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// This command registers the default task which will install bower packages into wwwroot/lib</span>
grunt<span class="token punctuation">.</span><span class="token function">registerTask</span><span class="token punctuation">(</span><span class="token string">"default"</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">"bower:install"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// The following line loads the grunt plugins.</span>
<span class="token comment">// This line needs to be at the end of this this file.</span>
grunt<span class="token punctuation">.</span><span class="token function">loadNpmTasks</span><span class="token punctuation">(</span><span class="token string">"grunt-bower-task"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
<p><strong>bower.json</strong></p>
<pre><code>
{
"name": "myProject",
"private": true,
"dependencies": {
"bootstrap": "3.0.0",
"jquery": "1.10.2"
},
"exportsOverride": {
"bootstrap": {
"js": "dist/js/*.*",
"css": "dist/css/*.*",
"fonts": "dist/fonts/*.*"
}
"jquery": {
"": "jquery.{js,min.js,min.map}"
}
}
}
</code></pre>
<h2>What about msbuild?</h2>
<p>Ok here comes the <strong>tough</strong> part. To work around msbuild I included the following xml in my csproj which should import the files in the wwwroot folder during build. I like to put this before the closing <code></Project></code> node.</p>
<pre><code> <Target Name="BeforeBuild">
<ItemGroup>
<Content Include="wwwroot\lib\**\*.css" />
<Content Include="wwwroot\lib\**\*.js" />
</ItemGroup>
</Target>
</code></pre>
<p>You could also in theory get really silly (<strong>Not Recommended</strong>) and call grunt during build. Although I did the opposite and <strong>called msbuild from grunt</strong>, which in my opinion is better.</p>
<pre><code> <Target Name="BeforeBuild">
<ItemGroup>
<Exec Command="npm install"/>
<Exec Command="node -e require('grunt').tasks()"/>
</ItemGroup>
</Target>
</code></pre>
<h3>Custom Targets</h3>
<p>So at my current employer we have a custom build engine, and for some reason the Content includes didn't work well with that. To mitigate this I included the following nodes as a child of the project node. I then called msbuild with the target of <code>CoreContent</code> which triggered the copy during the publishing. Now if a developer uses vs to publish, it will use the Content Include, and if our build system calls it, we will use the custom target.</p>
<pre><code>
<ItemGroup>
<CoreContent Include="wwwroot\lib\**\*.css" />
<CoreContent Include="wwwroot\lib\**\*.js" />
</ItemGroup>
<Target Name="CoreContent">
<copy SourceFiles="@(CoreContent)" DestinationFolder="$(WebProjectOutputDir)\wwwroot\lib\%(RecursiveDir)%(Filename)%(Extension)" />
</Target>
</code></pre>
Hosting NancyFx with OWIN on IIS2015-02-24T16:07:01Zhttps://blog.terrible.dev/nancyfx-owin-iis/<p>So I was quite confused about hosting Nancyfx on OWIN under IIS. <a href="https://github.com/NancyFx/Nancy/wiki/Managing-static-content#extra-steps-required-when-using-microsoftowinhostsystemweb">Parts</a> of the Nancy wiki led me slightly astray.</p>
<p>Here is the simple guide.</p>
<p>Make sure you Install the following nuget packages (if you havn't already).</p>
<!-- more -->
<pre><code>Nancy.Owin
Microsoft.Owin.Host.SystemWeb
</code></pre>
<p>Owin uses a class called Startup.cs to do basic configuration. We need to add nancy to the app, and then add additional StageMarkers used by the ASP pipeline.</p>
<p>Startup.cs</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>Owin<span class="token punctuation">.</span>Extensions</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Owin</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Startup</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Configuration</span><span class="token punctuation">(</span><span class="token class-name">IAppBuilder</span> app<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
app<span class="token punctuation">.</span><span class="token function">UseNancy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">UseStageMarker</span><span class="token punctuation">(</span>PipelineStage<span class="token punctuation">.</span>MapHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Static Files</h2>
<p>Here you need to make a choice, do you want to have IIS manage the static files, or use the OWIN module. Personally I go for IIS. I don't have any data on this, but I have a feeling IIS might be faster to serve static content.</p>
<h4>IIS Static Hosting</h4>
<p>runAllManagedModulesForAllRequests when set to true does not allow <strong>Native</strong> IIS modules to run like the static files module. So we will want to turn that off if we want IIS to handle static files.</p>
<p>web.config</p>
<pre><code>
<system.webServer>
<modules runAllManagedModulesForAllRequests="false" />
</system.webServer>
</code></pre>
<h4>OWIN Static Hosting</h4>
<p>Nuget Package</p>
<p><code>Install-Package Microsoft.Owin.StaticFiles</code></p>
<p>Web.config</p>
<pre><code>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
</code></pre>
<p>Startup.cs</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Startup</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Configuration</span><span class="token punctuation">(</span><span class="token class-name">IAppBuilder</span> app<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
app<span class="token punctuation">.</span><span class="token function">UseFileServer</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">FileServerOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
RequestPath <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">PathString</span><span class="token punctuation">(</span><span class="token string">"/foo"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
FileSystem <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">PhysicalFileSystem</span><span class="token punctuation">(</span><span class="token string">@".\web"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">UseNancy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">UseStageMarker</span><span class="token punctuation">(</span>PipelineStage<span class="token punctuation">.</span>MapHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h3>Put, Head, Delete</h3>
<p>if you need Put, Head or Delete requests add the following to your webconfig</p>
<pre><code>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
</code></pre>
<h2>Windows Authentication</h2>
<p>To use Windows authentication you need to have the authentication type in your web.config</p>
<pre><code> <system.web>
<authentication mode="Windows"/>
</system.web>
</code></pre>
<p>To actually be able to get the username of the user in code, you can use the following (assume .net 45).</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IUserIdentity</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token keyword">readonly</span> <span class="token class-name">ClaimsPrincipal</span> claimsPrincipal<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token function">User</span><span class="token punctuation">(</span><span class="token class-name">ClaimsPrincipal</span> claimsPrincipal<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>claimsPrincipal <span class="token operator">=</span> claimsPrincipal<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> UserName <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> claimsPrincipal<span class="token punctuation">.</span>Identity<span class="token punctuation">.</span>Name<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name">IEnumerable<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">></span></span> Claims <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> claimsPrincipal<span class="token punctuation">.</span>Claims<span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>c <span class="token operator">=></span> c<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Bootstrapper</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">DefaultNancyBootstrapper</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">RequestStartup</span><span class="token punctuation">(</span><span class="token class-name">TinyIoCContainer</span> container<span class="token punctuation">,</span> <span class="token class-name">IPipelines</span> pipelines<span class="token punctuation">,</span> <span class="token class-name">NancyContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
pipelines<span class="token punctuation">.</span>BeforeRequest <span class="token operator">+=</span> ctx <span class="token operator">=></span>
<span class="token punctuation">{</span>
ctx<span class="token punctuation">.</span>CurrentUser <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">User</span><span class="token punctuation">(</span>Thread<span class="token punctuation">.</span>CurrentPrincipal <span class="token keyword">as</span> <span class="token class-name">ClaimsPrincipal</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
Working with Entity framework (Code First)2014-11-16T20:06:58Zhttps://blog.terrible.dev/orm-showdown-dapper-vs-entityframework-part-1/<p><a href="http://msdn.microsoft.com/en-us/data/ef.aspx">Entity Framework</a> is the ORM that has been pushed by the MSFT giant over the last few years to the .NET community.</p>
<!-- more -->
<h2>Working with Entity Framework</h2>
<p>Entity framework comes in two flavors <code>Code First</code> and <code>Database First</code></p>
<p>Code first is MSFT's way of using Entity Framework to scaffold your database from code. This huge feature allows you, the developer, to not write any SQL to create the database.</p>
<h4>Database Philosophy</h4>
<p>MSFT's tutorials with EF really push you toward having Entity Framework create the database, and use some <code>Linq</code> tricks to generate all the SQL. Now one of the huge downsites to this philosophy is that there is no stored procedures you can magically change to <em>fix</em> any database performance issues. This means any changes to alter the way you query should be done with a new deployment of the application. This also means that you will not have the oppertunity to profile any sprocs, and try to gain CPU cycles in the database. If you are looking for high performance I would look toward using <a href="https://github.com/StackExchange/dapper-dot-net">Dapper</a> instead. The benefit for using EF, is honestly developer time. You can get started much faster using Entity Framework's code first approach.</p>
<h4>Getting Started with Code First</h4>
<p>To put it simply make a class(or classes) and make a context which contains a <code>set</code> of those classes. Make sure you <strong>first</strong> add the entity framework <a href="https://www.nuget.org/packages/entityframework">nuget package</a>.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Employee</span>
<span class="token punctuation">{</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Key</span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">int</span></span> Id <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> FirstName <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> LastName <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SomethingElse</span>
<span class="token punctuation">{</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Key</span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">int</span></span> Id <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> Yup <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">string</span></span> ImCool <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ApplicationDbContext</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">DbContext</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token function">ApplicationDbContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span><span class="token string">"DefaultConnection"</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name">DbSet<span class="token punctuation"><</span>Employee<span class="token punctuation">></span></span> EmployeesetSet <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name">DbSet<span class="token punctuation"><</span>SomethingElse<span class="token punctuation">></span></span> SomethingElseSet <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>then in the package console window type <code>enable-migrations</code> this will create a migrations folder and a configuration. If you wish your code to auto create the database on start, then add <code> AutomaticMigrationsEnabled = true;</code> to the <code>Configurations.cs</code> file that is created.</p>
<p>Then simply type <code>add-migration</code> give it a name, and the migration will look something like the following.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">partial</span> <span class="token keyword">class</span> <span class="token class-name">one</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">DbMigration</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Up</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">CreateTable</span><span class="token punctuation">(</span>
<span class="token string">"dbo.Employees"</span><span class="token punctuation">,</span>
c <span class="token operator">=></span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
Id <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">Int</span><span class="token punctuation">(</span><span class="token named-parameter punctuation">nullable</span><span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">identity</span><span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
FirstName <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
LastName <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">PrimaryKey</span><span class="token punctuation">(</span>t <span class="token operator">=></span> t<span class="token punctuation">.</span>Id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">CreateTable</span><span class="token punctuation">(</span>
<span class="token string">"dbo.SomethingElses"</span><span class="token punctuation">,</span>
c <span class="token operator">=></span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
Id <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">Int</span><span class="token punctuation">(</span><span class="token named-parameter punctuation">nullable</span><span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">identity</span><span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Yup <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
ImCool <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">PrimaryKey</span><span class="token punctuation">(</span>t <span class="token operator">=></span> t<span class="token punctuation">.</span>Id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Down</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">DropTable</span><span class="token punctuation">(</span><span class="token string">"dbo.SomethingElses"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">DropTable</span><span class="token punctuation">(</span><span class="token string">"dbo.Employees"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>You can then type update-database, and it will update the database. Note: the connection string is defined in the web config, and is declared on the following line.</p>
<p>YourDbContext.cs</p>
<p><code>public ApplicationDbContext() : base("DefaultConnection")</code></p>
<p>Web.config:</p>
<pre><code>< connectionStrings>
< add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-WebApplication11-20141116030948.mdf;Initial Catalog=aspnet-WebApplication11-20141116030948;Integrated Security=True"
providerName="System.Data.SqlClient" />
</ connectionStrings>
</code></pre>
<p>See we have a connectionstring in our webconfig called DefaultConnection, and using our base constructor we are naming that as our connection.</p>
Mono, not just a sickness2014-11-04T07:25:47Zhttps://blog.terrible.dev/mono-not-just-a-sickness/<p>In the old days, when programming in .NET you were signing yourself up to a lifetime of windows server, however things have changed.</p>
<!-- more -->
<h2>About me</h2>
<p>I am an avid user of Linux. My laptop, Linux; my gaming computer, linux; this blog? Linux. Safe to say I love the NIX environment.</p>
<p>I love C-like languages. My first language was JavaScript, then Java, eventually c#. I dislike ruby except for small scripts, and I would rather stab myself than use PHP.</p>
<p>Over time I have really grown to love c#.</p>
<blockquote>
<p>With Generics, Dynamic typing, async's, lamda expressions, nuget packages (c#-like npm modules), c# has a rich ecosystem of features.</p>
</blockquote>
<p>The one thing that has killed me, until recently is I have not been able to run my c# code on Linux.</p>
<h2>Mono Runtime</h2>
<p>For those of you whom do not know, <a href="http://www.mono-project.com/">mono</a> is an open source implementation of the .NET stack that runs on Linux, and Windows. This means that people can host their code on both platforms, but other people whom prefer linux can actually contribute to the c# community.</p>
<h3>Working with Mono</h3>
<p>Earlier this year a <a href="http://blog.normmaclennan.com/">colleague</a>, and I started working on a project at vistaprint that used mono. Here are some tips we learned.</p>
<ul>
<li>Mono might be missing some libraries. Use <a href="http://www.mono-project.com/docs/tools+libraries/tools/gendarme/">mono-Gendarme</a> as part of your build process to detect any compatibility issues.</li>
<li>Use <a href="http://monodevelop.com/">monodevelop</a> as your IDE, trust me its on-par with Visual Studio.</li>
<li>Make sure you are on 5.0 or higher.</li>
<li>Use <a href="https://launchpad.net/~ermshiperete/+archive/ubuntu/monodevelop">this PPA</a> on Ubuntu, and install monodevelop-current</li>
<li>Use frameworks, or that build against mono.</li>
<li>We had great luck with <a href="http://nancyfx.org/">Nancyfx</a></li>
<li>Build file paths using Path.Combine, never hardcode paths</li>
<li>This is because windows paths use <code>\</code> and Linux paths use <code>/</code> as the seperator</li>
<li><a href="https://www.nuget.org/packages/FluentMigrator/">Fluent DB</a> can build your database regardless of SQL server type (MS, postgre, etc)</li>
</ul>
<h3>Finding Help</h3>
<p>We put more help on a <a href="http://usemono.net">advocacy site</a>. This is a NancyFx site, built on Travis CI, deployed to heroku. The sites' <a href="https://github.com/maclennann/usemono-net">github page, and wiki</a> contain aditional knowledge.</p>
<p>Also <a href="https://blog.terrible.dev/mono-not-just-a-sickness/jabbr.net">Jabbr.net</a> is a great source to find .NET dev's whom are always ready to answer a questions.</p>
<h3>Myths?</h3>
<blockquote>
<p>MSFT is going to sue and or shutdown mono</p>
</blockquote>
<ul>
<li>Control + F <a href="http://www.hanselman.com/blog/IntroducingASPNETVNext.aspx">this blog post</a> for the word mono</li>
</ul>
<blockquote>
<p>Mono does not support <em>Insert current version of .NET</em></p>
</blockquote>
<p>Compatibility can be found <a href="http://www.mono-project.com/docs/about-mono/compatibility/">here</a> Although I'm betting that it supports pretty much everything current at the time of <em>you</em> reading this.</p>
<blockquote>
<p>Mono has poor GC performance</p>
</blockquote>
<p>I have seen this with the Generational collector, I suggest you switch to using the SGEN collector.</p>
<h2>Mono Successes?</h2>
<p>I wanted to come into this blog with a huge list of success stories for mono. However I didn't have the time, and I didn't want to seem like I was being paid by said people.</p>
<p>I guess the one huge success story I will point to is <a href="http://xamarin.com/">Xamarin</a>. Xamarin runs your mobile apps on all phones using c#, and guess what? Mono. Actually the Xamarin people are the ones working on mono, and (one could assume) funding it through the xamarin platform. I'd love to say I was being paid by xamarin to say this, but I am not. Heck my Xamarin license just expired.</p>
<h2>tl;dr</h2>
<p>Give mono a shot, and start hosting on linux. Mono has great support for the various .NET Versions. I recommend using <a href="http://nancyfx.org/">NancyFx</a> web framework, and not MVC.</p>
New Series: Windows myths debunked!2014-11-04T06:39:59Zhttps://blog.terrible.dev/windows-net-myths-debunked/<p>Over the last 8 years the demand to scale has ever increased.</p>
<blockquote>
<p>We have gone from curating machines like your favorite pets, and started spinning up, and destroying VM's at an ever increasing pace.</p>
</blockquote>
<p>As engineers the Unix like platforms, have always been easier to work with. Personally I enjoy linux, I love package managers, I love ssh, and configurations are much easier. That being said, lately I have been interacting a lot with Windows servers.</p>
<!-- more -->
<p>2014 was my first year really attending a lot of conferences. One thing I have seen a lot at these conferences are misconceptions about Windows itself, and the .NET environment. Granted, I still love Linux a ton, but I also believe Windows is a viable platform to run on.</p>
<p>This blog post starts a <strong>series</strong> of posts to convince people that Windows can be a viable platform. I'll also use this series to talk about things I like about .NET. Personally, I believe azure has proven the viability of using windows on a large scale.</p>
<h2>Package Management</h2>
<blockquote>
<p>When I want to install xyz program on my linux box, I just type apt-get package name, like to see you do that on windows! ~ SomeRandomDude</p>
</blockquote>
<p>This is the most common thing I have heard. I would like to direct <strong>everyone's</strong> attention to an amazing open source project called <a href="https://chocolatey.org/">Chocolatey</a></p>
<p>Chocolatey is a package manager for windows. Much like apt-get, chocolatey can download and install packages from the chocolatey website, or a locally hosted store.</p>
<p>The cool part about chocolatey? Completely open sourced, and driven by the community! Chocolatey was not developed at microsoft, but some engineers whom simply wanted apt-get like functionality in windows.</p>
<p>Microsoft is now embracing this effort, in the next version of <a href="http://blogs.technet.com/b/windowsserver/archive/2014/04/03/windows-management-framework-v5-preview.aspx">Windows Management Framework</a> Microsoft will release OneGet, a repository manager for windows. Under the bonnet driving OneGet by default, Chocolatey! Much like apt, to simply install puppet I can type <code>choco install puppet</code>.</p>
Binding SSL Certs on Windows Installer XML (WiX) deployed Web Applications2014-07-22T05:37:50Zhttps://blog.terrible.dev/binding-ssl-certs-on-windows-installer-xml-wix-deployed-web-applications/<p>This tutorial is about using SSL certs with WiX for IIS websites. For those of you whom didn't know, WiX is an MSI generator. You can even deploy IIS applications with WiX's MSI's.</p>
<!-- more -->
<h2>Warning: I suck at wix</h2>
<p>Now I am going to start of by saying, I am far from an expert on wix.</p>
<blockquote>
<p>If someone knows a better way please comment below. Tell me I am wrong</p>
</blockquote>
<h2>Danger: Some WiX Knowledge Required</h2>
<p>Ok so before I go on, I am not going to explain everything from scratch.</p>
<blockquote>
<p>I'm assuming you might know the basics of WiX here, and you have done iis things with it.</p>
</blockquote>
<h2>Show me Teh Codez...</h2>
<p>Ok here it goes...In your fragment that declares your website you need to declare a binary. This says basically bundle the binary code from this file into the msi. This can go right under your fragment tag. The <strong>sourceFile</strong> tag should be the path to your certificate.</p>
<pre class="language-XML" tabindex="0"><code class="language-XML"><Binary Id="certBinary" SourceFile=".\IRCool.org.pfx">
</Binary></code></pre>
<h3>Declare your IIS Instance things!</h3>
<p>Ok...So I'm hoping you know how the iis stuff with wix works if you have read up to this point (and heeded my warnings)</p>
<p>When you go to declare your component the iis certificate declaration needs to be a child of the component tag. The certificate needs to be the same level as your website tag.</p>
<p>The binary key in the certificate tag needs to match the ID of the binary tag we declared. I like to add it to local machine, personal store. Request <strong>must</strong> be no. Obviously the PFXPassword needs to be the password to your pfx file.</p>
<pre><code>
<iis:Certificate Id="cert" BinaryKey="certBinary" Name="IRCool.org" StoreLocation="localMachine" StoreName="personal" PFXPassword="mypasswordisawesome" Request="no" />
</code></pre>
<h3>Lets bind this</h3>
<p>Ok so now we have our certificate declared in IIS. We need to bind against it. So you will probably end up with something like the following:</p>
<p>You have declared a website, in it you have added 2 web addresses. A web address that is on port 443, and is secure. Another one that is on 80, and is not. You will have declared a certificate reference that matches your iis certificate tag.</p>
<pre><code>
<iis:WebSite Id='IRCool' Description='IRCool' Directory='Install_Web' StartOnInstall='yes' ConfigureIfExists='yes' AutoStart='yes'>
<iis:WebAddress Id='SecIRCool' Port='443' Header='IRCool' Secure='yes' />
<iis:WebAddress Id='IRCool' Port='80' Header='IRCool' />
<iis:WebApplication Id='IRCoolApp' WebAppPool='IRCoolAppPool' Name='IRCool' />
<iis:CertificateRef Id='cert' />
</iis:WebSite>
</code></pre>
<h2>Ok..how do I redirect my port 80?</h2>
<p>So I know there <strong>has</strong> to be a better way here. I'm not sure how to configure IIS to do this with wix. However according to <a href="http://stackoverflow.com/a/4945950">Stack Overflow</a> you could redirect on begin request in MVC4+ (or you could do the following in <a href="http://nancyfx.org/">NancyFX</a>).</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">RequestStartup</span><span class="token punctuation">(</span><span class="token class-name">TinyIoCContainer</span> container<span class="token punctuation">,</span> <span class="token class-name">IPipelines</span> pipelines<span class="token punctuation">,</span> <span class="token class-name">NancyContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
pipelines<span class="token punctuation">.</span>BeforeRequest <span class="token operator">+=</span> <span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token operator">=></span> x<span class="token punctuation">.</span>Request<span class="token punctuation">.</span>Url<span class="token punctuation">.</span>IsSecure
<span class="token punctuation">?</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">RedirectResponse</span><span class="token punctuation">(</span>x<span class="token punctuation">.</span>Request<span class="token punctuation">.</span>Url<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Replace</span><span class="token punctuation">(</span><span class="token string">"http:"</span><span class="token punctuation">,</span> <span class="token string">"https:"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">RequestStartup</span><span class="token punctuation">(</span>container<span class="token punctuation">,</span> pipelines<span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>tl;dr?</h2>
<p>You should end up with a fragment that resembles this:</p>
<pre><code><Fragment>
<Binary Id="certBinary" SourceFile=".\IRCool.org.pfx"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="IISMain" Name='inetpub'>
<Directory Id="PubFolderName" Name="PubFolderName">
<Component Id='WebsiteConfig' Guid='{YOURGUIDHERE}' Win64="yes">
<iis:Certificate Id="cert" BinaryKey="certBinary" Name="IRCool.org" StoreLocation="localMachine" StoreName="personal" PFXPassword="mypasswordisawesome" Request="no" />
<iis:WebSite Id='IRCool' Description='IRCool' Directory='PubFolderName' StartOnInstall='yes' ConfigureIfExists='yes' AutoStart='yes'>
<iis:WebAddress Id='SecIRCool' Port='443' Header='IRCool' Secure='yes' />
<iis:WebAddress Id='IRCool' Port='80' Header='IRCool' />
<iis:WebApplication Id='IRCoolApp' WebAppPool='IRCoolAppPool' Name='IRCool' />
<iis:CertificateRef Id='cert' />
</iis:WebSite>
<iis:WebAppPool Id='IRCoolAppPool' Identity="localSystem" RecycleMinutes="0" IdleTimeout="0" ManagedPipelineMode='Integrated' ManagedRuntimeVersion='v4.0' Name='IRCool' />
</Component>
</Directory>
</Directory>
</Directory>
<Fragment>
</code></pre>
Using Action<>, Func<> to hide using statements2014-07-06T07:56:02Zhttps://blog.terrible.dev/using-action-func-to-hide-using-statements/<p>Ok so to give you all some background. I always write my data access with a repository pattern in c#. Now I often use dapper, however I'd guess this problem would also apply with Entity framework.</p>
<!-- more -->
<p>Everytime I start writing my database access I always start with something like...</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">InsertSomething</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span></span> something<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">using</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> x <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">SqlConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>...and honestly pretty soon I am living in <code>using</code> statement hell.</p>
<p>Now I tried to mitigate this in the past with IDisposable, but when I'd do some weak reference dependancy injection magic things usually got borked. I like to see using statements in action. I like know that things are getting disposed. However the verbosity, and sheer pain of it makes me want to puke. So one day I came up with the following.</p>
<script src="https://gist.github.com/TerribleDev/f248f559dd89c8dc4b42.js"></script>
<p><a href="https://gist.github.com/f248f559dd89c8dc4b42.git">Gist Link</a></p>
<h2>Ok? How do I use this?</h2>
<p>Ok here is a basic example below using the <a href="https://code.google.com/p/dapper-dot-net/">Dapper</a> orm.</p>
<p>So basically we create our db class passing in the type of database connection we wish to use in <code><></code>. In this case we are using Sql server but in theory we could also use Postgres. We are making an annonymous function that gets passed x, which will be a database connection. This connection will already be created, with the proper connection string. We are then going to call dapper's QueryAsync which will return an IEnumerable of <code>MyReturnType</code> after calling MySproc. The Database connection will be disposed of without us having to worry.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"> <span class="token class-name"><span class="token keyword">var</span></span> db <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">DataBase<span class="token punctuation"><</span>SqlConnection<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token string">"connectionstring"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> result <span class="token operator">=</span> db<span class="token punctuation">.</span><span class="token function">QueryDatabaseAsync</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">QueryAsync</span><span class="token generic class-name"><span class="token punctuation"><</span>MyReturnType<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token string">"MySproc"</span><span class="token punctuation">,</span>
<span class="token keyword">new</span>
<span class="token punctuation">{</span>
MySprocParameter <span class="token operator">=</span> <span class="token string">"awesome"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token named-parameter punctuation">commandType</span><span class="token punctuation">:</span> CommandType<span class="token punctuation">.</span>StoredProcedure
<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h2>Action<>, Func<> Class<> what is this?</h2>
<p>Ok, so I know as a new c# programmer generics seem intimidating. So I will walk you through this.</p>
<h3>MyClass<></h3>
<p>You may have classes ask for a generic. This means they are asking for a class. <strong>Note</strong> the word class. This will <strong>not</strong> be an object.</p>
<p>First the line <code>public class DatabaseBase<T> where T : class, IDbConnection, new()</code> declares that this class is public. This class is called DataBase. This class requires a generic which we will call T in this class. T will have to be a class (not interface, nor struct, or enum). This class must inhert from IDbConnection. This class can also be created without a constructor. Now Notice in my gist, where I am using my <code>using</code> statements. You will see <code>new T()</code> that is because we are newing the class we have passed as a generic.</p>
<h3>Func< T,TR></h3>
<p>Next up is a Func. Now Functions are a delegate, or method that when ran have a return type. Functions <strong>Must have a return</strong>. In this case the T is a passed in paramter. This means the delegate must be able to handle an IDbConnection somehow and return a TR.</p>
<p>In the following example we have a method declaration that takes in a function that has a result. This method also returns the result of the function (note the TR return type).</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token keyword">public</span> <span class="token return-type class-name">TResult</span> <span class="token generic-method"><span class="token function">QueryDatabase</span><span class="token generic class-name"><span class="token punctuation"><</span>TResult<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token class-name">Func<span class="token punctuation"><</span>T<span class="token punctuation">,</span> TResult<span class="token punctuation">></span></span> action<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">using</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> x <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">T</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
x<span class="token punctuation">.</span>ConnectionString <span class="token operator">=</span> ConnectionString<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">action</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3>Action< T ></h3>
<p><code>Action<T></code> is essentially the same as <code>Func<T,TR></code> execpt actions do not have a return type. This would be more like a void than anything else. The T is a passed in parameter to the function. So you can pass in something like a database connection, but you will not have a return. Simple use case sql insert statement.</p>
Excel Interop cannot open my file!2014-06-28T23:26:00Zhttps://blog.terrible.dev/excel-interop-cannot-open-my-file/<p>So a while back I made a website that uses the Excel interop (long story). Since I made it a while ago, the IIS configuration is not automated, and must be done artisanally.</p>
<p>Recently I have been working on moving it to a new server. I installed Excel, and the website.</p>
<!-- more -->
<p><strong>Everything seemed ok until sysprep happend!</strong></p>
<p><img src="https://blog.terrible.dev/content/images/2014/Jun/jackie.PNG" alt=""></p>
<p>So I immediately was not pleased. First I started ripping apart everything profile related with IIS, and nothing.</p>
<p>Eventually I stumbled across <a href="http://stackoverflow.com/a/7386967/3671357">something on stack overflow</a> to summarize make sure <code>C:\Windows\SysWOW64\config\systemprofile</code> contains a folder called <code>Desktop</code>. If you are on 32 bit you need <code>c:\Windows\System32\config\systemprofile</code> to contain the <code>Desktop</code> folder.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/Jun/Capture3.PNG" alt=""></p>
<p>Pretty much desperate, and out of options I gave it a shot. Somehow it was the fix, although it pains me to say this.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/Jun/really-seriously-truly.png" alt=""></p>
Anti-Forgery Tokens in NancyFX with Razor2014-06-11T23:34:13Zhttps://blog.terrible.dev/anti-forgery-tokens-in-nancyfx-with-razor/<p>Getting started with anti-forgery tokens in NancyFX with razor views is pretty simple.</p>
<p>To start you need to enable csrf in application startup.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ApplicationStartup</span><span class="token punctuation">(</span><span class="token class-name">TinyIoCContainer</span> container<span class="token punctuation">,</span> <span class="token class-name">IPipelines</span> pipelines<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Csrf<span class="token punctuation">.</span><span class="token function">Enable</span><span class="token punctuation">(</span>pipelines<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">ApplicationStartup</span><span class="token punctuation">(</span>container<span class="token punctuation">,</span> pipelines<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Now you need to create a token on the get request that returns the form</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
Get<span class="token punctuation">[</span><span class="token string">"/"</span><span class="token punctuation">]</span> <span class="token operator">=</span> x <span class="token operator">=></span>
<span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">CreateNewCsrfToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> View<span class="token punctuation">[</span><span class="token string">"Index"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token operator"><</span><span class="token operator">!</span><span class="token operator">--</span> more <span class="token operator">--</span><span class="token operator">></span></code></pre>
<p>Now in your view you need to render the token</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token operator"><</span><span class="token class-name">form</span> method<span class="token operator">=</span><span class="token string">"POST"</span><span class="token operator">></span>
Username <span class="token operator"><</span><span class="token class-name">input</span> type<span class="token operator">=</span><span class="token string">"text"</span> name<span class="token operator">=</span><span class="token string">"Username"</span> <span class="token operator">/</span><span class="token operator">></span>
<span class="token operator"><</span>br <span class="token operator">/</span><span class="token operator">></span>
Password <span class="token operator"><</span><span class="token class-name">input</span> name<span class="token operator">=</span><span class="token string">"Password"</span> type<span class="token operator">=</span><span class="token string">"password"</span> <span class="token operator">/</span><span class="token operator">></span>
<span class="token operator"><</span>br <span class="token operator">/</span><span class="token operator">></span>
<span class="token operator"><</span><span class="token class-name">input</span> type<span class="token operator">=</span><span class="token string">"submit"</span> <span class="token keyword">value</span><span class="token operator">=</span><span class="token string">"Login"</span> <span class="token operator">/</span><span class="token operator">></span>
@Html<span class="token punctuation">.</span><span class="token function">AntiForgeryToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span>
</code></pre>
<p>Finally you need to authenticate the token on the post request</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">Post<span class="token punctuation">[</span><span class="token string">"/"</span><span class="token punctuation">]</span> <span class="token operator">=</span> x <span class="token operator">=></span>
<span class="token punctuation">{</span>
<span class="token keyword">try</span>
<span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">ValidateCsrfToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">CsrfValidationException</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> Response<span class="token punctuation">.</span><span class="token function">AsText</span><span class="token punctuation">(</span><span class="token string">"Csrf Token not valid."</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">WithStatusCode</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//do something</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
Must Have Tool: NDepend2014-05-24T01:04:17Zhttps://blog.terrible.dev/must-have-tool-ndepend/<p>Code quality tooling has become a bigger, and bigger industry. Tools like <a href="http://www.jetbrains.com/resharper/">Resharper</a>, and <a href="http://stylecop.codeplex.com/releases/view/79972">stylecop</a> have been telling us how bad us human beings are at developing code.</p>
<p>The one problem I have always had with these tools is they dont go above and beyond to help you understand your code at a higher level.</p>
<!-- more -->
<h2>So what is NDepend?</h2>
<p><img src="https://blog.terrible.dev/content/images/2014/May/ndep.PNG" alt="NDepend Logo"></p>
<p>According to <a href="http://www.ndepend.com/Features.aspx">their website</a> NDepend does everything from code rules, code querying, comparing builds, CI reporting, complexity diagramming, and the list goes on and on.</p>
<p>When I first heard of it, I assume it was more resharper, and less stylecop, but I was wrong.</p>
<h2>My Code Quality Beginnings...</h2>
<p>Before I go on about NDepend I have to tell you my history with code quality tools.</p>
<h3>JS Lint == /sadface</h3>
<p>I first learned of code quality tools, when I heard about <a href="http://www.jslint.com/">JSLint</a>. As JavaScript was my first programming language, I naturally thought I was amazing at it. However being a weakly type language, with horrible origins, it was easy to make bad code.</p>
<p>The first code I pumped into JS lint returned with thousands of changes I needed to make, and I wasn't sure where to start. JSLint did a good job of destroying my ego, and de-motivating me as a human being. I took personal offense to it, even though it was trying to help me. Furthermore because it didn't really integrate into my IDE, it was harder for me to track down issues.</p>
<h3>Stylecop</h3>
<p><img src="https://blog.terrible.dev/content/images/2014/May/91wmm.jpg" alt=""></p>
<p>My next attempt at using code quality tools was stylecop. Stylecop is a simple C# visual studio plugin that tells you where your code does not follow best practices. The first time I ran my code though stylecop it threw back over 700 warnings. The fact that it found so much to change was great, but the fact that everything was a warning, and nothing was an error was very concerning. Especially since I knew some bad code was in that codebase.</p>
<p>Also with the overall lack of visualization stylecop was less than perfect. You would have to double click on every warning, and hope it brought you to the proper offending code.</p>
<h3>Mono.Gendarme</h3>
<p>So recently I started using Gendarme to do code analyzation. I commit code, <a href="http://jenkins-ci.org/">jenkins</a> builds it, gendarme analyzes it, and jenkins would host my gendarme graphs. This was great, because jenkins could show the code gendarme was complaining about. Gendarme does not make everything warnings, and it does a good job at analyzing code.</p>
<p>My major problem with this, is that I'd have to commit bad code to the code base, then go back and fix the problems. Instead of fixing them before they landed in jenkins lap.</p>
<h3>Resharper</h3>
<p>Now before I go on I have to mention Resharper. Resharper is a developer productivity tool that uses a lot of coding standards/rules to make sure your code does not suck. However this is no replacement for a true code quality tool. Resharper is more about productivity (fixing lambdas, making sure your linq statements are readable, etc.). The big difference is that Resharper lacks in the reporting deparment, it does not capture trends, and does not enforce certain best practice rules.</p>
<p>Resharper only looks at source code, where as most other static analysis tools also look at compiled IL code as well.</p>
<h2>NDepend: First Impressions</h2>
<blockquote>
<p>NDepend runs extremely fast, and it never gets in your way.</p>
</blockquote>
<p>So I when first fired up Visual Studio, and started using NDepend I was blown away with the performance. NDepend Runs extremely fast, and never crashes visual studio. I needed a few minutes to process what I was looking at, and before long I realized NDepend had summerized my whole code base into one very sweet dashboard. As I clicked around the fun started to really begin...</p>
<p><img src="https://blog.terrible.dev/content/images/2014/May/ndepdash.PNG" alt=""></p>
<p><img src="https://blog.terrible.dev/content/images/2014/May/NDependDash.PNG" alt="Sample NDepend Dasbboard"></p>
<h2>NDepend: Organized Code Quality</h2>
<p>So the major feature I was blown away by with NDepend was how clean, and organized the code rules are. The tool really tells you which things you need to fix <strong>now</strong>, and which things can wait. You can easily turn rules on, and off with a click a checkbox. Everything is grouped together nicely.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/May/errorsOrganized.PNG" alt="Code Quality dashboard"></p>
<blockquote>
<p>NDepend uses a code querying engine (basically <code>linqTo<YourCodeHere></code>).</p>
</blockquote>
<p>The code quality rules, uses the NDepends querying engine to get your code. When you click on a rule the Linq query used will be displayed in a separate window. You can use this window to create your own rules, using the same querying engine. The following is a query to find code that should not be declared public.</p>
<pre>
//Avoid public methods not publicly visible
// Matched methods are declared public but are not publicly visible by assemblies consumers.
// Their visibility level must be decreased.
warnif count > 0
from m in JustMyCode.Methods where
!m.IsPubliclyVisible && m.IsPublic &&
// Eliminate virtual methods
!m.IsVirtual &&
// Eliminate interface and delegate types
!m.ParentType.IsInterface &&
!m.ParentType.IsDelegate &&
// Eliminate default constructors
!(m.IsConstructor && m.NbParameters == 0) &&
// Eliminate operators that must be declared public
!m.IsOperator &&
// Eliminate methods generated by compiler
!m.IsGeneratedByCompiler
select m
</pre>
<h2>NDepend: Code Dependency Management</h2>
<p>The other feature, and its probably more of a series of features is how NDepend manages code dependency. This does this with some awesome interactive graphs. The <a href="http://www.ndepend.com/Doc_VS_Arch.aspx#Dep">documents</a> show pretty much all the graphs, and I wont get into it all, but from a high level they provide great visualizations of your code.</p>
<blockquote>
<p>Graphing everything from class inheritance, to dependency graphs NDepend brings a new level of graphing to code quality tools.</p>
</blockquote>
<p>The tool allows you to find poor architectural decisions, and helps you correct them in the early days. Before the bad design decisions really bite you.</p>
<h2>But wait there's more!</h2>
<p>If you thought this was a simple visual studio plugin, you would be wrong.</p>
<blockquote>
<p>Having code quality in the build system is a must. I have always made sure code quality was also being measured in my CI pipline, and you should to.</p>
</blockquote>
<p>NDepend plugs into your build system to provide long term trend reporting. These reports can include LOC trends, which are compared against rule violation trends. NDepend reports can show your Test code coverage, code complexity, and code composition as your application matures.</p>
<p>With an optional separate GUI, command line tool, and pluggable rules engine, NDepend provides a new level of code quality management.</p>
<h2>tl;dr?</h2>
<p>NDepend is a code quality tool that really shows your code smells in new ways. with long term trend reporting, heat maps, and more graphs than you will ever need. NDepend will help your team grow a codebase that is clean, and free from dodgy code.</p>
Watching the Watchers: Monitorama PDX 2014 Day Two2014-05-07T14:48:55Zhttps://blog.terrible.dev/watching-the-watchers-monitorama-pdx-2014-day-two/<ul>
<li><a href="https://blog.terrible.dev/watching-the-watchers-monitorama-day-one/">Day One</a></li>
</ul>
<p>Day 2 was full of math based paranoia, math, and puppet(s)....</p>
<!-- more -->
<h2>Auditing all the things": The future of smarter monitoring and detection</h2>
<p>Jen Andre started off with a talk about auditd, and how to audit everything in your frinastructure. Using custom logging tools you can watch the command flow for every logged in session, even when the session su's to a different user.</p>
<h2>Is There An Echo In Here?: Applying Audio DSP algorithms to monitoring</h2>
<p>DSP (Digital Signal Processing) applied to monitoring data, could convert a very noisey graph, into a very readable one as Noah Kantrowitz pointed out in the second talk of the day.</p>
<h2>A Melange of Methods for Manipulating Monitored Data</h2>
<p>Dr Neil J. Gunther talked about how he is applying maths (yes plural :P) to gathered data metrics. He points out that you should never trust your data (even if it was gathered acuratly), and always trust in your instincts.</p>
<h2>The Final Crontab</h2>
<p>Crontabber is a jobs engine produced at Mozzilla. Selena Deckelmann talks about how it works, and why it is better than regular cron. The huge advantage to use it, is the jobs can have dependancies to each other.</p>
<h2>This One Weird Time-Series Math Trick</h2>
<p>Baron Schwartz delivered a very math centric talk about using math (like sliding averages, holt-winters, etc.) to properly analize your data.</p>
<h2>The Lifecycle of an Outage</h2>
<p>Scott Sanders talks was about how hipchat, and hubot are coming together to help dealing with a problem. He noted at github the bots can embed graph data into hip chat that others can see as they hop online. He also talked about analyzing your processes after an outage, to improve the handling of future issues.</p>
<h2>A whirlwind tour of Etsy's monitoring stack</h2>
<p>Etsy is able to deploy their application at any moment in time. Doing this requires both great CI tools, but also even better monitoring tools. Having power tools like ganglia, graphite, splunk, logstash. They are able to gain great insight into their application.</p>
<h2>Wiff: The Wayfair Network Sniffer</h2>
<p>Wireshark as a Service, wiff is a network traffic logging tool developed at wayfair. Able to log traffic throughout the network layer, wiff is able to help you understand your network traffic.</p>
<p>According to the presenter Dan Rowe, wiff helped wayfair detect a bug in their cookie generating algorithm.</p>
<h2>Web performance observability</h2>
<p><a href="http://webrockit.io/">Web Rockit</a> is a simple tool that detects web loading performace. The tool uses Phantom.js (headless webkit browser) to load the page and gather statistics during the load. These statistics can help you determine what is going on when your webpage loads.</p>
<h2>Lightning Talks</h2>
<p>The one talk that stood out to me at the lightning talks is never manage your software like a <a href="http://pete.io/Jra5">17th century ship</a>.</p>
<h2>Puppet Afterparty</h2>
<p>While the line for the beer was long, and the food was in short supply the puppet party was amazing. Ping pong filled the air, whilst tech nerds played board games. The people that work at puppet were very friendly and eager to talk about programming.</p>
Watching the Watchers: Monitorama PDX 2014 Day One2014-05-06T13:53:28Zhttps://blog.terrible.dev/watching-the-watchers-monitorama-day-one/<ul>
<li><a href="https://blog.terrible.dev/watching-the-watchers-monitorama-pdx-2014-day-two/">Day Two</a></li>
</ul>
<p>I am here in lovely Portland Oregon attending <a href="http://monitorama.com/">Monitorama</a>. Monitorama is a 3 day open source monitoring convention.</p>
<p>Monitorama had catered food, and drink. The food was plentiful and delicious, and the drinks were amazing.</p>
<p>There were 10 talks, I have made a quick summarization below. I don't have time to write in detail about each one, but I am sure you will get the gist from the basic summary.</p>
<!-- more -->
<h2>Please, no More Minutes, Milliseconds, Monoliths... or Monitoring Tools!</h2>
<p>The first talk from Adrian Crockford was about monitoring by the second as opposed to by the minute. <a href="http://www.williamhertling.com/2014/05/adrian-cockcroft-on-monitoring-cloud.html">Gene Kim's notes</a> summarize it better than I do, but in short: focus more on monitoring tools for developers, monitor by the second, and learn to analyze the data properly.</p>
<h2>Computers are a Sadness, I am the Cure</h2>
<p>Jason Mickens provided the funnest talk of the day. I couldn't fully grasp the message, but In short Bane == NoSql, Cloud == Crazy Train and stop talking about map reduce.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/May/Screenshot-2014-05-06-at-9-52-14-AM.png" alt=""></p>
<h2>Simple math to get some signal out of your noisy sea of data</h2>
<p>Toufic Boubez Provided the third talk of the day. Talking about (not so) simple math around your data. He urges people to stop treating data as Gaussian, and truly understand how their data gets arranged.</p>
<p>He pushed for using algorithms with sliding means as a way to truely understand your data. Just remember you spent time collecting it, you should spend time analyzing it.</p>
<h2>The Care and Feeding of Monitoring</h2>
<p>Great talk from Katherine Daniels, about how everyone needs to work together better to monitor things. She noted that no one sets out to make bad decisions, but bad things sometimes happen because of decisions made.</p>
<p><em>We take some things, and put internets on them ~ Dan Slimmon</em></p>
<p>Dan Slimmon's talked a lot about alarms. Smoke detectors people pay attention to, but no one pays attention to car alarms.</p>
<p>He talked a lot about how to actually use probability statistics to understand how often someone will get phone called on an actual issue or not.</p>
<h2>Metrics 2.0</h2>
<p>This was a strange, yet insightful talk about how metrics should be more self decriptive. Dieter Plaetinck wants people to try to use a new standard in <a href="http://metrics20.org">metrics</a>. I'm not sure how I feel about metrics 2.0, but I do agree that metric names can be ambiguous.</p>
<h2>Our Most Wicked Problem</h2>
<p>...A talk about the diversity problems in the industry today. Ashe Dryden talked a lot about how women are far more excluded than included in IT. This was an insightful talk, about how we need to provide space to all of the women coming into IT.</p>
<h2>The cost and complexity of reactive monitoring</h2>
<p>Chris Baker talks a lot about how reactive monitoring is terrible, and proactive is the way to go. Most humans never run though a logical sequence of troubleshooting steps, but tend to blame the newest thing they put into production.</p>
<h2>From Zero To Visibility</h2>
<p>Bridget Kromhout finished up the day with a talk about setting up the monitoring in her company from nothing. Going from a bunch of random shell scripts, to a proper monitoring framework (nagios, graphite, statsd, pingdom, etc.). Some of the pain points she encountered were around budgetary restrictions.</p>
<h2>After party</h2>
<p>The after party was great, the music was quite loud which made it hard to talk to people. I talked quite a bit to the New Relic crew about what they were doing. The one thing I was blown away by was how welcoming everyone was, and how everyone were fighting the same problems in their respective companies.</p>
ChromeOS: Gateway to portable productivity2014-04-29T20:00:01Zhttps://blog.terrible.dev/chromeos-gateway-to-portable-productivity/<p>Up until the last few years the only devices on the market were all full operating system work horses. However the majority of us would easily sacrifice functionality for portability. This statement has been backed up by the increase of market demand for tablets and ultrabooks over the years.</p>
<!-- more -->
<h2>Netbook Past</h2>
<p>When netbooks first came out they were running Window XP with an Intel Atom Processor. I was one of the early adopters, getting a first model Aspire One, and at the time I was blown away. I remember comparing it to the first ASUS EE, and the other offerings at the time.</p>
<p>In recent years netbooks have been replaced by ultrabooks, and tablets. Being a person that likes a physical keyboard I was put off from the tablets, and the ultrabooks always seemed expensive for a touch screen I was never going to use.</p>
<h2>Power Users and tablets</h2>
<p>Taking a side step for a moment. I know I am more of a unique customer than most. I believe the keyboard will always be a faster mechanism to productivity than a touch screen. I cannot live without a physical keyboard. Most power users of computers usually have this kind of mentality. So the form factor of a netbook is more suitable than a tablet.</p>
<h3>Browser Applications</h3>
<p>The great part about the advances in web technologies over the few years is that most power applications have become browser oriented. Most of my development work can now be done in a browser, which expands my use of a low profile device. ChromeOS brings a natural browser experience to applications that can work both online, and offline.</p>
<h2>Why ChromeOS?</h2>
<p>ChromeOS has a great expanse of apps that can work both offline and online. The list of apps includes RDP clients, hundreds of workflow management tools, and various coding IDE's. Most Chromebooks are very portable, and very inexpensive. Plus the 7 second boot time, and 8 hour battery life (on average) is <strong>amazing</strong>.</p>
<h3>Crouton for local development</h3>
<p>If you wish to do offline development crouton (basically ubuntu Chroot) can provide you a more full operating system for Chrome. This is a great way to maintain the lightweight basic ChromeOS while having immediate access to a more full operating system experience. This is obviously a basic hack to the ChromeOS, but it provides a great way to create applications locally. I think most people who get a Chromebook are blown away at how much is possible without the ubuntu sideload.</p>
<h3>Remote Desktop</h3>
<p>The old school approach to coding on the go is still viable. The RDP experience (if you don't mind windows) provides a full desktop session remotely. For intensive coding projects on the go this was always my alternative for working on projects everywhere. ChromeOS has more than one RDP application in the Chrome store, and most of them do a great job.</p>
<h2>tl;dr</h2>
<p>Chromebooks offer inexpensive way to leverage both cloud, and offline technologies to provide productivity, without sacrificing portability.</p>
Must have tool: LinqPad2014-04-15T02:59:46Zhttps://blog.terrible.dev/must-have-tool-linqpad/<p><a href="http://linqpad.net">LinqPad</a> is an interactive C#/F#/VB.NET scratchpad that lets you run arbitrary C#/F#/VB.NET code, and also lets you query databases with linq.</p>
<!-- more -->
<h2>What did that method do again?</h2>
<p>We have all been there....its way past your bedtime, and you cannot for the life of you remember what happens when string.Concat is called. You could try to just run something quick in your project to find out, but that would take time to build. You could google the result, and hope you can find the answer quickly....Or you can open linqpad and run the method!</p>
<p><img src="https://blog.terrible.dev/content/images/2014/Apr/linqpad.PNG" alt="query result from linqpad "></p>
<p>Ok of course you would never forget about string.Concat, but what about a method in a .dll? Well it can do that too!</p>
<h2>Quickly, I can't figure out the SQL Codez!</h2>
<p>Ok so if you are like myself you probably suck at SQL...I was once good until I saw the Linq light...only dynamically creating linq queries is never as good as having real stored procedures. The <a href="https://www.linqpad.net/WhyLINQBeatsSQL.aspx">Linq Website</a> has more examples of using SQL with linqpad than I could ever come up with.</p>
<p>To put it simply writing in linq is far more expressive than SQL. If I need to write a complex SQL query I usually Figure out the linq query, and when I am happy with the results, I click the SQL button. Magically linqpad returns the SQL code for the linq query!</p>
<h2>Can I debug my dll's ran in LinqPad using Visual Studio?</h2>
<p>Believe it or not...you can...Linqpad will easily import and run dll's. Once you have pointed linqpad to dll files, and imported the namespaces, you will be good to go. To attach visual studio as a debugger simply click debug, attach to process, and click on the linqpad process, with the proper project for debugging open. Once you start running your dll's in linqpad, the debugger will pickup what you are doing and stop the process at any linebreaks. The great part about this, is you can debug class libraries with linqpad without having to fire up a secondary project to run the code in.</p>
<h2>TL;DR?</h2>
<p>Linqpad converts linq to sql, and runs your .NET code from a simple scratchpad...If you suck at sql, or you want to quickly test something LinqPad rocks!</p>
Value types vs Reference Types in C#2014-04-10T02:21:19Zhttps://blog.terrible.dev/value-types-vs-reference-types-in-c-and-why-it-matters/<p>In C# there are two kinds of types...Value and reference...</p>
<h2>What are Reference Types?</h2>
<p>Reference types in C# are mostly objects and strings. These are types when placed on a stack refer to a memory address in the heap.</p>
<h2>What are Value Types?</h2>
<p>Value types make up the bulk of types in c#. These include int, float, double, long, bool, etc. These types values are only stored in the stack.</p>
<h2>Stack? Heap? What's the difference?</h2>
<p>To put it short, the <strong>stack</strong> is a series of memory blocks (like a scratch pad) that is used for the current thread. The stack is used for basic property data access. Accessing the stack is very rapid, as its only used for trivial data. The heap is an area of memory for dynamic memory allocation. The heap is used to store things in data that are not value types, usually objects and strings. The heap is slower to access, but larger in size.</p>
<h2>Reference type tripping points</h2>
<p>Reference types are basically pointers. These pointers can trip you up in interesting ways. For example suppose you have an object called MyObjectName:</p>
<pre><code>var MyObjectName = new SomeClass();
</code></pre>
<p>and you decide to make someone else's object name the same as you're name</p>
<pre><code>
var OtherObjectName = MyName;
</code></pre>
<p>When you change MyName to be something else, you will also change OtherName.</p>
<p>This is because objects are a reference type. On the stack the object is a pointer reference to the heap. When you make OtherName equal you are pointing it to the same memory address as MyName. You can see this in action <a href="https://dotnetfiddle.net/pGh3fT">here</a></p>
<pre><code>var MyName = new SomeClass();
var OtherName = MyName;
MyName = MyName.Name = "Joe";
//OtherName will now equal Joe
</code></pre>
<p>This is also the same for array's if you make 1 array equal another, you will not have 2 array's with the same value. You will have 2 variables that point to the same array.</p>
<h3>So the same must work for value types right?</h3>
<p><strong>No</strong></p>
<p>If you have 2 ints and assign one int to equal the other. The value on the stack will be copied to that int, and since the stack value is the actual value they will be independent of each other.</p>
<h2>Boxing and Un-Boxing</h2>
<p>When you have a value type and you want it on the heap you must convert it to an object. This is called boxing</p>
<pre><code>var val = 3;
var x = (object)val;
</code></pre>
<p>However once you do this, the two variables will be independent from each other. So if you change x you won't change val and vice-versa.</p>
<p>To get the object back on the stack you must cast it back into an int. This is called un-boxing</p>
<pre><code>
var y = (int)x;
</code></pre>
Custom error pages in Nancyfx (C# Web Framework)2014-04-01T00:40:54Zhttps://blog.terrible.dev/custom-error-pages-in-nancy/<p>To do custom error pages in Nancy you must implement an IStatusCodeHandler. This class must provide 2 methods. HandlesStatusCode is a bool that basically should tell Nancy if this class will handle the status code. If this returns true then this class will be responsible for handling the request.</p>
<!-- more -->
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">HandlesStatusCode</span><span class="token punctuation">(</span><span class="token class-name">HttpStatusCode</span> statusCode<span class="token punctuation">,</span> <span class="token class-name">NancyContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>statusCode <span class="token operator">==</span> <span class="token number">404</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Handle</span><span class="token punctuation">(</span><span class="token class-name">HttpStatusCode</span> statusCode<span class="token punctuation">,</span> <span class="token class-name">NancyContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> response <span class="token operator">=</span> viewRenderer<span class="token punctuation">.</span><span class="token function">RenderView</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> <span class="token string">"Your404View"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The only problem with the above code (which I have seen throughout the net) is you basically have to implement different IStatusCodeHandlers for each type (or types) of status codes.</p>
<p>What you can do is this <em>(or scroll to the end to see the final result)</em>....</p>
<p>First add the following properties... _checks will be where we store the list of http requests we will handle...This is a static class so it will be shared in memory with the other objects of the same class.</p>
<p>Checks will be the getter of this information, and viewRenderer will be the mechanism we will render the view.</p>
<pre><code>
private static IEnumerable<int> _checks = new List<int>();
public static IEnumerable<int> Checks { get { return _checks; } }
private IViewRenderer viewRenderer;
</code></pre>
<p>Next add an <strong>IViewRenderer</strong> to your constructor this will be dynamically injected by Nancy.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token function">CustomStatusCode</span><span class="token punctuation">(</span><span class="token class-name">IViewRenderer</span> viewRenderer<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>viewRenderer <span class="token operator">=</span> viewRenderer<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Afterwards we should add some methods so that people can add, and remove status codes from this store.</p>
<pre><code>
public static void AddCode(int code)
{
AddCode(new List<int>() {code});
}
public static void AddCode(IEnumerable<int> code)
{
_checks = _checks.Union(code);
}
public static void RemoveCode(int code)
{
RemoveCode(new List<int>() { code });
}
public static void RemoveCode(IEnumerable<int> code)
{
_checks = _checks.Except(code);
}
</code></pre>
<p>Now we have to tell Nancy what we are checking for:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">HandlesStatusCode</span><span class="token punctuation">(</span><span class="token class-name">HttpStatusCode</span> statusCode<span class="token punctuation">,</span> <span class="token class-name">NancyContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>_checks<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x <span class="token operator">==</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> statusCode<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>...and finally we should probably handle the status codes. Below will render a view that is located in Codes/{httprequestnumber}...So for a 404 this will render Codes/404.cshtml (<strong>Note:</strong> if you are not using razor you may wish to change the filename extension.</p>
<p>How this works is simple, try to render the view if it cannot (ie. it cannot find the file or it runs into a problem) remove the http request type from our list and return the status code, nancy will take it from there.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Handle</span><span class="token punctuation">(</span><span class="token class-name">HttpStatusCode</span> statusCode<span class="token punctuation">,</span> <span class="token class-name">NancyContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">try</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> response <span class="token operator">=</span> viewRenderer<span class="token punctuation">.</span><span class="token function">RenderView</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> <span class="token string">"/Codes/"</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>statusCode <span class="token operator">+</span> <span class="token string">".cshtml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
response<span class="token punctuation">.</span>StatusCode <span class="token operator">=</span> statusCode<span class="token punctuation">;</span>
context<span class="token punctuation">.</span>Response <span class="token operator">=</span> response<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">RemoveCode</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>statusCode<span class="token punctuation">)</span><span class="token punctuation">;</span>
context<span class="token punctuation">.</span>Response<span class="token punctuation">.</span>StatusCode <span class="token operator">=</span> statusCode<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>You will need to make the necessary view, and you will also need to give it the http codes you wish it to handle. In my case I add them from the web.config during start up. I also use a module to add/remove status codes at will (ill provide a sample of that module below)...</p>
<h2>Final Result</h2>
<h3>IStatusCodeHandler Class:</h3>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CustomStatusCode</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IStatusCodeHandler</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">IEnumerable<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> _checks <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">IEnumerable<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> Checks <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> _checks<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token class-name">IViewRenderer</span> viewRenderer<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token function">CustomStatusCode</span><span class="token punctuation">(</span><span class="token class-name">IViewRenderer</span> viewRenderer<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>viewRenderer <span class="token operator">=</span> viewRenderer<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">HandlesStatusCode</span><span class="token punctuation">(</span><span class="token class-name">HttpStatusCode</span> statusCode<span class="token punctuation">,</span> <span class="token class-name">NancyContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>_checks<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x <span class="token operator">==</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> statusCode<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">AddCode</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> code<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">AddCode</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>code<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">AddCode</span><span class="token punctuation">(</span><span class="token class-name">IEnumerable<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> code<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
_checks <span class="token operator">=</span> _checks<span class="token punctuation">.</span><span class="token function">Union</span><span class="token punctuation">(</span>code<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">RemoveCode</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> code<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">RemoveCode</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> code <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">RemoveCode</span><span class="token punctuation">(</span><span class="token class-name">IEnumerable<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> code<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
_checks <span class="token operator">=</span> _checks<span class="token punctuation">.</span><span class="token function">Except</span><span class="token punctuation">(</span>code<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Disable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
_checks <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Handle</span><span class="token punctuation">(</span><span class="token class-name">HttpStatusCode</span> statusCode<span class="token punctuation">,</span> <span class="token class-name">NancyContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">try</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> response <span class="token operator">=</span> viewRenderer<span class="token punctuation">.</span><span class="token function">RenderView</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> <span class="token string">"/Codes/"</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> statusCode <span class="token operator">+</span> <span class="token string">".cshtml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
response<span class="token punctuation">.</span>StatusCode <span class="token operator">=</span> statusCode<span class="token punctuation">;</span>
context<span class="token punctuation">.</span>Response <span class="token operator">=</span> response<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">RemoveCode</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>statusCode<span class="token punctuation">)</span><span class="token punctuation">;</span>
context<span class="token punctuation">.</span>Response<span class="token punctuation">.</span>StatusCode <span class="token operator">=</span> statusCode<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h3>Module that provides flexability:</h3>
<p><code>/error/add/404</code> will add 404's <code>/error/remove/404</code> will remove 404's</p>
<p>You could make a querystring accept an array if you wish, in my case this isn't needed.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">StatusCodesModule</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">NancyModule</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token function">StatusCodesModule</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span><span class="token string">"error"</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
Get<span class="token punctuation">[</span><span class="token string">"/add/{code}"</span><span class="token punctuation">]</span> <span class="token operator">=</span> x <span class="token operator">=></span>
<span class="token punctuation">{</span>
CustomStatusCode<span class="token punctuation">.</span><span class="token function">AddCode</span><span class="token punctuation">(</span>x<span class="token punctuation">.</span>code<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token string">"done"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
Get<span class="token punctuation">[</span><span class="token string">"/remove/{code}"</span><span class="token punctuation">]</span> <span class="token operator">=</span> x <span class="token operator">=></span>
<span class="token punctuation">{</span>
CustomStatusCode<span class="token punctuation">.</span><span class="token function">RemoveCode</span><span class="token punctuation">(</span>x<span class="token punctuation">.</span>code<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token string">"done"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h3>Bootstrapper startup</h3>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Bootstrapper</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">DefaultNancyBootstrapper</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ApplicationStartup</span><span class="token punctuation">(</span><span class="token class-name">TinyIoCContainer</span> container<span class="token punctuation">,</span> <span class="token class-name">IPipelines</span> pipelines<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
CustomStatusCode<span class="token punctuation">.</span><span class="token function">AddCode</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
CustomStatusCode<span class="token punctuation">.</span><span class="token function">AddCode</span><span class="token punctuation">(</span>ConfigurationManager<span class="token punctuation">.</span>AppSettings<span class="token punctuation">[</span><span class="token string">"HttpErrorCodes"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token char">','</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>x <span class="token operator">=></span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">Parse</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">ApplicationStartup</span><span class="token punctuation">(</span>container<span class="token punctuation">,</span> pipelines<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
Getting SquishIt to work with Nancyfx and Razor (...and other static content issues)2014-03-23T06:04:20Zhttps://blog.terrible.dev/getting-squishit-to-work-with-nancyfx-and-razor/<p>SquishIt is a content bundler and minification tool. The <a href="https://github.com/NancyFx/Nancy/wiki/SquishIt-with-Nancy">github</a> documentation contains exaples how to install and use it, and a <a href="https://github.com/jetheredge/SquishIt">sample application</a> is provided. However I had some issues getting it to work with razor so I figured I would share these pain points with you.</p>
<!-- more -->
<h2>Razor cannot find Assemblies</h2>
<p>To start my project is a Nancyfx application with razor view engine installed. I initially ran <code>Install-Package SquishIt</code>. Once installed I <a href="http://blogs.lessthandot.com/index.php/webdev/serverprogramming/aspnet/squishit-and-nancy/">ran through another tutorial</a> that requires some editing of the webconfig. However my webconfig has been altered a lot already, and it did not look like the sample application. I am also not a guru in the web.config so I was kind of confused where to place the sample XML provided. I ignored the webconfig, I fired up nancy and tried to use SquishIt, only to get the following razor compile error.</p>
<p><code>The type or namespace name 'SquishIt' could not be found (are you missing a using directive or an assembly reference?) </code></p>
<p>It seems you <strong>must</strong> tell razor about squishIt's assemblies. Well It turns out there are basically 2 blocks of entries you need to add to your web.config. First you need to place <code><section name="razor" type="Nancy.ViewEngines.Razor.RazorConfigurationSection, Nancy.ViewEngines.Razor"/></code> inside <code><configSections></code> but outside of <code><sectionGroup></code>.</p>
<p>You should end up with a section config that looks like the following:</p>
<pre class="language-xml" tabindex="0"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>configSections</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>sectionGroup</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>system.web.webPages.razor<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral>
<section name=<span class="token punctuation">"</span></span><span class="token attr-name">pages"</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral requirePermission=<span class="token punctuation">"</span></span><span class="token attr-name">false"</span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>sectionGroup</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>section</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>razor<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Nancy.ViewEngines.Razor.RazorConfigurationSection, Nancy.ViewEngines.Razor<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>configSections</span><span class="token punctuation">></span></span></code></pre>
<p>Next paste the following XML <strong>after</strong> <code></configSections></code></p>
<pre class="language-xml" tabindex="0"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>razor</span> <span class="token attr-name">disableAutoIncludeModelNamespace</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>assemblies</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>add</span> <span class="token attr-name">assembly</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>SquishIt.Framework<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>assemblies</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>namespaces</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>add</span> <span class="token attr-name">namespace</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>SquishIt.Framework<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>namespaces</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>razor</span><span class="token punctuation">></span></span></code></pre>
<p>Once I did this the razor views could compile, and it seemed to work, but not quite...</p>
<h2>SquishIt cannot resolve file paths</h2>
<p>Once I got it up and running, things did not seem right. So I started combing through google. I stumbled across a <a href="https://groups.google.com/forum/#!msg/squishit/YBsUiL9v1Ow/7lBJmMIHGMoJ">thread</a> where the creator of SquishIt noted SquishIt was having issues with resolving file paths. This was caused by a change to Nancy.</p>
<p>He notes a <a href="https://github.com/AlexCuse/SquishIt.NancySample/commit/7338026d4d425960151978171596749066b460bc">commit</a> to the sample application that fixes the problem. In nuget I updated SquishIt with the <code>-pre</code> flag so I could get the latest release. Once I did I implemented the following class (from the gitcommit):</p>
<pre class="language-c-like" tabindex="0"><code class="language-c-like">
using Nancy;
using SquishIt.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Class.Web
{
public class NancyPathTranslator : IPathTranslator
{
private readonly IRootPathProvider _rootPathProvider;
public NancyPathTranslator(IRootPathProvider rootPathProvider)
{
_rootPathProvider = rootPathProvider;
}
public string ResolveAppRelativePathToFileSystem(string file)
{
// Remove query string
if (file.IndexOf('?') != -1)
{
file = file.Substring(0, file.IndexOf('?'));
}
return _rootPathProvider.GetRootPath() + "/" + file.TrimStart('~').TrimStart('/');
}
public string ResolveFileSystemPathToAppRelative(string file)
{
var root = new Uri(_rootPathProvider.GetRootPath());
return root.MakeRelativeUri(new Uri(file, UriKind.RelativeOrAbsolute)).ToString();
}
}
}
</code></pre>
<p>And then added</p>
<pre class="language-c-like" tabindex="0"><code class="language-c-like">
Bundle.ConfigureDefaults().UsePathTranslator(new NancyPathTranslator(new AspNetRootSourceProvider()));
</code></pre>
<p>Which seemed to work. I believe if you have your file paths be the same as the paths called by the HTML, it will probably work fine without the above fix.</p>
<h2>Scripts/ folder doesn't work</h2>
<p>This isn't actually a SquishIt problem, but I didn't notice this until I installed SquishIt. Files in a Scripts/ folder will not be served up by Nancy.</p>
<p>Back to Google I went, and I found my answer on <a href="http://stackoverflow.com/a/13517803">stack overflow</a>. Apparently Nancy only uses Content/ as the content directory, for static content. I ended up adding the following to my ConfigureConventions override.</p>
<pre class="language-c-like" tabindex="0"><code class="language-c-like">
protected override void ConfigureConventions(Nancy.Conventions.NancyConventions nancyConventions)
{
nancyConventions.StaticContentsConventions.AddDirectory("Scripts","Scripts/");
base.ConfigureConventions(nancyConventions);
}
</code></pre>
<p>The AddDirectory requires 2 strings, the first being the route to expect, the second is the directory it needs. This will enable the scripts folder to work in its entirety. You can use this to add other content directories. For me this worked fine.</p>
<h2>Serving content</h2>
<p>Now that it all worked I added <code>Bundle.Css().Add("~/Content/bootstrap.css").AsCached("bootstrap", "~/assets/css/bootstrap");</code> to my ApplicationStartup override. Created a module to serve up the static content (stolen from <a href="https://github.com/NancyFx/Nancy/wiki/SquishIt-with-Nancy">github</a>) .</p>
<pre class="language-c-like" tabindex="0"><code class="language-c-like">
public class ServeAsset : NancyModule
{
public ServeAsset():base("/assets")
{
Get["/js/{name}"] = parameters => CreateResponse(Bundle.JavaScript().RenderCached((string)parameters.name), Configuration.Instance.JavascriptMimeType);
Get["/css/{name}"] = parameters => CreateResponse(Bundle.Css().RenderCached((string)parameters.name), Configuration.Instance.CssMimeType);
}
Response CreateResponse(string content, string contentType)
{
return Response
.FromStream(() => new MemoryStream(Encoding.UTF8.GetBytes(content)), contentType)
.WithHeader("Cache-Control", "max-age=45");
}
}
</code></pre>
<p>Then added <code> @Html.Raw(Bundle.Css().RenderCachedAssetTag("bootstrap"))</code> to my razor view, and by magic it works.</p>
<p>As a side note, it will only minify if you're not in debug mode. So if you're application's webconfig has <code><compilation debug="true" targetFramework="4.5"></code> you may want flip it to false to see the minified files.</p>
<p>This behavior can be overridden with the <code>.ForceRelease()</code> as part of your bundle. ex. <code>Bundle.Css().Add("~/Content/bootstrap.css").ForceRelease().AsCached("bootstrap", "~/assets/css/bootstrap");</code></p>
<h2>Conclusion</h2>
<p>Well after the work above I was finally generating minified files. SquishIt's ability to minify quickly is very nice. The way it manages files reminds me of the <a href="http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification">MVC4 Bundling</a>, but SquishIt allows for much greater control over the process.</p>
Capturing Client Side JavaScript Errors2014-03-19T23:57:16Zhttps://blog.terrible.dev/capturing-client-side-javascript-errors/<p>Capturing client side errors in my opinion is really good. For starters you can troubleshoot your client side implementation, but you can also make sure a js change did not break certain pages.</p>
<p>Below is a really simple, yet effective way to capture errors. Eventually you may want to implement something more advanced, but this will get you out of the gate.</p>
<!-- more -->
<pre class="language-javascript" tabindex="0"><code class="language-javascript">window<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">errorMsg<span class="token punctuation">,</span> url<span class="token punctuation">,</span> lineNumber<span class="token punctuation">,</span> column<span class="token punctuation">,</span> error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
$<span class="token punctuation">.</span><span class="token function">ajax</span><span class="token punctuation">(</span><span class="token string">'/api/Error'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
<span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token literal-property property">Message</span><span class="token operator">:</span> errorMsg<span class="token punctuation">,</span>
<span class="token literal-property property">ScriptUrl</span><span class="token operator">:</span> url<span class="token punctuation">,</span>
<span class="token literal-property property">Line</span><span class="token operator">:</span> lineNumber<span class="token punctuation">,</span>
<span class="token literal-property property">PageUrl</span><span class="token operator">:</span> window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>protocol <span class="token operator">+</span> <span class="token string">"//"</span> <span class="token operator">+</span> window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>host <span class="token operator">+</span> <span class="token string">"/"</span> <span class="token operator">+</span> window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>pathname<span class="token punctuation">,</span>
<span class="token function-variable function">StackTrace</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">return</span> error <span class="token operator">?</span> error<span class="token punctuation">.</span>stack<span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>You will need Jquery, and a server side API to accept the data. Not all browsers are currently including a Stack Trace, so you will only get stacks from certain browsers.</p>
You hired adults, not children2014-03-15T08:17:54Zhttps://blog.terrible.dev/you-hired-adults-not-children/<p>One of the things that I often see in our industry is the culture of access control. Security measures are put into place, because you wish to restrict access to a certain thing. Systems like HRIS need such restrictions, as private information should not be publicly available to the company. However often systems that don't need security controls put into place end up having them.</p>
<blockquote>
<p>Most people understand where they fall in the business, and the authority delegated to them.</p>
</blockquote>
<!-- more -->
<h2>Filtering Internet</h2>
<p>Filtering internet is a controversial topic in most work places. By actively monitoring your employees activities on the internet, they will feel a sense of distrust. If you trust this person to write code for your production website, you can probably trust them to surf at will. I'm not Advocating that you don't log the activity. However you shouldn't actively block websites, or read the logs. Activity Logs should only be used when legal problems arise, and <strong>not</strong> something you hang over your employee's heads.</p>
<h2>Ownership and Directed Management</h2>
<p>Let employees have ownership of their work. Let them understand that with the freedom to own things, comes the responsibility to that thing. Employees whom decide to use non-standard technologies, should have to own that thing entirely. Stopping them from using it can be a barrier to productivity, especially if that particular technology is best for their project.</p>
<p>Asking someone to do something without context is demoralizing. Let employees know why you are asking them to do something. This establishes your motives, and gives that person a sense as to how they fit in the organization. If someone asks you to do something, and you are busy let them know why you can't fulfill their request at that moment.</p>
<h2>Access Control: Barrier of productivity</h2>
<p>One of the huge problems in most companies are barriers to productivity. These can be caused by processes, but also access control. Most systems do not need have access control set around them. If you trust your employees, and colleagues to be adults, you should not have to lock them out of xyz system as long at that system does not store sensitive data. No one manager or even team should have to approve specific patches. Anyone who feels they have authority to approve something, should be able to do so. People fully understand the authority delegated to them. Waiting for specific people can be ultimately a huge barrier to success.</p>
<h2>Overall Message</h2>
<p>There is nothing wrong with being a manager, but try to delegate responsibility to you're subordinates. Give them the trust and respect that they deserve. Employees whom are empowered are more antonymous and are ultimately more productive than their oppressed counterparts.</p>
Admob with Xamarin Android Part 2: InterstitialAd2014-03-11T05:44:06Zhttps://blog.terrible.dev/admob-with-xamarin-part-2-interstitialad/<p><span style="float: left"><a href="https://blog.terrible.dev/admob-with-xamarin-part-1-banner-ads/">Part 1: Banner Ads <i class="fa fa-hand-o-left"></i></a></span><br></p>
<p>Interested in Interstital ads, but not banner? Thats ok, but I recommend your read my first post about <a href="https://blog.terrible.dev/admob-with-xamarin-part-1-banner-ads/">banner ads</a>. The first steps, installing Google Play Services, altering your permissions, adding to your manifests files, and reviewing my <a href="https://github.com/TerribleDev/XamarinAdmobTutorial">github demo</a> are located in that tutorial.</p>
<!-- more -->
<h2>The Basics</h2>
<p>The very basic amount of code to do Interstitial Ad's are below</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> ad <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">InterstitialAd</span><span class="token punctuation">(</span>con<span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span>AdUnitId <span class="token operator">=</span> <span class="token string">"unitID"</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> requestbuilder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">AdRequest<span class="token punctuation">.</span>Builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span><span class="token function">LoadAd</span><span class="token punctuation">(</span>requestbuilder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span><span class="token function">Show</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<p>The problem with the above code is it tries to show the ad right away, but the ad may not be loaded already. The unique way interstitial ads work, are you must call <code>Show()</code>, after the banner is downloaded. So we must have an event listener that hears when the ad is loaded, before we can show it.</p>
<h2>Doing things better</h2>
<p>Back to my github code, the Adwrapper class contains build methods for <em>full page ad</em> aka Interstitial.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>App</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Content</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>OS</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Runtime</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Views</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Widget</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Gms<span class="token punctuation">.</span>Ads</span><span class="token punctuation">;</span>
<span class="token keyword">namespace</span> <span class="token namespace">admobDemo<span class="token punctuation">.</span>AndroidPhone<span class="token punctuation">.</span>ad</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">AdWrapper</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">InterstitialAd</span> <span class="token function">ConstructFullPageAdd</span><span class="token punctuation">(</span><span class="token class-name">Context</span> con<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">string</span></span> UnitID<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> ad <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">InterstitialAd</span><span class="token punctuation">(</span>con<span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span>AdUnitId <span class="token operator">=</span> UnitID<span class="token punctuation">;</span>
<span class="token keyword">return</span> ad<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">InterstitialAd</span> <span class="token function">CustomBuild</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">InterstitialAd</span> ad<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> requestbuilder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">AdRequest<span class="token punctuation">.</span>Builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span><span class="token function">LoadAd</span><span class="token punctuation">(</span>requestbuilder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> ad<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The custom build extension method works the same as the banner ad method, and has not been customized in this template.</p>
<p>The InterstitialAd class does not come with native event listeners. To implement listeners you must create a class that inherits from AdListner and then define the event listeners. We will want to do this so we can show the ad once it is downloaded to the phone, and not have to keep checking to see if it has downloaded. The demo code AdEventListener.cs file in the ad folder of AndroidPhone project contains an implementaiton of this.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">namespace</span> <span class="token namespace">admobDemo</span>
<span class="token punctuation">{</span>
<span class="token keyword">class</span> <span class="token class-name">adlistener</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">AdListener</span></span>
<span class="token punctuation">{</span>
<span class="token comment">// Declare the delegate (if using non-generic pattern).</span>
<span class="token keyword">public</span> <span class="token keyword">delegate</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">AdLoadedEvent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">delegate</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">AdClosedEvent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">delegate</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">AdOpenedEvent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Declare the event.</span>
<span class="token keyword">public</span> <span class="token keyword">event</span> <span class="token class-name">AdLoadedEvent</span> AdLoaded<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">event</span> <span class="token class-name">AdClosedEvent</span> AdClosed<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">event</span> <span class="token class-name">AdOpenedEvent</span> AdOpened<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnAdLoaded</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>AdLoaded <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">AdLoaded</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnAdLoaded</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnAdClosed</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>AdClosed <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">AdClosed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnAdClosed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnAdOpened</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>AdOpened <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">AdOpened</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnAdOpened</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Once you have these componants in place your activity should end up looking like this.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">using</span> <span class="token namespace">System</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>App</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Content</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Runtime</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Views</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Widget</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>OS</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Gms<span class="token punctuation">.</span>Ads</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">admobDemo</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">admobDemo<span class="token punctuation">.</span>AndroidPhone<span class="token punctuation">.</span>ad</span><span class="token punctuation">;</span>
<span class="token keyword">namespace</span> <span class="token namespace">admobDemo<span class="token punctuation">.</span>AndroidPhone</span>
<span class="token punctuation">{</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Activity</span><span class="token attribute-arguments"><span class="token punctuation">(</span>Label <span class="token operator">=</span> <span class="token string">"admobDemo.AndroidPhone"</span><span class="token punctuation">,</span> MainLauncher <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> Icon <span class="token operator">=</span> <span class="token string">"@drawable/icon"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Activity1</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Activity</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnCreate</span><span class="token punctuation">(</span><span class="token class-name">Bundle</span> bundle<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnCreate</span><span class="token punctuation">(</span>bundle<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Set our view from the "main" layout resource</span>
<span class="token function">SetContentView</span><span class="token punctuation">(</span>Resource<span class="token punctuation">.</span>Layout<span class="token punctuation">.</span>Main<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> FinalAd <span class="token operator">=</span> AdWrapper<span class="token punctuation">.</span><span class="token function">ConstructFullPageAdd</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token string">"your ad id here"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> intlistener <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">admobDemo<span class="token punctuation">.</span>adlistener</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
intlistener<span class="token punctuation">.</span>AdLoaded <span class="token operator">+=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>FinalAd<span class="token punctuation">.</span>IsLoaded<span class="token punctuation">)</span>FinalAd<span class="token punctuation">.</span><span class="token function">Show</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
FinalAd<span class="token punctuation">.</span>AdListener <span class="token operator">=</span> intlistener<span class="token punctuation">;</span>
FinalAd<span class="token punctuation">.</span><span class="token function">CustomBuild</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>To walk you through the code...after <code>SetContentView()</code>....We make a full page Ad <em>(and pass it our AD id)</em>, we create an event listener based on the ad listener class. We set the event listener to trigger an annonymous function that will show the ad. we make the Ad's event listener to be the event listener we made, then we run CustomBuild which builds the Ad and starts loading the Ad. Once the ad loads it will call the event handler, and Boom! Show the ad to the user.</p>
<p>Obviously this is a basic implementation, and showing the ad when the app first starts may, or may not be the best stratergy for <strong>You</strong>.</p>
Admob with Xamarin Android Part 1: BannerAd2014-03-11T04:51:51Zhttps://blog.terrible.dev/admob-with-xamarin-part-1-banner-ads/<p><span style="float: right"><a href="https://blog.terrible.dev/admob-with-xamarin-part-2-interstitialad/"><i class="fa fa-hand-o-right"></i> Part 2: Interstitial Ads</a></span><br></p>
<p>This will be a brief overview on how to get admob working with Xamarin.</p>
<h2>Disclaimer</h2>
<p>I highly suggest you run this on a real phone. I'm not sure if the virtual phones can load content on the internet. I always develop on a real phone.</p>
<p>Sample code located in a <a href="https://github.com/TerribleDev/XamarinAdmobTutorial">repo at github</a></p>
<!-- more -->
<h2>Create an admob account</h2>
<p>First you will need to create an account. After you do so create an ad, you must choose either full page aka Interstitial, or banner ad.</p>
<h2>Install Play Services Component</h2>
<p>This is quite simple right click on the components folder (in visual studio, or xamarin studio) and click get more components.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/Mar/componant.png" alt="get a componant"></p>
<p>Find the play services you require and click Add to App.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/Mar/playservices.PNG" alt=""></p>
<p>Add the following XML to your Android Manifest file, place it in between the <code><application></application></code> tags.</p>
<pre class="language-xml" tabindex="0"><code class="language-xml">
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta-data</span> <span class="token attr-name"><span class="token namespace">android:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.google.android.gms.version<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">android:</span>value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@integer/google_play_services_version<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>activity</span> <span class="token attr-name"><span class="token namespace">android:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.google.android.gms.ads.AdActivity<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">android:</span>configChanges</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
</code></pre>
<h2>Add proper permissions</h2>
<p>You need to add these permissions to your AssemblyInfo.cs</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token target keyword">assembly</span><span class="token punctuation">:</span> <span class="token class-name">UsesPermission</span><span class="token attribute-arguments"><span class="token punctuation">(</span>Android<span class="token punctuation">.</span>Manifest<span class="token punctuation">.</span>Permission<span class="token punctuation">.</span>Internet<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token target keyword">assembly</span><span class="token punctuation">:</span> <span class="token class-name">UsesPermission</span><span class="token attribute-arguments"><span class="token punctuation">(</span>Android<span class="token punctuation">.</span>Manifest<span class="token punctuation">.</span>Permission<span class="token punctuation">.</span>AccessNetworkState<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span></code></pre>
<h2>The Basics</h2>
<p>The standard code to create an ad is something like this:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Gms<span class="token punctuation">.</span>Ads</span><span class="token punctuation">;</span>
<span class="token keyword">namespace</span> <span class="token namespace">funtimes</span>
<span class="token punctuation">{</span>
<span class="token keyword">class</span> <span class="token class-name">a</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Activity</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Method</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> ad <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">AdView</span><span class="token punctuation">(</span>con<span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span>AdSize <span class="token operator">=</span> AdSize<span class="token punctuation">.</span>SmartBanner<span class="token punctuation">;</span>
ad<span class="token punctuation">.</span>AdUnitId <span class="token operator">=</span> 'your id here'<span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> requestbuilder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">AdRequest<span class="token punctuation">.</span>Builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span><span class="token function">LoadAd</span><span class="token punctuation">(</span>requestbuilder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> layout <span class="token operator">=</span> <span class="token generic-method"><span class="token function">FindViewById</span><span class="token generic class-name"><span class="token punctuation"><</span>LinearLayout<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>Resource<span class="token punctuation">.</span>Id<span class="token punctuation">.</span>mainlayout<span class="token punctuation">)</span><span class="token punctuation">;</span>
layout<span class="token punctuation">.</span><span class="token function">AddView</span><span class="token punctuation">(</span>ad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h2>Doing things better</h2>
<p>However in the interests of showing, and creating more flexible code this tutorial will guide you through the wrapper implementation I constructed, and posted on <a href="https://github.com/TerribleDev/XamarinAdmobTutorial">github</a>.</p>
<p>To start I created admobDemo.AndroidPhone.ad.AdWrapper.cs This code abstracts out some of the verbose building process, and allows the building Ad code to be reused. the code pertaining banner ads looks like this</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Gms<span class="token punctuation">.</span>Ads</span><span class="token punctuation">;</span>
<span class="token keyword">namespace</span> <span class="token namespace">admobDemo<span class="token punctuation">.</span>AndroidPhone<span class="token punctuation">.</span>ad</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">AdWrapper</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">AdView</span> <span class="token function">ConstructStandardBanner</span><span class="token punctuation">(</span><span class="token class-name">Context</span> con<span class="token punctuation">,</span> <span class="token class-name">AdSize</span> adsize<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">string</span></span> UnitID<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> ad <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">AdView</span><span class="token punctuation">(</span>con<span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span>AdSize <span class="token operator">=</span> adsize<span class="token punctuation">;</span>
ad<span class="token punctuation">.</span>AdUnitId <span class="token operator">=</span> UnitID<span class="token punctuation">;</span>
<span class="token keyword">return</span> ad<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">AdView</span> <span class="token function">CustomBuild</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">AdView</span> ad<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name"><span class="token keyword">var</span></span> requestbuilder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">AdRequest<span class="token punctuation">.</span>Builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ad<span class="token punctuation">.</span><span class="token function">LoadAd</span><span class="token punctuation">(</span>requestbuilder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> ad<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The ConstructStandardBanner method takes in a context (usually this in an activity class), an ad size which usually people use AdSize.SmartBanner, and the unitID of your Ad (ID that you got from admob).</p>
<p>The <a href="http://msdn.microsoft.com/en-us/library/bb383977.aspx">extension</a> method <code>CustomBuild</code> allows you to define things in the requestbuilder <em>(which I have not changed in this implementation)</em>. The request builder is mostly to give demographic information to Google, to help serve up a <em>better</em> ad.</p>
<p>Your main activity should end up looking something like this:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token keyword">using</span> <span class="token namespace">System</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>App</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Content</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Runtime</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Views</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Widget</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>OS</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">Android<span class="token punctuation">.</span>Gms<span class="token punctuation">.</span>Ads</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">admobDemo</span><span class="token punctuation">;</span>
<span class="token keyword">using</span> <span class="token namespace">admobDemo<span class="token punctuation">.</span>AndroidPhone<span class="token punctuation">.</span>ad</span><span class="token punctuation">;</span>
<span class="token keyword">namespace</span> <span class="token namespace">admobDemo<span class="token punctuation">.</span>AndroidPhone</span>
<span class="token punctuation">{</span>
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Activity</span><span class="token attribute-arguments"><span class="token punctuation">(</span>Label <span class="token operator">=</span> <span class="token string">"admobDemo.AndroidPhone"</span><span class="token punctuation">,</span> MainLauncher <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> Icon <span class="token operator">=</span> <span class="token string">"@drawable/icon"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Activity1</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Activity</span></span>
<span class="token punctuation">{</span>
<span class="token class-name">AdView</span> _bannerad<span class="token punctuation">;</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnCreate</span><span class="token punctuation">(</span><span class="token class-name">Bundle</span> bundle<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnCreate</span><span class="token punctuation">(</span>bundle<span class="token punctuation">)</span><span class="token punctuation">;</span>
_bannerad <span class="token operator">=</span> AdWrapper<span class="token punctuation">.</span><span class="token function">ConstructStandardBanner</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> AdSize<span class="token punctuation">.</span>SmartBanner<span class="token punctuation">,</span> <span class="token string">"your ad id here"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
_bannerad<span class="token punctuation">.</span><span class="token function">CustomBuild</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> layout <span class="token operator">=</span> <span class="token generic-method"><span class="token function">FindViewById</span><span class="token generic class-name"><span class="token punctuation"><</span>LinearLayout<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>Resource<span class="token punctuation">.</span>Id<span class="token punctuation">.</span>mainlayout<span class="token punctuation">)</span><span class="token punctuation">;</span>
layout<span class="token punctuation">.</span><span class="token function">AddView</span><span class="token punctuation">(</span>_bannerad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnResume</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>_bannerad <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> _bannerad<span class="token punctuation">.</span><span class="token function">Resume</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnResume</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnPause</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>_bannerad <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>_bannerad<span class="token punctuation">.</span><span class="token function">Pause</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnPause</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>As you can see we are constructing the banner using our wrapper. Then we are calling it's custom build extension method. We are getting a LinearLayout that has been defined in the views's .axml file (you can add your own their if you wish) and then we are injecting the banner into this LinearLayout.</p>
<p>You need to make sure you pause and resume the bannerAds by including them in the overrides on the Activity class. You also need to make sure you give it your ad ID.</p>
<p>If you have issues where the ad does not show, you may want to make sure whatever LinearLayout (or other UI control) you inject the banner into is being shown in the UI. I once saw a problem where one layout was filling the parent so the other was not being shown, therefore the banner was hidden.</p>
Abstracting Xamarin Android SharedPreferences2014-03-06T18:55:25Zhttps://blog.terrible.dev/xamarin-android-sharedpreferences/<p>The standard way to get/set SharedPreferences in Xamarin is with the following code.</p>
<p>Get Preference:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> shared <span class="token operator">=</span> con<span class="token punctuation">.</span><span class="token function">GetSharedPreferences</span><span class="token punctuation">(</span>_preferenceName<span class="token punctuation">,</span> FileCreationMode<span class="token punctuation">.</span>WorldReadable<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> <span class="token keyword">value</span> <span class="token operator">=</span> shared<span class="token punctuation">.</span>All<span class="token punctuation">.</span><span class="token function">Where</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>Key <span class="token operator">==</span> key<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>Value<span class="token punctuation">;</span>
</code></pre>
<p>Set Preference:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> shared <span class="token operator">=</span> con<span class="token punctuation">.</span><span class="token function">GetSharedPreferences</span><span class="token punctuation">(</span><span class="token string">"PreferenceName"</span><span class="token punctuation">,</span> FileCreationMode<span class="token punctuation">.</span>WorldWriteable<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> edit <span class="token operator">=</span> shared<span class="token punctuation">.</span><span class="token function">Edit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
edit<span class="token punctuation">.</span><span class="token function">PutString</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span>
edit<span class="token punctuation">.</span><span class="token function">Commit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>The main issue I have/had with this is you often have to know what will be returned, and what type you need to save as. Usually this isn't difficult, but it adds an un-needed level of complexity.</p>
<p>The other major issues I have with this, is that it is quite verbose, and unnecessary. The code duplication here can be quite high.</p>
<!-- more -->
<h2>The Solution</h2>
<p>I recently added on <a href="https://github.com/TerribleDev/XamAndroidSettings">github</a> an abstraction around the shared preferences that make it easier to use. This class uses <a href="http://msdn.microsoft.com/en-us/library/512aeb7t.aspx">c# generics</a>, and an extension method I wrote for <code>ISharedPreferencesEditor</code> that make SharedPreferences easier to use.</p>
<p>The sample code below shows how to use it.</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp">
<span class="token class-name"><span class="token keyword">var</span></span> sk <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">SettingsKey<span class="token punctuation"><</span><span class="token keyword">string</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token string">"KeyName"</span><span class="token punctuation">,</span> <span class="token string">"PreferenceName"</span><span class="token punctuation">,</span> <span class="token string">"DefaultValuehere"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token keyword">var</span></span> setting <span class="token operator">=</span> sk<span class="token punctuation">.</span><span class="token function">GetSetting</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
<span class="token class-name"><span class="token keyword">var</span></span> setsetting <span class="token operator">=</span> sk<span class="token punctuation">.</span><span class="token function">SetSetting</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token string">"New Value!"</span><span class="token punctuation">)</span>
</code></pre>
<p>To start create a new <code>SettingsKey</code> class and provide a primative type (Note: it only accepts String, Bool, Int, Float, Long).</p>
<p><code>var sk = new SettingsKey<string>("KeyName", "PreferenceName", "DefaultValuehere");</code></p>
<p>My example creates an object called sk with T of type string. You must give the key a name, you must provide the preferenceName (name used to share the settings with other classes),and you must give it a default value (because the user setting may not exist yet).</p>
<p>Below is a version that uses int:</p>
<p>``var sk = new SettingsKey<int>("Times app has been loaded", "PreferenceName", 15);`</int></p>
<p>Afterwards you can simply use <code>sk.GetSetting(this)</code> to get the setting and <code>sk.SetSetting(this, 25)</code> to set a new setting.</p>
<p>The way I used this, was to have the settingskey classes wrapped in a repository-type class with the keys pre-defined (in a struct). Using this I was able to call <code>repo.sk1.GetSetting();</code> throughout my application without having to worry if I typed the correct key in or not. This was especially valuable when I wrote my <a href="https://play.google.com/store/apps/details?id=ultimategravatarsync.ultimategravatarsyncfree">GravatarSync</a> app which has a service backend service, and a front end activity that both access the preferences.</p>
<h2>The Result</h2>
<p>After making this I wanted to start using SharedPreferences as a storage medium. Setting up localSQL for your app is a pain, and maintaing that data when an update to your app is pushed out can be risky. The SharedPreferences are maintained even upon an update, and android does not let these settings get deleted (unless the user deletes them).</p>
Receiving feedback (without being an asshole)...2014-03-02T21:12:08Zhttps://blog.terrible.dev/receiving-feedback-without-being-an-asshole/<p><span style="float: left"><a href="https://blog.terrible.dev/providing-feedback-without-being-an-asshole/">Providing feedback <i class="fa fa-hand-o-left"></i></a></span><br></p>
<p>Feedback is a two way street if you are willing to hear your strengths reinforced, you should be able to handle what people think are your flaws.</p>
<!-- more -->
<h2>Don't get Emotional</h2>
<p>One of the big problems I have when providing feedback is that person often takes it far more personal than its intended. If someone has properly sat you down and asked you for a moment of your time, they are taking time out of their day, and yours. They are doing this, because they want to see your professional relationship with that person to grow and succeed.</p>
<blockquote>
<p>Listen to the feedback in detail, and try to see things from their perspective.</p>
</blockquote>
<h2>Ask Questions</h2>
<p>You need to ask questions here. This is how you identify what exactly the problem is and why. Also let them understand your perspective, and why you thought you were doing the right thing. Fully understand the problem at hand. Even if you disagree with the feedback, acknowledge their stance and be polite during the conversation.</p>
<h2>Don't pull others into the conversation</h2>
<p>Do not try to Place blame on others, just remember these are <strong>you're</strong> behavior problems, not someone else's. Don't tell them to also talk to <em>XYZ</em> person, just because you think they are also doing the same. If they are doing the same problem, inform that person directly using my <a href="https://blog.terrible.dev/providing-feedback-without-being-an-asshole/">guide</a> on providing feedback.</p>
<h2>Show Appreciation</h2>
<p>Even if you disagree always show appreciation. Let them know their time is not wasted, and always seem approachable. The ultimate goal is to take the feedback, while still maintaining a solid relationship with this person. Just remember whomever they are you are most likely going to have to interact with them again in you're organization.</p>
<h2>...but I disagree</h2>
<p>If you really disagree take in the feedback, wait until the emotional level has calmed and then really point out why you disagree. Do not start yelling, or raising your voice, and always give your honest opinion. If you feel that the conversation is going nowhere, let the dust settle for a few days. If you feel you want to talk about it again, ask them to sit back down with you and resume the conversation in a civilized manor. Just remember being approachable is number one in a corporate atmosphere, and upsetting people is a career killer.</p>
Installing NodeBB on CentOS 6.52014-03-01T19:14:42Zhttps://blog.terrible.dev/installing-nodebb-on-centos-6-5/<p><a href="https://nodebb.org/">NodeBB</a> is forum software written on <a href="http://nodejs.org/">Node.js</a></p>
<p>The official installation instructions are on <a href="https://github.com/designcreateplay/NodeBB">github</a>, but the documentation is for <a href="http://www.ubuntu.com/">Ubuntu</a>.</p>
<p>To install on CentOS follow these instructions.</p>
<!-- more -->
<p>Install the base software stack.</p>
<pre><code>sudo yum update
sudo yum groupinstall "Development Tools" -y
sudo yum install nodejs git redis ImageMagick npm
</code></pre>
<p>Next, clone the repository.</p>
<pre><code> cd /path/to/nodebb/install/location
git clone git://github.com/designcreateplay/NodeBB.git nodebb
</code></pre>
<p>Obtain npm Dependencies.</p>
<pre><code>cd nodebb
sudo npm install -g npm
sudo npm install
</code></pre>
<p>Start Redis</p>
<pre><code>sudo service redis start
</code></pre>
<p>Then run through the setup (it will prompt you for things like listening on port numbers and host-names).</p>
<pre><code>./nodebb setup
</code></pre>
<p>After start it up.</p>
<pre><code>./nodebb start
</code></pre>
<p>Now you should be able to access it in the web browser (using the config you setup earlier).</p>
Setting up robots.txt for your ghost powered blog2014-02-25T21:23:06Zhttps://blog.terrible.dev/setting-up-robots-txt-for-your-ghost-powered-blog/<p>Setting up your robots.txt file for your blog is easy, by adding a file called robots.txt in the root of your current themes directory.</p>
<!-- more -->
<p><code>~/blogFolder/content/theme/Casper</code></p>
<p>If you are unfamiliar with linux, to do this simply cd to the directory and run the command <code>sudo vi robots.txt</code> Press i (for insert mode), type your entry (example farther down in this blog), press esc, then type <code>:wq</code> (w stands for write, q stands for quit). Then hit enter</p>
<p>You should probably point sitemap to your rss feed. Most bots (including googlebot) can use the rss feed as a sitemap</p>
<pre><code>
Sitemap: http://yourdomain/rss
User-agent: *
</code></pre>
<p>As a side note, in the robots.txt file you must specify the full URL to your sitemap file.</p>
iPhone or Android (From a guy living with both)2014-02-25T00:29:43Zhttps://blog.terrible.dev/iphone-or-android-from-a-guy-living-with-both/<p>I know, I know the very first question you ask is going to be <em>why do you have two phones</em>, the answer being One is for work, the other is for my personal life. Now that we are done with that subject, we can get on with the review...</p>
<!-- more -->
<h2>Warning: I am a self-Proclaimed Android Fan-boy</h2>
<p>Before I really get into it, I will warn you all that I am apart of the Android User Master Race. Some bias opinion <strong>will</strong> occur.</p>
<h2>What phones?</h2>
<p>I will mostly be reviewing the <a href="http://www.apple.com/iphone-5c/">iPhone 5c</a>, against the <a href="https://play.google.com/store/devices/details/Nexus_5_16GB_White?id=nexus_5_white_16gb&hl=en">Nexus 5</a>.</p>
<h2>What no flashy graphs?</h2>
<p>Unlike most reviews this wont have a bunch of data touting the disk read speeds during mid-day under controlled duress. This is a simple review of my experience with the two devices.</p>
<h2>Build Quality <i class="fa fa-apple"></i></h2>
<h3>iPhone 5c</h3>
<p>The first time I held the 5c, I thought it felt like a kids toy. Although that feeling still lingers with me today, I have noticed since that the quality of the build is fantastic. The buttons feel like they were made to last 1000 years, and the plastic does not feel cheap. I get the feeling it would survive a nasty fall. Although the phone is small, it does not make me wish I had a bigger one. On a side note I was more blown away by the iPhone headphones. These ear buds are actually great value for $30 (free with iPhone). They sound amazing, and they can take a beating. I plug them into my Nexus 5 to make phone calls a lot.</p>
<h3>Nexus 5</h3>
<p>The Nexus 5 features a much bigger screen than the iPhone 5c, but not so large it does not make it harder to handle. The white back looks very nice, and the buttons feel solid. Power button on the side is my preference. My one gripe with it, is when you hold it you don't get the feeling you are holding the greatness of <a href="http://google.com">google</a> in your hand. I'm not sure what hidden element I am talking about, but it feels pretty plain as you hold it. That being said I do feel like I can bend space-time with the phone.</p>
<h2>Operating System <i class="fa fa-android"></i></h2>
<h3>iPhone 5c</h3>
<p>We all know iOS is pretty much amazing to those who love apple. For me I have some gripes.</p>
<ul>
<li>iPhone keyboard always shows capitalized letters, regardless if you are typing lower case or upper case</li>
<li>I wish my home page was not the app tray</li>
<li>The notifications pull down menu is not intuative, and sometimes clicking the close button is unresponsive</li>
</ul>
<h3>Nexus 5</h3>
<p>Android OS is pretty awesome as well but there are some flaws. On a side note I'd like to say that touchwiz and other 3rd party customizations really make Android suck. The one thing that really impresses me about Android is the notifications menu. The menu is clean, and only notifies you on things you care about. If you want widgets, put 'em on the home screen. There is a real seperation of concerns in Android that feels missing in iPhone.</p>
<ul>
<li>Some of the home screen widgets really eat battery life</li>
<li>Some of the older Anroid applications feel out of place on newer devices <em>ie not using the holo theme</em></li>
</ul>
<h2>Finding Applications <i class="fa fa-apple"></i></h2>
<p>I got to give this one to apple. I'm not sure of the Apple stores size, but I felt the store contained better quality apps. The Android app store is really good if you want <a href="https://play.google.com/store/apps/details?id=com.Quotes.ConfuciusQuotes&hl=en">Confucius quotes</a>, apps made in <a href="https://play.google.com/store/apps/details?id=ultimategravatarsync.ultimategravatarsyncfree&hl=en">3 days or less</a>, or apps that show hot asian babes. <a href="http://www.apple.com/">Apple</a> has done a good job at keeping the quality high. I never found an app that had no value to the phone.</p>
<h2>Battery <i class="fa fa-apple"></i></h2>
<p>The iPhones battery is the most impressive part. The Nexus 5 will give me a full day, but will need a charge at the end of the day. The 5c's battery usage is very low. the phone will go all day, and most of the night on one change. The iPhone also charges much faster than the Nexus 5. The one thing that pissed me off, was the Apple charging cable costs $19. I really like Android's use of the universal microUSB.</p>
<h2>Siri vs Google Now <i class="fa fa-android"></i></h2>
<p>I'm not going into to much depth here, but as a user I much prefered Google Now. Although Siri had some nice qualities, I felt like google now was more accurate on searching, and provided better context in my queries. Google Now feels much snappier, and responds only when you need it <em>(ok google)</em>.</p>
<h2>Trend Factor <i class="fa fa-android"></i></h2>
<p>I think apple always use to win this category, however with google wallet and NFC payment I have to give this to the Nexus 5. I have baught many things with my phone, and every time people are amazed. When you are at McDonalds and the only thing standing between you and a big Mac is a simple NFC tap, people think you are gods gift to the earth. One woman asked me out on a date after buying something at the pharmacy (I'm not kidding...it really happend). She was in utter amazement about how suave I was with my phone. Apple has really slipped in years, now more than ever people are interested in Android phones.</p>
<h2>Verdict</h2>
<p><img src="https://blog.terrible.dev/content/images/2014/Feb/115580-1.png" alt="Android Won">
The iPhone, while being a real contender is far from perfect. I have give this to the Nexus 5. That being the case my dream phone would be an iPhone running Android software. I really prefer the software of Android, but retina display, and camera really makes me like the iPhone a lot. My only serious gripe with Android is the quality of the apps. However it does not override the iPhones terrible keyboard.</p>
Providing feedback (without being an asshole)...2014-02-25T00:29:26Zhttps://blog.terrible.dev/providing-feedback-without-being-an-asshole/<p><span style="float: right"><a href="https://blog.terrible.dev/receiving-feedback-without-being-an-asshole/"><i class="fa fa-hand-o-right"></i> Recieving feedback</a></span><br></p>
<p>Giving and receiving feedback, allows us to maintain our strengths while improving our weaknesses. There are two major types of feedback, constructive, and reinforcing. Constructive feedback is asking someone to change behavior, while reinforcing is acknowledging good behavior.</p>
<!-- more -->
<h2>Giving Constructive Feedback</h2>
<p>Constructive feedback is the hardest type of feedback to deliver. This is the feedback where you are asking someone to change their behavior. You may be delivering feedback that is for skill, or behavior change.</p>
<blockquote>
<p>feedback, it is not yelling at someone for 20 minutes, nor is it judging them. Feedback helps improve someones weakness, someones professional relationships, and their stance in the organization.</p>
</blockquote>
<h3>The Delivery</h3>
<p>To start ask the person to talk in private. This gives the conversation some level of privacy, and will make this person less embarrassed. Thank them for sitting down and talking to you. Once the formalities are over, begin paraphrasing the offending behavior.</p>
<blockquote>
<p>Do not pull other people into the conversation. Stating Stacie has this same issue with this person, puts them on the defensive. Give them your perspective only.</p>
</blockquote>
<p>After you have paraphrased the offending behavior from your point of view, give examples of how this behavior affects yourself negatively, and possibly the team. This is the chance to really voice why this behavior needs to stop. Make sure they fully understand your perspectives, and why they are being given this feedback.</p>
<p>Let them respond to your feedback. Fully listen to their explinations, and allow them to ask questions. Their explanation can help bridge you're differences. Toward the end of the conversation provide the person with ways how they can stop, or how they can try to stop. Also let them know what the consequences would be (if any) if they continue to do this behavior. <strong>Always</strong> give this person a chance to talk, as they gave you. Fully acknowledge their perspectives, ask questions about it, and if you disagree let them know why.</p>
<p>Remember this is a person you are talking to. People should still be talked to with dignity, and respect no matter what. This could be a simple misunderstanding, for which you wouldn't want to upset anyone over.</p>
<h2>Giving Reinforcing Feedback</h2>
<p>Reinforcing feedback is the kind of feedback that is easy to deliver. This acknowledges the value that person's behavior brings to the organization.</p>
<h3>The Delivery</h3>
<blockquote>
<p>Be specific in your feedback. Just remember you are reinforcing a positive behavior, not touting how <em>genius</em> they are.</p>
</blockquote>
<p>This kind of feedback can be addressed to both the employee's manager (if that person is not you), and the employee directly. This should start with a summary of what the employee did that was great, how it affected you, and how it could potentially affect others in a positive manor. Don't ever compare the person to another (ie. this guy is amazing as <em>insert employee of the month</em>). Just remember saying <em>hard-worker, always in the office, etc</em> is not constructive to the conversation, and should be avoided.</p>
<h2>Being asked for Feedback by your boss</h2>
<p>Sometimes feedback is asked of you by your boss. This person is coming to you, asking how he/she is doing at his/her job. This is not the time to play suck-up, this is the time to be honest. Provide real feedback using the techniques I have outlined above. Letting them know what they could change is the kind of advise they are looking for.</p>
<h2>Who should I give feedback to?</h2>
<p>Usually it is appropriate for managers to give feedback to subordinates. As long as the culture of your company is not terrible; You should provide feedback to your peers, subordinates, and managers alike. Giving feedback to your boss, allows this person to see things from your perspective, which could be invaluable to someone running a large team. Remember your boss is just as human as you. He/she could be doing the wrong thing over and over again without realizing. Providing him feedback could ultimately improve your working environment, your team, and your companies culture as a whole.</p>
Parsing, and Nesting Models in backbone.js2014-02-24T07:18:51Zhttps://blog.terrible.dev/nested-models-in-backbone-js/<h2>The Parse Function</h2>
<p>The parse function allows you to do some pre-processing of the data sent from the server before the model is created. Parse should return an object containing the values that will make up this models attribues. This is called after the fetch command has recieved the data, but before the response is put into the model. The example below parses dates to local time before adding them to the model using <a href="http://momentjs.com/">moment</a>.</p>
<!-- more -->
<pre class="language-javascript" tabindex="0"><code class="language-javascript">
namespace<span class="token punctuation">.</span>Model <span class="token operator">=</span> Backbone<span class="token punctuation">.</span>Model<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">urlRoot</span><span class="token operator">:</span> <span class="token string">'/api/'</span><span class="token punctuation">,</span>
<span class="token function-variable function">parse</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">response<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">var</span> attr <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
attr<span class="token punctuation">.</span>date <span class="token operator">=</span> <span class="token function">moment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">utc</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>date<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">local</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
attr<span class="token punctuation">.</span>OtherData <span class="token operator">=</span> response<span class="token punctuation">.</span>OtherData
<span class="token keyword">return</span> attr<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Nesting Models (aka model within a model)</h2>
<p>We will use the same parse function as above to create models within this model from data retrieved by the server. You could even loop through an array's keys and values to convert them to a model if need be.</p>
<pre class="language-javascript" tabindex="0"><code class="language-javascript">
namespace<span class="token punctuation">.</span>Model <span class="token operator">=</span> Backbone<span class="token punctuation">.</span>Model<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">urlRoot</span><span class="token operator">:</span> <span class="token string">'/api/'</span><span class="token punctuation">,</span>
<span class="token function-variable function">parse</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">response<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">var</span> attr <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> submodel <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">namespace<span class="token punctuation">.</span>otherModel</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">value1</span><span class="token operator">:</span> response<span class="token punctuation">.</span>subModelArray<span class="token punctuation">.</span>value1<span class="token punctuation">,</span> <span class="token literal-property property">value2</span><span class="token operator">:</span> response<span class="token punctuation">.</span>subModelArray<span class="token punctuation">.</span>value2 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
attr<span class="token punctuation">.</span>SubModel <span class="token operator">=</span> submodel<span class="token punctuation">;</span>
<span class="token keyword">return</span> attr<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
You're doing it wrong (software testing)2014-02-20T10:00:57Zhttps://blog.terrible.dev/softwaretesting/<p>One of the major systems that will stop you from losing money is your testing environment. The ability to properly test patches before they are put into production is a must.</p>
<!-- more -->
<h2>Hardware Symmetry</h2>
<blockquote>
<p>Our test environment does not have nearly the same CPU/Memory that production servers have</p>
</blockquote>
<p>The discrepancy between test and and prod adds unnecessary variables to your testing. Your testing environment needs to be a mirror hardware-wise as your production environment. The ability to accurately test the memory increases, and CPU impact is critical to the success of your code in production.</p>
<p>For instance if you have multiple worker processes in production, that each hold a cache of data and that cache is increased by 2GBb. This may be seen in a non-prod environment as a small increase. However, if your production environment is running 4 times the worker processes as your non prod the small 2GB rise becomes 8GB very quickly.</p>
<p>This large increase in memory usage could destabilize your platform (or not), but the unpredictability of this fact is scary. Tests should be <a href="http://en.wikipedia.org/wiki/Scientific_method">scientific</a>, and a radical difference between the two environments causes unnecessary variables.</p>
<h2>Testing in prod as a last resort</h2>
<blockquote>
<p>We can't test this in test, because our <em>(insert discrepancy of the day)</em> in test is not good enough</p>
</blockquote>
<p>If you suspect that a patch is causing performance problems, but you are unable to fully test it in a non-prod environment. Try to get the right hardware provisioned, or see what can be done for effective testing. The cost of serious performance degradation in production can be far worse than getting the right hardware, or pushing back at other developers.</p>
<p>If you have to test in prod try to patch a few servers and see what happens. Going all the way can also be more costly, then applying something on a few machines and rolling back. Make sure that potentially destructive tests are performed when all teams are in the office. Provide communication, and get everyone involved. If testing in prod requires a pow-wow of 10+ people you will quickly see those kinds of tests end fast.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/Feb/9689481.jpg" alt=""></p>
<h2>Learn from your mistakes</h2>
<blockquote>
<p>Continuous Improvement is not only an improvement of code, but also an evolution of philosophies. ~<a href="https://blog.normmaclennan.com">Norm Maclennan</a></p>
</blockquote>
<p>When problems occur in prod, you sometimes hear why did QA not catch this? When really the question should be, why was this not caught in test. One of the huge differences between these two statements is the first tries to blame a person, while the other constructively finds ways to improve and evolve.</p>
<blockquote>
<p>Everyone in the organization should take ownership of testing, and testing environments. ~ <a href="http://about.tommyparnell.com">Tommy Parnell</a></p>
</blockquote>
<p>This is a huge key to success. Realize that if you write code, you probably write test cases. You should make sure you understand the release process, how code is tested, and how QA performs tests. Making sure QA can accurately test your code will ultimately prove beneficial to both you, your team, and your organization.</p>
<p>##Inconsistent Releases</p>
<p>Releases to test should be performed in the same manor as releases to prod. Any deviation from the documented process should be addressed immediately. Code changes should be managed properly, and scientifically for formal testing to be effective.</p>
<p>Patches should also follow a consistent pattern from one software upgrade to the next. Hearing <em>this patch is going to be weird</em> from a Release Engineer is basically a red flag for <em>this is going to go wrong, but we don't want to take the blame for it</em></p>
Xamarin For Android The Conclusion: (Part 4 of 4)2014-02-18T21:33:54Zhttps://blog.terrible.dev/xamarin-the-conclusion-part-4-of-4/<ul>
<li><a href="https://blog.terrible.dev/xamarin-the-good-the-bad-and-the-ugly/">Part One</a></li>
<li><a href="https://blog.terrible.dev/xamarin-for-android-the-bad-part-2-of-4/">Part Two</a></li>
<li><a href="https://blog.terrible.dev/xamarin-for-android-the-ugly-part-3-of-4/">Part Three</a></li>
<li>Part Four</li>
</ul>
<p>Well verdict is in boys, and girls. Personally, I thought the platform needs to mature more. For those people who can pay for the business edition ($1000 USD/developer), and really prefer c#; then go for it. For most of us that can either do c# or Java; you may want to stick with Java.</p>
<h2>C# vs. Java for Android</h2>
<p>Essentially <a href="http://Xamarin.com">Xamarin</a> is a competing product with using Java. I felt that the hefty price tag, and the lack of free support means the ROI for <a href="http://Xamarin.com">Xamarin</a> will be low.</p>
<blockquote>
<p>If <a href="http://Xamarin.com">Xamarin</a> provided more in the way of automation tools, and documentation; it would be the clear winner</p>
</blockquote>
<p>The fact is going straight to Java for most people is probably a must. Even if you are more comfortable with c#, finding help on the internet is much easier. As the platform matures, and more features are added hopefully things will change.</p>
<h2>License cost deterrent</h2>
<p>One of my biggest gripes with <a href="http://Xamarin.com">Xamarin</a> is the very inflexible <a href="https://store.xamarin.com/">license schemes</a>. You can get by with the $300 indie edition, but it is pretty clear they want people to go the $1000 business edition route.</p>
<blockquote>
<p>The biggest deterrent to the <a href="http://Xamarin.com">Xamarin</a> platform is the high cost of licensing.</p>
</blockquote>
<p>With no sliding scale prices based on organization size, or project scope <a href="http://Xamarin.com">Xamarin</a> is a tough sell <em>(especially for open source projects)</em>.</p>
<h3>Student Discount</h3>
<p>Xamarin, does provide a student discount. They give 90% off for enterprise edition, and for those of you whom go to school this is almost a must buy. You could probably make it back with this simple formula.</p>
<blockquote>
<p>Flappy bird-like animal + Mario pipes + admob = $$$</p>
</blockquote>
<h2>Verdict</h2>
<p>Personally I like <a href="http://Xamarin.com">Xamarin</a> platform. The ability to re-use code for multiple mobile platforms can be helpful. For most of us tinkerers out there <a href="http://developer.android.com/sdk/installing/studio.html">Android Studio</a> is probably enough. For serious businesses, with a major focus on c#; <a href="http://Xamarin.com">Xamarin</a> is probably the prefered method of development.</p>
<h3>Room for improvement</h3>
<p>Before I can fully back <a href="http://Xamarin.com">Xamarin</a> I'd like to see better componants that provide more mobile platform abstraction, increased automation tools (visual studio macros could help here), and better documentation. From the activity of there web pages, I suspect all of these things are coming.</p>
Xamarin For Android The Ugly: (Part 3 of 4)2014-02-18T08:16:17Zhttps://blog.terrible.dev/xamarin-for-android-the-ugly-part-3-of-4/<ul>
<li><a href="https://blog.terrible.dev/xamarin-the-good-the-bad-and-the-ugly/">Part One</a></li>
<li><a href="https://blog.terrible.dev/xamarin-for-android-the-bad-part-2-of-4/">Part Two</a></li>
<li>Part Three</li>
<li><a href="https://blog.terrible.dev/xamarin-the-conclusion-part-4-of-4/">Part Four</a></li>
</ul>
<p>I had some problems with Xamarin. Somethings are ugly, but with plastic surgery almost anything can become beautiful.</p>
<h2>Components</h2>
<p>Xamarin has its own software packages available for download. I tried a lot of them out, some were good others not so much. One of my biggest gripes was that Google Play Services currently has a <a href="http://stackoverflow.com/questions/20125720/xamarin-android-builds-deployments-are-very-slow-how-to-speed-them-up">bug</a> that makes builds <strong>really</strong> slow. Other packages were either genius, or were simply unimpressive. The components have their own package manager, and it does do a decent job of keeping them in order. I have to admit though Xamarin has its own set of componants that do <a href="http://components.xamarin.com/gettingstarted/xamarin.inappbilling">in-app billing</a>, and <a href="http://components.xamarin.com/view/xamarin.mobile">access phone data</a> without having to lift much of a finger.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/Feb/turtle_Alan_Rees.jpg" alt="Moving at the build speed of Play Services"></p>
<h3>Component Documentation</h3>
<p>A real put down is that only some of the components have adequate documentation. For instance for me to get <a href="http://www.google.com/ads/admob/">admob</a> working with play services; I had to look at the Java documentation, and try to figure out how its supposed to be done on Xamarin. This wasn't to difficult, but admob is well used. I would have assumed the documentation would have covered it, but couldn't find anything.</p>
<h2>Visual Studio Designer</h2>
<p>The Visual studio designer for Android at first seemed like the best thing since sliced bread! I was able to get a UI up and running in no time. Making my app work for tablets, and mobile phones alike was simple. However, once in a while it would be stubborn, and stop working. I'm not sure if it was something I was doing, but I felt like it would bomb out and I would have to restore the XAML file to continue.</p>
<p>The editor really isn't great for designing ListViews, working with fragments, or making something that will scale easily. Often it made things exact pixel widths instead of using dots per inch. To keep it short, I still had to do plenty of editing of the source manually (which was not too bad). Making the theme stick on the default view was a pain, until I realized that I could ignore the editor, and decorate my MainActivity with the theme I wanted to use.</p>
<pre>[Activity(Label = "Label", MainLauncher = true, Icon = "@drawable/Icon", Theme = "@android:style/Theme.Holo.Light")]</pre>Xamarin For Android The Bad: (Part 2 of 4)2014-02-18T07:54:43Zhttps://blog.terrible.dev/xamarin-for-android-the-bad-part-2-of-4/<ul>
<li><a href="https://blog.terrible.dev/xamarin-the-good-the-bad-and-the-ugly/">Part One</a></li>
<li>Part Two</li>
<li><a href="https://blog.terrible.dev/xamarin-for-android-the-ugly-part-3-of-4/">Part Three</a></li>
<li><a href="https://blog.terrible.dev/xamarin-the-conclusion-part-4-of-4/">Part Four</a></li>
</ul>
<p><a href="http://xamarin.com/">Xamarin</a> is a very good platform, but like everything it has parts that are not so great.</p>
<h2>Documentation</h2>
<p>One thing that was really hard for me, was to find documentation that was newer than 2012. Android has made great strides with Ice Cream Sandwich, and Jelly Bean. New features such as <a href="http://developer.android.com/guide/components/fragments.html">fragments</a> have breathed life into the platform.</p>
<p>The <a href="http://xamarin.com/">Xamarin</a> documentation provides examples even with the newest features, but there is something about it that feels lacking. Almost like it was thrown together at the last minute. They have been doing webcasts to improve the knowledge out in the wild, but googling the answer to your problem just won't do. Part of the problem is that most developers write in Java, and only bigger companies can afford the <a href="https://store.xamarin.com/">hefty license fees</a> that come with full support.</p>
<p>The user community was helpful at times, but I often found myself wandering though <a href="http://github.com">GitHub</a> hoping my answer could be found in some mystical repo; Eventually having to study the full implementation to find the answer I needed.</p>
<h2>Finding help</h2>
<p>Although <a href="http://xamarin.com">Xamarin</a> has a forum where helpful users help each other, there are not nearly as many people coding on <a href="http://xamarin.com">Xamarin</a> than regular Java. Figuring out how to get something complicated working, was a nightmare. I'd look at a Java implementation, and then try to translate it into its <a href="http://xamarin.com">Xamarin</a> counterpart, which sometimes was far removed than the Java code. There are some examples of <a href="http://xamarin.com">Xamarin</a> for android out there, but nothing that really delves deep into manipulating the inner workings of the phone. I saw this especially when trying to edit contacts programatically. <a href="http://xamarin.com">Xamarin</a> support seemed helpful, but far too expensive for most freelance developers. This was a pretty huge put-off. If I went the Java route my questions would be answered with a simple search of <a href="http://stackoverflow.com">stack overflow</a>.</p>
<h2>Boilerplate</h2>
<p>Like most things Java, Android requires a lot of boilerplate. For a developer like myself, whom avoids Java this was a problem. I would have thought that <a href="http://xamarin.com/">Xamarin</a> would have abstracted out more of the boilerplate than they did. On the one had, having my code look somewhat familiar when I see Java examples was nice, but on the other hand because the API is still different often the Java versions would not be close enough to fully help. My main problem with this, is if I really wanted to write boilerplate I would have used the Java libraries myself. They did make a start for this by generating the manifest file automatically, but I feel it needs to go further to fully mature this platform as a viable alternative to Java.</p>
Xamarin For Android The Good: (Part 1 of 4)2014-02-18T06:58:36Zhttps://blog.terrible.dev/xamarin-the-good-the-bad-and-the-ugly/<h2>Introduction</h2>
<ul>
<li>Part One</li>
<li><a href="https://blog.terrible.dev/xamarin-for-android-the-bad-part-2-of-4/">Part Two</a></li>
<li><a href="https://blog.terrible.dev/xamarin-for-android-the-ugly-part-3-of-4/">Part Three</a></li>
<li><a href="https://blog.terrible.dev/xamarin-the-conclusion-part-4-of-4/">Part Four</a></li>
</ul>
<p>This will be a series of blog entries where I discuss the Xamarin platform for Android.</p>
<p>I really enjoy C# programming language <em>(JavaScript second)</em>....Linq, Generics, anonymous methods, and Visual Studio are just some of the reasons I like it. <a href="http://xamarin.com/">Xamarin</a> is a platform that gives you the ability you to write Android applications in c#.</p>
<p>When I heard about <a href="http://xamarin.com/">Xamarin</a> I naturally, wanted to give it a shot. Having tried Eclipse, and Android Studio for android development I was no idiot when it came to the platform. So I got a license, and did nothing with it for six months, until a few weeks ago. After only 3 days I created <a href="https://play.google.com/store/apps/details?id=ultimategravatarsync.ultimategravatarsyncfree">Ultimate Gravatar Sync</a>. An app that sync's your contacts gravatar images to their picture in your phone.</p>
<h2>C# with no compromise</h2>
<p>The <a href="http://xamarin.com/">Xamarin</a> platform uses mono, and some kind of voodoo bindings to the Java libraries to make it work. I wont go in depth, but the native features of the C# language are there to use. I never felt like my hands had been tied, that all of a sudden I couldn't use a library that is normally part of the <a href="http://msdn.microsoft.com/en-us/library/yf1d93sz(v=vs.110).aspx">GAC</a> (Global Assembly Cache). When I needed multi-threading, System.Threading was there, and when I needed to use C# Generics I had no issues implementing them.</p>
<p><img src="https://blog.terrible.dev/content/images/2014/Feb/architecture1.png" alt="Xamarin execution"></p>
<h2>Manage Android Manifest files</h2>
<p>One of the things that blew me away about the platform, was that I never had to add anything to my manifest file. For those of you whom don't know, Android requires an XML config detailing the permissions you require, and the classes you have in your application.</p>
<p>Simple decoration such as:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Activity</span><span class="token attribute-arguments"><span class="token punctuation">(</span>Label <span class="token operator">=</span> <span class="token string">"Label"</span><span class="token punctuation">,</span> MainLauncher <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> Icon <span class="token operator">=</span> <span class="token string">"@drawable/Icon"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span></code></pre>
<p>Will Generate in your manifest file as:</p>
<pre class="language-xml" tabindex="0"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>pre</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>activity</span>
<span class="token attr-name"><span class="token namespace">android:</span>label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Label<span class="token punctuation">"</span></span>
<span class="token attr-name"><span class="token namespace">android:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.logoActivity<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>intent-filter</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>action</span> <span class="token attr-name"><span class="token namespace">android:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>android.intent.action.MAIN<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>category</span> <span class="token attr-name"><span class="token namespace">android:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>android.intent.category.LAUNCHER<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>intent-filter</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>activity</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>pre</span><span class="token punctuation">></span></span></code></pre>
<p>Adding permissions is also easy:</p>
<pre class="language-csharp" tabindex="0"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token target keyword">assembly</span><span class="token punctuation">:</span> <span class="token class-name">UsesPermission</span><span class="token attribute-arguments"><span class="token punctuation">(</span>Android<span class="token punctuation">.</span>Manifest<span class="token punctuation">.</span>Permission<span class="token punctuation">.</span>Internet<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span></code></pre>
<h2>Using Java Libraries</h2>
<p><a href="http://xamarin.com/">Xamarin</a> provides some kind of crazy visual studio project, that will essentially provide c# bindings to Java libraries you require. To bind Simply create a Java Binding project, adding the .Jar files, and then build. Watch the magic happen. They do <a href="http://docs.xamarin.com/guides/android/advanced_topics/java_integration_overview/binding_a_java_library_(.jar)/">note</a> that you sometimes need to do some configuration for certain libraries, however I had no issues with the one I tried. On top of that if you really needed to, you could access the <a href="http://docs.xamarin.com/guides/android/advanced_topics/java_integration_overview/working_with_jni/">Java Native Interface</a> for even more power.</p>
You're doing it wrong! (Recruiter Edition)2014-02-17T06:08:28Zhttps://blog.terrible.dev/youre-doing-it-wrong-recruiter-edition/<p>Recruiting, I am sure is a tough job (I wouldn't actually know), but often being on the other end I see pitfalls that a lot of recruiters fall into. So for all of you recruiters, please do not do these things.</p>
<!-- more -->
<h3>The Linkedin Summary</h3>
<p>We all know that a major way to find candidates is through social media, the top one is <a href="http://linkedin.com">Linkedin</a>. Linkedin allows you to instantly find candidates that have the skills you are looking for.</p>
<p>In Linkedin the summary is really a place for a person to express who they are, where they would like to be in 5 years, and how they wish to get there. This is usually a good place where people leave information for recruiters.</p>
<p>If you find a candidate with qualifications that are suitable, spend the 5 minutes to read their summary. Their summary could include information that will help in your efforts to recruit this person. Showing that you spent the few minutes to read their summary in your initial contact message will go far. Ignoring their summary will most certainly be your recruitment downfall.</p>
<h3>The Problem</h3>
<p>At the end of the day, a developer wants to solve a problem. Developers want to solve interesting problems, or problems which not many people can solve. Sending an email saying <em>hey im looking for xyz candidate with experience in ruby</em> will probably not get much attention.</p>
<p>Think for a moment about why you are hiring someone. You hire people, because your company has a problem, and that problem needs to be solved.</p>
<p>Sending an email stating a problem you have, and why you need this person to help solve it, will ultimately prove better than a list of standard qualifications necessary for the position.</p>
<p>Ultimately you should try to get them excited to work at your company. Free beer, and pizza is not a recruiting tool, just a way to disguise what could be a poor environment to work in.</p>
<h3>First Contact</h3>
<p><img src="https://blog.terrible.dev/content/images/2014/Feb/968full_star_trek__first_contact_screenshot.jpg" alt="First Contact"></p>
<h4>Do</h4>
<ul>
<li>Address the candidate with the name they have listed on websites/resumes</li>
<li>Present clearly what you are looking for, and what you are not looking for</li>
<li>Ask them what their future goals are</li>
<li>Ask them if they know anyone whom would be interested (if they are not)</li>
<li>Tell them why your company is worth working for. Be honest, provide stories from your own experiences</li>
<li>Be honest about the job, they will leave if they find out it was not what you said it was</li>
</ul>
<h4>Don'ts</h4>
<ul>
<li>Assume their name is a nickname (ex. addressing someone named Dave, as David)</li>
<li>Contact someone asking for qualifications that are clearly not listed on their resume</li>
<li>Being unprepared during an interview (phone or otherwise)</li>
<li>Sell them your company with offers of free gifts (both before, and during employment)</li>
</ul>
<p>...and if they turn you down, be polite. Leave a lasting impression. You only get one shot to show your organizations value. Even if they turn you down, they may refer others to you.</p>
...A blog about technology, how original(not)!2014-02-16T22:13:57Zhttps://blog.terrible.dev/-a-blog-about-technology-how-originalnot/<h4>Introduction (who am I?)</h4>
<p>Hello, Tommy here. I work at <a href="http://vistaprint.com">vistaprint</a>. I spend most of my time monitoring a website, writing internal tools, and doing things some would consider "Devops".</p>
<p>I'm not very qualified as a blogger, quite frankly my English skills are terrible.</p>
<p>My perspective is not very unique at this point. The industry is full of developer/sysadmin employees, and devops has become an industry movement. This movement has created in my opinion a 'trendy effect' to what some would consider little more than a buzz word.</p>
<!-- more -->
<h4>DevOps the modern exorcist?</h4>
<p>Many years ago the catholic church would perform exorcisms on people whom they deemed to be possessed by the devil. The people who would do these works, were not high up in the ranks of the church. However the work they did both mysterious, and possibly dangerous is at the same time totally enticing. This lead to the popularization of what we see now as an exorcist.</p>
<p>Currently DevOps is starting to take on the same popularity. The chance to tackle a problem such as proper monitoring, task automation, etc. really seems sexy to other developers. Having to work on the same website, or the same payments system every day, becomes tedious. However, coming into the office and tackling real infrastructure problems, at break neck speed is very desirable for traditional developers. People must understand, that DevOps personnel are not far superior than sysadmin/developer/qa, but simply tackling 3 jobs at the same time.</p>
<h4>Technology today, and Service Oriented Arch.</h4>
<p>Currently, the industry is making the transition from traditional monolithic infrastructures, to a more services based world. If you are working at an indie start-up, or a big company that really planned ahead, you are probably thinking <strong>that I am blogging in the past</strong>. We have all heard the <a href="https://engineering.groupon.com/2013/node-js/geekon-i-tier/">success stories </a>, however with each success there are 5 failures you didn't know about (90% of statistics made up), and some companies are starting to feel the pains of moving both culturally, and technologically to a service world. The obvious problem is that the <strong>traditional way of doing things cannot continue</strong>, but the movement of change can kill an organization just as fast.</p>
<h4>So what makes you so qualified to talk on these topics?</h4>
<p>Nothing really, most of this blog will be ranting about things I dislike, or pointing out not so interesting things about Computers. I'm not much of a business leader, and unfortunatly for the readers of this blog I am one of those sysadmin's whom thinks they can code. I hope some of you find my perspective useful, and feel free to leave comments at will.</p>