tag:blogger.com,1999:blog-228250202024-03-07T09:22:53.284+00:00Golden NuggetsNuggets of technical information for .Net developersJoel Hammond-Turnerhttp://www.blogger.com/profile/10684302883494591548noreply@blogger.comBlogger169125tag:blogger.com,1999:blog-22825020.post-28265921865314477612020-06-11T09:22:00.001+01:002020-06-11T09:23:19.089+01:00Thursday Quickie: Fixing NCrunch for Azure Functions<font face="arial">So I'm a big fan of <a href="https://www.ncrunch.net/">NCrunch</a> - <a href="https://twitter.com/remcomulder">Remco Mulder</a>'s continuous testing plug-in for Visual Studio.</font><div><font face="arial"><br /></font></div><div><font face="arial">I'm not a true adherent to TDD, so I find it really helps in ensuring that you've got proper coverage of my code, particularly of conditionals, and pushes me to write more tests generally. All good.</font></div><div><font face="arial"><br /></font></div><div><font face="arial">But it doesn't (yet) support Azure Functions projects properly - the post-build oddities of Functions project just don't play well with NCrunch.</font></div><div><font face="arial"><br /></font></div><div><font face="arial">However, there's a pretty easy fix that seems to work the majority of the time.</font></div><div><font face="arial"><br /></font></div><div><font face="arial">Just add the following to the Azure Function project .csproj file:</font></div><div><font face="arial"><br /></font></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><div style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, "Courier New", Courier, monospace; font-size: 14px; white-space: pre;"><pre><PropertyGroup Condition="'$(NCrunch)' == '1'"> </pre></div></div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><div style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, "Courier New", Courier, monospace; font-size: 14px; white-space: pre;"><pre><span> </span><ExcludeRestorePackageImports>true</ExcludeRestorePackageImports></pre></div></div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><div style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, "Courier New", Courier, monospace; font-size: 14px; white-space: pre;"><pre></PropertyGroup></pre></div></div></blockquote><div><font face="arial"><br /></font></div><div><font face="arial">Pretty simple. </font></div><div><font face="arial"><br /></font></div><div><font face="arial">Thanks have to go to Clement on the <a href="https://forum.ncrunch.net/yaf_postsm14507_Azure-Function---build-issue.aspx#post14507">NCrunch Forums</a> for this fix.</font></div><div><font face="arial"><br /></font></div><div><font face="arial"><br /></font></div><div><br /></div><div><br /></div><div><br /></div>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-4043074373977433092019-10-22T09:19:00.001+01:002019-11-05T12:03:33.863+00:00Tuesday Quickie: ILogger in Azure Functions done right<span style="font-family: "arial" , "helvetica" , sans-serif;">So we had a discussion at work yesterday about how to use </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ILogger</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> from <b>Microsoft.Extensions.Logging</b> in our <b>Azure Functions v2</b> projects.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">All the samples have a hang-over from the v1 days where the function method takes an </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ILogger</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> as a method dependency. I asserted that a cleaner way would be to have </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ILogger</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> as a class-level dependency, injected via the constructor.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The only problem was that it didn't work - the <b>MSDI</b> wasn't resolving </span><b style="font-family: "Courier New", Courier, monospace;">ILogger</b><span style="font-family: "arial" , "helvetica" , sans-serif;"> when constructing our functions class.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="color: blue;">namespace</span> MyFunctionApp</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">{</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">public class</span> <span style="color: #3d85c6;">MyFunctionClass</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">private readonly</span> <span style="color: #3d85c6;">ILogger</span> logger;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: #38761d;">// DOESN'T WORK!</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">public</span> <span style="color: #3d85c6;">MyFunctionClass</span>(<span style="color: #3d85c6;">ILogger</span> logger)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">this</span>.logger = logger;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> [<span style="color: #3d85c6;">FunctionName</span>(<span style="color: #cc0000;">"MyFunctionName"</span>)]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">public async</span> <span style="color: #3d85c6;">Task</span><<span style="color: #3d85c6;">IActionResult</span>> MyFunctionMethod(</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> [<span style="color: #3d85c6;">HttpTrigger</span>(<span style="color: #3d85c6;">AuthorizationLevel</span>.Anonymous, <span style="color: #cc0000;">"get"</span>, <span style="color: #cc0000;">"post"</span>, Route = null)]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: #3d85c6;">HttpRequest</span> req,</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: #3d85c6;">ILogger</span> log) <span style="color: #38761d;">// WORKS!</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ...</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">A bit of a proof-of-concept later and I found the trick - use </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ILogger<T></b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> as the constructor dependency</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> - where </span><span style="font-family: "courier new" , "courier" , monospace;"><b>T</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> is the class that owns the method.</span><span style="font-family: "arial" , "helvetica" , sans-serif;">!</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="color: blue;"> public class</span> <span style="color: #3d85c6;">MyFunctionClass</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">private readonly</span> <span style="color: #3d85c6;">ILogger</span> logger;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: #38761d;">// WORKS!</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">public</span> <span style="color: #3d85c6;">MyFunctionClass</span>(<span style="color: #3d85c6;">ILogger</span><<span style="color: #3d85c6;">MyFunctionClass</span>> logger)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">this</span>.logger = logger;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ...</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">But why? </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">What's going on is that the <b>Azure Functions v2</b> runtime sets up the DI to serve an </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ILogger</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> when method-injection is used, but not for constructor injection. For constructor injection the runtime has set the DI to serve up only </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ILogger<T></b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">.</span><br />
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">Looking at the differences between the loggers that the two DI methods return, we can actually make sense of why the behaviours are different.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The </span><b style="font-family: "Courier New", Courier, monospace;">ILogger</b><span style="font-family: "arial" , "helvetica" , sans-serif;"> returned for method injection is configured with the category "</span><span style="font-family: "courier new" , "courier" , monospace;"><i>Function.MyFunctionName.User</i></span><span style="font-family: "arial" , "helvetica" , sans-serif;">".</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ILogger<T></b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> returned for constructor injection, however, gets a category of "</span><span style="font-family: "courier new" , "courier" , monospace;"><i>MyFunctionApp.MyFunctionClass</i></span><span style="font-family: "arial" , "helvetica" , sans-serif;">" instead. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The <b>Azure Functions v2</b> runtime is building a logger based on the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>FunctionName</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> attribute for method injection - it's a special case hangover from v1!</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">So to get hold of an </span><b style="font-family: "Courier New", Courier, monospace;">ILogger</b><span style="font-family: "arial" , "helvetica" , sans-serif;"> in your function class using constructor injection, you just need to ask for an </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ILogger<MyClass></b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> instead! </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Seemples!</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Update - 2019-11-05:</span></h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">So I missed out a rather important part of this post... the pattern above is lovely, but it <u><i>doesn't work</i></u>! </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">None of the logging to <b style="font-family: "courier new", courier, monospace;">ILogger<MyClass></b> instances appear in Application Insights - but logging from the <b>Azure Functions v2</b> runtime itself does.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Actually the problem isn't the pattern above at all, but another nasty little <b>Azure Functions v1</b> hangover that Microsoft hasn't fixed yet.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">By default, the <b>Azure Functions v2</b> runtime filters out any logging that's not from the runtime itself, or from </span><span style="font-family: Courier New, Courier, monospace;"><b>ILogger</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> instances that the runtime provides (with the <span style="font-family: "arial" , "helvetica" , sans-serif;">"</span><span style="font-family: "courier new" , "courier" , monospace;"><i>Function.MyFunctionName.User</i></span><span style="font-family: "arial" , "helvetica" , sans-serif;">"</span> style category).<br /><br />The fix is easy - but irritating. Add logging configuration to your </span><span style="font-family: Courier New, Courier, monospace;"><b>host.json</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> file, thus:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"></span><br />
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: 1.45; margin-bottom: 16px; overflow-wrap: normal; overflow: auto; padding: 16px;"><code style="background: initial; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;">{
"version": "2.0",
"logging": {
"logLevel": {
"MyFunctionApp": "Trace"
}
}
}</code></pre>
<span style="font-family: "arial" , "helvetica" , sans-serif;">There's an issue that was openned on GitHub in April 2019 about this ( </span><a href="https://github.com/Azure/azure-functions-host/issues/4345" style="font-family: arial, helvetica, sans-serif;">https://github.com/Azure/azure-functions-host/issues/4345</a><span style="font-family: arial, helvetica, sans-serif;"> ), so I assume Microsoft will get around to removing the filtering at some point.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-14851479811600814312019-05-16T11:07:00.001+01:002019-05-16T11:08:53.431+01:00Thursday Quickie: IoC Registrations done wrong broke my DbContext<hr />
<div style="text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: large;"><b><u>TLDR</u>: Using InjectionConstructors in Unity can give you singletons. Beware! (and TEST!)</b></span></div>
<hr />
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">So our tester at work spotted some </span><span style="font-family: "courier new" , "courier" , monospace;"><b>InvalidOperationExceptions</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> being logged from our data access library recently indicative of a </span><span style="font-family: "courier new" , "courier" , monospace;"><b>DbContext</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> being re-used across requests... </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Digging into the registration showed quite a few instance of this sort of code:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #3d85c6;">container</span>.<span style="color: #bf9000;">RegisterType</span><<span style="color: #0b5394;">IService</span>, <span style="color: #0b5394;">ServiceImplementation</span>>(</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">new</span> <span style="color: #0b5394;">TransientLifetimeManager</span>(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">new</span> <span style="color: #0b5394;">InjectionConstructor</span>(<span style="color: blue;">new</span> <span style="color: #0b5394;">Dependency</span>()));</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Spot the mistake?</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Passing an </span><span style="font-family: "courier new" , "courier" , monospace;"><b>InjectionConstructor</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> into </span><span style="font-family: "courier new" , "courier" , monospace;"><b>RegisterType</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> to specify which constructor on the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ServiceImplementation</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> class to use is fine... </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Except that passing </span><span style="font-family: "courier new" , "courier" , monospace;"><b>new Dependency()</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> to the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>InjectionConstructor</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> <i><u>does not</u></i> indicate that a new instance of the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>Dependency</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> type should be created for each resolution of </span><span style="font-family: "courier new" , "courier" , monospace;"><b>IService</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">... instead it creates a <i><u>singleton instance </u></i>there and then that's subsequently shared across <i><u>all</u></i> instances of the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>IService</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">. Which is bad.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Of course, for </span><span style="font-family: "courier new" , "courier" , monospace;"><b>DBContext</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> dependencies this is particularly bad - and is the source of the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>InvalidOperationException</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> that was detected. </span><span style="font-family: "arial" , "helvetica" , sans-serif;">It's an easy mistake to make, but one that's really hard to spot until you see those exceptions being logged.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The solution - use </span><span style="font-family: "courier new" , "courier" , monospace;"><b>InjectionConstructor</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> as it's intended:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="color: #3d85c6;">container</span>.<span style="color: #bf9000;">RegisterType</span><<span style="color: #0b5394;">IService</span>, <span style="color: #0b5394;">ServiceImplementation</span>>(</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">new</span> <span style="color: #0b5394;">TransientLifetimeManager</span>(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="color: blue;">new</span> <span style="color: #0b5394;">InjectionConstructor</span>(</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <span style="background-color: yellow;"><span style="color: blue;">new</span> <span style="color: #0b5394;">ResolvedParameter</span><<span style="color: #0b5394;">Dependency</span>>()</span>));</span><br />
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">The </span><span style="font-family: "courier new" , "courier" , monospace;"><b>ResolvedParameter</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> clause says clearly that you're letting the container decide on the lifetime of Dependency.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">For bonus points - and to prevent regressions - write tests that verify both that your composition root / container bootstrapper registers types with the correct lifetimes, and that where you've got </span><span style="font-family: "courier new" , "courier" , monospace;"><b>DBContexts</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> involved that you get a separate </span><span style="font-family: "courier new" , "courier" , monospace;"><b>DBContext</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> instance when you resolve two instances of </span><span style="font-family: "courier new" , "courier" , monospace;"><b>IService</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Whilst the above is specific to the Unity IoC framework, you can be sure that all IoC frameworks will have a similar gotcha - so watch out for your registrations!</span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-87784997770761582952019-04-09T09:12:00.000+01:002019-04-09T09:12:30.432+01:00Tuesday Quickie: When closure bites (or how not to configure Newtonsoft.Json)<hr />
<blockquote class="tr_bq">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><b>TLDR</b>: Be very careful using captured closures and anonymous methods - they can leak memory when you don't expect. Also copy-and-paste code is <i>bad</i>.</span></blockquote>
<hr />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span><span style="font-family: "arial" , "helvetica" , sans-serif;">So yesterday we had an issue where a long-running service within our platform suddenly started throwing </span><span style="font-family: "courier new" , "courier" , monospace;"><b>StackOverflowExceptions</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> with a new version. It was a blocker to the next release, so inevitably I got tasked with fixing the issue.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">A quick profile of a locally running copy replicated the error (phew!) and pointed to one of our HTTP based service clients being at fault. This was confusing, as those components hadn't changed. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">But what had changed was how those clients were being used - previously, they had accidentally been injected from the IoC container as singletons - now they were being injected as transients.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">So why would the stack overflow?</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">It turns out that the service clients all had copy-and-paste code used to ensure that a custom JSON converter was added to the default </span><span style="font-family: "courier new" , "courier" , monospace;"><b>JSONSerializerSettings</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> used by the <b><i>Newtonsoft JSON</i></b> library, and that code was leaking memory and ultimately causing the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>StackOverflowException</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">But how? </span><span style="font-family: "arial" , "helvetica" , sans-serif;">Here's the old code:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<script src="https://gist.github.com/Rammesses/f93570a7f5a3ca534f5bd844b1361402.js"></script>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Pretty straightforward - and a static method in a static class shouldn't leak?</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div style="text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-size: x-large;"><b><i><u>WRONG</u></i></b></span>!</span></div>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span><span style="font-family: "arial" , "helvetica" , sans-serif;">On lines <i><u>8</u></i> and <i><u>9</u></i> we're capturing a closure (</span><span style="font-family: "courier new" , "courier" , monospace;"><b>defaultSettings</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">) and then using that within an anonymous method that we're assigning back to </span><span style="font-family: "courier new" , "courier" , monospace;"><b>J</b></span><span style="font-family: "courier new" , "courier" , monospace;"><b>sonConvert.DefaultSettings</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Because of the captured closure, the compiler couldn't make the anonymous method truly static - so you get a new instance every time the helper method is called - and those instances are pinned (again because of the captured closure) so that they can't be garbage collected.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Since this helper was being called every time a service client was being instantiated, and the clients were no longer singletons, the profile was showing tens of thousands of instances in memory of </span><span style="font-family: "courier new" , "courier" , monospace;"><b>Func<JsonSerializerSettings></b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">. Not good.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The solution is to be rather more defensive in adding the converter. Here's the corrected version:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<script src="https://gist.github.com/Rammesses/2a7125d3490604360563b6414db37102.js"></script>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">We create our own default </span><span style="font-family: Courier New, Courier, monospace;"><b>JsonSerializerSettings</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> instance and a genuinely static </span><span style="font-family: Courier New, Courier, monospace;"><b>Func<JsonSerializerSettings></b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> helper method on lines <i><u>7</u></i> & <i><u>8</u></i>.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span><span style="font-family: "arial" , "helvetica" , sans-serif;">If </span><span style="font-family: Courier New, Courier, monospace;"><b>JsonConvert.DefaultSettings</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> is null, we assign that helper (within a double-checked lock for safety) on line </span><span style="font-family: Courier New, Courier, monospace;"><i><u>18</u></i></span><span style="font-family: "arial" , "helvetica" , sans-serif;">.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Finally, we use whatever helper factory was assigned to get the default </span><span style="font-family: Courier New, Courier, monospace;"><b>JsonSerializerSettings</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> instance (line <u><i>23</i></u>) and add our converter if needed - again within a double-checked lock (line <i><u>32</u></i>).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Re-running the repro resulted in exactly 1 instance of </span><span style="font-family: Courier New, Courier, monospace;"><b>Func<JsonSerializerSettings></b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> being created - and our bug is fixed.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The moral of the story? Watch out for anonymous methods and captured closures - they can bite! </span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com1tag:blogger.com,1999:blog-22825020.post-68613354934998311852019-03-22T10:26:00.001+00:002019-03-22T10:26:27.082+00:00Friday Quickie: Fixing Kubernetes connectivity with Docker for Windows<span style="font-family: Arial, Helvetica, sans-serif;">Another aide-memoire - when using kubectl on Windows against Docker for Windows you get the following error:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<blockquote class="tr_bq">
<span style="background-color: white; color: #24292e; font-size: 14px;"><span style="font-family: Courier New, Courier, monospace;"><b>Unable to connect to the server: dial tcp [::1]:8080: connectex: No connection could be made because the target machine actively refused it.</b></span></span></blockquote>
<span style="background-color: white; color: #24292e; font-size: 14px;"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white;">This</span><span style="background-color: white; color: #24292e; font-size: 14px;"> might well just just be that the tool can't find it's config... and the fix is easy - just s</span></span><span style="background-color: white; color: #24292e; font-family: Arial, Helvetica, sans-serif; font-size: 14px;">et an environment variable:</span><br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #24292e; font-size: 14px;"><span style="font-family: Courier New, Courier, monospace;"><b>KUBECONFIG=c:\users\joel\.kube\config</b></span></span></blockquote>
<span style="color: #24292e; font-family: Arial, Helvetica, sans-serif;"><span style="background-color: white; font-size: 14px;">Restart your powershell instance and try again... Simple. </span></span><span style="background-color: white; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;">(see also </span><a href="https://github.com/kubernetes/kubernetes/issues/53881" style="font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;" target="_blank">this issue in github</a><span style="background-color: white; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;">)</span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-64688044178626108642019-02-14T12:34:00.002+00:002019-02-14T12:34:36.751+00:00Thursday Quickie: When AssemblyBinding redirect doesn't... and how I fixed it<hr />
<blockquote class="tr_bq">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><b>TLDR</b>: If your </span><span style="font-family: "courier new" , "courier" , monospace;"><b>csproj</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> file has </span><span style="font-family: "courier new" , "courier" , monospace;"><b>AutoGenerateBindingRedirects</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> set to </span><b><span style="font-family: "courier new" , "courier" , monospace;">true</span></b><span style="font-family: "arial" , "helvetica" , sans-serif;">, then you <b><i><u>MUST</u></i></b> include the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>xmlns</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> on the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>assemblyBinding</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> node for any custom binding redirects in </span><span style="font-family: "courier new" , "courier" , monospace;"><b>app.config</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">.</span></blockquote>
<hr />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">So I've been banging my head against the wall trying to get a piece of code delivered over the last few days, and kept hitting an issue where code runs perfectly locally, but when deployed to the target server was failing with the dreaded error</span><br />
<blockquote class="tr_bq">
<span style="background-color: #f3fdfe; color: #757575; font-family: "roboto" , sans-serif; font-size: 15px;">Could not load file or assembly 'System.Net.Http, Version=4.1.1.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)</span></blockquote>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">I'd used <a href="http://gertjanvanmontfoort.blogspot.com/2017/11/systemnethttp-dll-version-problems.html" target="_blank">Gertjan van Montfoort's excellent article</a> as a guide, but whatever version of the NuGet package I installed, and whatever version I referenced in my binding redirects in app.config, it just would not fire up.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Looking at the </span><b><span style="font-family: "courier new" , "courier" , monospace;">Fusion</span></b><span style="font-family: "arial" , "helvetica" , sans-serif;"> logs (helped by </span><a href="https://www.hanselman.com/blog/BackToBasicsUsingFusionLogViewerToDebugObscureLoaderErrors.aspx" style="font-family: Arial, Helvetica, sans-serif;" target="_blank">Scott Hanselman's article</a><span style="font-family: "arial" , "helvetica" , sans-serif;">) I could see that my app was initially loading </span><span style="font-family: "courier new" , "courier" , monospace;"><b>System.Net.Http</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> from the GAC for a </span><span style="font-family: "courier new" , "courier" , monospace;"><b>4.0.0.0</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> reference, then successfully loaded </span><span style="font-family: "courier new" , "courier" , monospace;"><b>4.1.1.3</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> from the app directory (the one from the NuGet package I referenced).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">But when it was trying to load </span><span style="font-family: "courier new" , "courier" , monospace;">4.1.1.2</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> because of other dependencies </span><span style="font-family: "courier new" , "courier" , monospace;"><b>Fusion</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> was not honouring the binding redirect, and so the app was failing on startup.</span><br />
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">Finally I found a comment on the net that hinted about case sensitivity within the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>app config</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">, so I went looking for differences between my custom redirects and those generated on build into </span><span style="font-family: "courier new" , "courier" , monospace;"><b>MyApp.exe.config</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">And I found one - the generated redirects all have an </span><span style="font-family: "courier new" , "courier" , monospace;"><b>xmlns</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> attribute on the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>assemblyBinding</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> node - and my custom one <b><i><u>did not</u></i></b>. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The solution - add one in your app.config</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"><?</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">xml</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">version</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">=</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">1.0</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">encoding</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">=</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">utf-8</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">?></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"><</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">configuration</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> <</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">runtime</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> <</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">assemblyBinding</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </span><span style="background-color: yellow;"><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">xmlns</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">=</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">urn:schemas-microsoft-com:asm.v1</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span></span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> <</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">dependentAssembly</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> <</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">assemblyIdentity</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">name</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">=</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">System.Net.Http</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">publicKeyToken</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">=</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">b03f5f7f11d50a3a</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">culture</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">=</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">neutral</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"><span class="Apple-converted-space"> </span>/></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> <</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">bindingRedirect</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">oldVersion</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">=</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">0.0.0.0-4.2.0.0</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </span><span style="color: red; font-family: "consolas"; font-size: 9.5pt;">newVersion</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">=</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">4.1.1.2</span><span style="font-family: "consolas"; font-size: 9.5pt;">"</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"><span class="Apple-converted-space"> </span>/></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">dependentAssembly</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">assemblyBinding</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"> </</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">runtime</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">></span><span style="font-family: "consolas"; font-size: 9.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="caret-color: rgb(0, 0, 0); font-family: Calibri, sans-serif; font-size: 11pt; margin: 0cm 0cm 0.0001pt; text-size-adjust: auto;">
<span style="color: blue; font-family: "consolas"; font-size: 9.5pt;"></</span><span style="color: #a31515; font-family: "consolas"; font-size: 9.5pt;">configuration</span><span style="color: blue; font-family: "consolas"; font-size: 9.5pt;">></span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Now your binding redirects get merged with the generated ones and it all works.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">My interpretation is that <b>Fusion</b> appears to honour the redirects in </span><span style="font-family: "courier new" , "courier" , monospace;"><b>assemblyBinding</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> nodes only if <b><i><u>all</u></i></b> have </span><span style="font-family: "courier new" , "courier" , monospace;"><b>xmlns</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> attributes or <b><i><u>none</u></i></b> have them - but not if mixed. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Hopefully others will find this useful - now I can get on and do some actual work!</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-69931236103284267902018-06-06T16:28:00.002+01:002018-06-06T16:28:12.602+01:00Honey, I shrunk `ConfigureServices()`<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
The problem with all DI systems is that configuration generally is pulled in two polar-opposite directions. Either your container is configured by convention (with a few rare exception cases), or it's configured directly and declaratively with <em style="box-sizing: border-box;">masses</em> of registrations.</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
The latter configuration practice has the benefit of not having any side-effects as you bring in third party libraries - you'll not get random <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">Controller</code> classes added to your system, for example. And this is why it's my preference.</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
BUT, declaring every dependency in your container can lead to the dreaded "God Configuration Method" - where one method has hundreds of lines of container registration. This bad - it couples your application tightly to all dependencies at all levels, and makes it hard to maintain.</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
For the last few years, I've been using a discovery system for Unity that moves the registrations for dependencies away from the "God Configuration Method" and into individual "Bootstrappers" that live alongside the implementation of the service that they register.</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
This "magic" discovery pattern works well - reducing the "God Configuration Method" to a single line - and allowing (for example) client libraries to define the "right" lifecycles themselves, not relying on a programmer getting it right each time they use the client.</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
Today, I'm releasing an experiment - a port of "magic" bootstrapper discovery for ASPNet Core and the Microsoft DI framework.</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
It might be useful - it's certainly simple enough to use. The experiment is to see what sort of take-up it gets.<br />
<br />
Note: I added the "magic" extensions under the <span style="font-family: Courier New, Courier, monospace;"><b>Microsoft.Extensions.DependencyInjection.Discovery</b></span> namespace deliberately.</div>
<h2 style="border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;">
Usage</h2>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
Using the discovery library is simple. First install the NuGet package:</div>
<div class="highlight highlight-source-powershell" style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">install-package</span> CheviotConsulting.DependencyInjection.Discovery</pre>
</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
Next, where previously you would add registrations into the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">Startup.ConfigureServices(...)</code> method, you write a <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">IServiceDiscoveryBootstrapper</code> implementation</div>
<div class="highlight highlight-source-cs" style="box-sizing: border-box; font-size: 16px; margin-bottom: 16px;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-size: 13.6px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">using </span><span class="pl-k" style="box-sizing: border-box; color: #6f42c1;">Microsoft.Extensions.DependencyInjection;
</span><span class="pl-k" style="box-sizing: border-box;"><span style="color: #6f42c1;">
</span><span style="color: #d73a49;">public</span></span><span style="color: #24292e;"> </span><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">sealed</span><span style="color: #24292e;"> </span><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">class</span><span style="color: #24292e;"> </span><span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">WebAppServiceBootstrapper</span><span style="color: #24292e;"> : </span><span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IServiceDiscoveryBootstrapper
</span> {
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">public</span><span style="color: #24292e;"> </span><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">void</span><span style="color: #24292e;"> </span><span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">ConfigureServices</span><span style="color: #24292e;">(</span><span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IServiceCollection</span><span style="color: #24292e;"> </span><span class="pl-smi" style="box-sizing: border-box; color: #24292e;">services</span><span style="color: #24292e;">)
</span> {
<span class="pl-smi" style="box-sizing: border-box; color: #24292e;">services</span><span style="color: #24292e;">.</span><span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">AddTransient</span><span style="color: #24292e;"><</span><span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IWebAppService</span><span style="color: #24292e;">, </span><span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">MyWebAppService</span><span style="color: #24292e;">>();
</span> }
}</pre>
</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
You can have as many of these as you like, in as many referenced projects as you like - which allows you to put a service registration alongside a service or service client itself.</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
Then in the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">Startup.ConfigureServices(...)</code> method, you add the following single line:</div>
<div class="highlight highlight-source-cs" style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">using</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">Microsoft</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">Extensions</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">DependencyInjection</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">Discovery</span>;
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">public</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">class</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">Startup</span>
{
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> This method gets called by the runtime. Use this method to add services to the container.</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">public</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">void</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">ConfigureServices</span>(<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IServiceCollection</span> <span class="pl-smi" style="box-sizing: border-box;">services</span>)
{
...
<span class="pl-smi" style="box-sizing: border-box;">services</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">BootstrapByDiscovery</span>();
}</pre>
</div>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
And that's it. The discovery framework will load any assemblies referenced by your application, find all <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">IServiceDiscoveryBootstrapper</code> instances and execute the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">ConfigureServices(...)</code> method on each in turn - bootstrapping the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">IServiceCollection</code> used by <span style="box-sizing: border-box; font-weight: 600;">ASPNet Core</span> / <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">Microsoft.Extensions.DependencyInjection</code>.</div>
<h2 style="border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;">
Advanced Usage</h2>
<h3 style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Bootstrapper Dependencies</h3>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
Unlike the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">Startup.ConfigureServices</code> method, you can't pass dependencies in the method parameters. However, by default the bootstrapper classes themselves are resolved using the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">IServiceCollection</code> as it stands just before the call to <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">BootstrapByDiscovery()</code> is made. So you can use constructor dependency injection in your bootstrapper.</div>
<div class="highlight highlight-source-cs" style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">public</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">sealed</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">class</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">SampleServicesBootstrapper</span> : <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IServiceDiscoveryBootstrapper</span>
{
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">private</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">readonly</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IHttpContextAccessor</span> <span class="pl-smi" style="box-sizing: border-box;">contextAccessor</span>;
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">public</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">SampleServicesBootstrapper</span>(<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IHttpContextAccessor</span> <span class="pl-smi" style="box-sizing: border-box;">contextAccessor</span>)
{
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">this</span>.<span class="pl-smi" style="box-sizing: border-box;">contextAccessor</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">=</span> <span class="pl-smi" style="box-sizing: border-box;">contextAccessor</span>;
}
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">public</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">void</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">ConfigureServices</span>(<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IServiceCollection</span> <span class="pl-smi" style="box-sizing: border-box;">services</span>)
{
<span class="pl-smi" style="box-sizing: border-box;">services</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">AddSingleton</span><<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">MyCustomService</span>>(<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">new</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">MyCustomService</span>(<span class="pl-smi" style="box-sizing: border-box;">contextAccessor</span>));
}
}</pre>
</div>
<h3 style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Manual Bootstrapping</h3>
<div style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
If you don't want to rely on the "magic" discovery, you can always bootstrap each of your bootstrappers individually within your <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">Startup.ConfigureServices(...)</code> method.</div>
<div class="highlight highlight-source-cs" style="box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">public</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">class</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">Startup</span>
{
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> This method gets called by the runtime. Use this method to add services to the container.</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">public</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">void</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">ConfigureServices</span>(<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">IServiceCollection</span> <span class="pl-smi" style="box-sizing: border-box;">services</span>)
{
...
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> Bootstrap services manually</span>
<span class="pl-smi" style="box-sizing: border-box;">services</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">BootstrapFrom</span><<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">SampleServicesBootstrapper</span>>();
<span class="pl-smi" style="box-sizing: border-box;">services</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">BootstrapFrom</span>(<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">new</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">WebAppServiceBootstrapper</span>());
}
}</pre>
</div>
Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com5tag:blogger.com,1999:blog-22825020.post-21159120433537144172018-04-24T10:15:00.000+01:002018-04-25T09:44:11.538+01:00DDDSW 2018 - Retrospective<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEKvFtu7uSXKl8kZSMr0wXqYaPJUsNzAHRGM8wKb78PKMYnIxxi5d9NguDrFjbaH3YZXVGOyGEFunj6goDM2-_ulvKCO-FmoBRo0g0FmdM_1tENc-ajFxz-sY7eFMARYyLOe6yKw/s1600/dddsw_no_year.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="236" data-original-width="471" height="100" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEKvFtu7uSXKl8kZSMr0wXqYaPJUsNzAHRGM8wKb78PKMYnIxxi5d9NguDrFjbaH3YZXVGOyGEFunj6goDM2-_ulvKCO-FmoBRo0g0FmdM_1tENc-ajFxz-sY7eFMARYyLOe6yKw/s200/dddsw_no_year.png" width="200" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">So it's now the Monday after the Saturday before and I've had time to chill and think back on the excellent event that was DDDSW 2018.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Held in the Redcliffe Sixth Form Centre again, my day started early as I was driving down and back in the day. Fortunately the M4 was clear and in spite of the roadworks around Bristol Temple Meads, I rolled into the car park just after 0830.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzVW81pMOCb4JdjCa_VeKvkQoTrTvQtWoUhVGAehCb6E9fUUO6g_r86yPac02AxvYXI77wgWc8W7SO5rKqiDwOp3JJDwpkMsbQc-zeMl0kw-wcMq0bkry6aYnJiWGjMcR_1KNUUA/s1600/IMG_0093.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzVW81pMOCb4JdjCa_VeKvkQoTrTvQtWoUhVGAehCb6E9fUUO6g_r86yPac02AxvYXI77wgWc8W7SO5rKqiDwOp3JJDwpkMsbQc-zeMl0kw-wcMq0bkry6aYnJiWGjMcR_1KNUUA/s320/IMG_0093.JPG" width="240" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">Once again, Landmark was sponsoring the Cream Teas, so I was able to bag a sponsors parking space behind the building (thanks Ross) and get the goodies in via the back door.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Setting up the Landmark stand-up and handing the box full of goodies for the delegate bags took but moments, and then it was up to the Speaker Room to do a quick run-through and check connectivity via my phone. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">I was scheduled for Track 5 just before lunch, so I would have had plenty of time to prepare had I needed it - as it was I could chat and catch up with old friends.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Speaker Briefing was followed by the usual intro and housekeeping talk in the main room. It was really good to see a strong turnout again too, right from the start</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWgW_5OrTo_S32NZHxO5jbSt5NyST4Gb9UAAV2SmD-4tC9DOZHEINOjRItW4J2cz7dSrmfZD1bGXjHhaO5vHHNgrwHzv2-_5z28XT5scXzxIQ60AJGMVhXUibIGm3RbekVEv1b_A/s1600/IMG_0096.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="1600" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWgW_5OrTo_S32NZHxO5jbSt5NyST4Gb9UAAV2SmD-4tC9DOZHEINOjRItW4J2cz7dSrmfZD1bGXjHhaO5vHHNgrwHzv2-_5z28XT5scXzxIQ60AJGMVhXUibIGm3RbekVEv1b_A/s400/IMG_0096.jpg" width="400" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">With these over, it was off to the sessions - and first up was one that was really just for me with no real bearing on my day-to-day job (tho' I've got a few ideas now).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Session 1 - <a href="https://dddsouthwest.com/proposed-talks/66" target="_blank">Unity 101 with Andy Clarke</a></span></h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">I was interested with this as I'd played a little with <a href="https://unity3d.com/" target="_blank">Unity 3d</a> already, but hadn't really got past attaching standard behaviours to pre-fabs. Andy started simply with an intro to the product (used for everything from simple 3d games up to <a href="https://unity.com/madewith/adam" target="_blank">Neill Blomkamp's "Adam" series</a> of shorts. He then gave a quick once over of </span><span style="font-family: "arial" , "helvetica" , sans-serif;">UI (and the left-hand-coordinate-system), and soon had balls rolling and boxes bouncing off each other as they spun.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDd1RuzMgCAdENHwGSnNqbiECaTNSI-B2a4ak6XS7ihyphenhyphenNjCUolvtcJy1UVQmgleuB1ewnx6-Sm7i97sKG7f0l8U77uINSl1YNoP7vHSmbFLrRgeKcRHWO5FaLk4MSLiSmLJOXLpA/s1600/IMG_0098.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDd1RuzMgCAdENHwGSnNqbiECaTNSI-B2a4ak6XS7ihyphenhyphenNjCUolvtcJy1UVQmgleuB1ewnx6-Sm7i97sKG7f0l8U77uINSl1YNoP7vHSmbFLrRgeKcRHWO5FaLk4MSLiSmLJOXLpA/s320/IMG_0098.jpg" width="240" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">Next up was "Tank Dominoes", using pre-fabs from the Unity Store to indulge in a bit of monolith-toppling. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">With a tank. 😁 </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">It was only a shame that Andy's laptop refused to play the sound effect of the explosion.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Then Andy demonstrated the Inverse Kinematic Skeleton system available with a humanoid model.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">By the end he had a two-player networked sample running where the characters could pass a batton between each other. The amount of code required - or rather the lack of it - is a real testament to what a powerful authoring environment Unity is.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Thoroughly enjoyable, Andy's talk will give me a good head-start against my 11 year old who wants to try Unity himself for game development (Scratch is so Junior School, apparently).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Session 2 - <a href="https://dddsouthwest.com/proposed-talks/83" target="_blank">"Give it a REST - Tips for designing and consuming public APIs" with Liam Westley</a></span></h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">You've got to give it to Liam - a day or so before DDDSW he'd been knocked off his bike (and had possibly broken a bone in his wrist), but that didn't stop him giving a polished presentation on the good, the bad and the ugly sides of public facing APIs.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQC2oDSmqxxG7QbgtXbLoR39pS2IgB3yHGR-YEzI7wtoW0r1uabgCqn1wF5voWY9TzMN31S_EsUgfI-uPpQIIQ3dsGyEfd0ZdbG-YRKG27069PUqgmBnMKh9go3OClG5U3jqrKrg/s1600/IMG_0100.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="413" data-original-width="1600" height="101" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQC2oDSmqxxG7QbgtXbLoR39pS2IgB3yHGR-YEzI7wtoW0r1uabgCqn1wF5voWY9TzMN31S_EsUgfI-uPpQIIQ3dsGyEfd0ZdbG-YRKG27069PUqgmBnMKh9go3OClG5U3jqrKrg/s400/IMG_0100.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Liam explaining (with video) his cycling accident</td></tr>
</tbody></table>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Liam started by describing some of the history and development of <b>REST</b>ful best practice - and how <b>HATEOAS </b>was a crucial upcoming technology. <b>REST</b> is <i><u>not</u></i> <b>CRUD</b>, and <b>HATEOAS</b> is a <b>REST </b><u><i>constraint</i></u>, not an independent thing.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">He described how Google ReCaptcha was exceptionally clever when deprecating service versions by using canary deployments to show a message designed to get users to prod web site owners to upgrade.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8uumxqx8d8c0LwZ9I9xMTovoVlkyoA7qtyyRx8i8Pq7OgrPuGv_Zg476kHXMLp6Vfth1SyL844bE6rAWwf9I-eReLVfsFqN3n0qeC04YgIzlpC-7TJYqgoq8dD0LJipAoLGMfpQ/s1600/IMG_0102.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1201" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8uumxqx8d8c0LwZ9I9xMTovoVlkyoA7qtyyRx8i8Pq7OgrPuGv_Zg476kHXMLp6Vfth1SyL844bE6rAWwf9I-eReLVfsFqN3n0qeC04YgIzlpC-7TJYqgoq8dD0LJipAoLGMfpQ/s320/IMG_0102.jpg" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Versioning came under the microscope - here be dragons - as did effective patterns for genuinely asynchrons operations using <b>HTTP 202 Accepted</b> and a <b>HATEOAS </b>response payload.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Liam finally explained how a public API is effectively a contract between owner and user, and needs to be handled as such if you don't want to hack your users off.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Lots of good stuff to take back to work here, although I'm not sure I captured it all in my "sketchy" notes.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Next up was my own talk.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Session 3 - <a href="https://dddsouthwest.com/proposed-talks/106" target="_blank">Azure in Action: CosmosDB, Functions and ServiceBus in perfect harmony</a></span></h3>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">I'd had a humbling experience submitting this year - not one, but two talks accepted for DDDSW, with absolutely identical numbers of votes! I could only do one, so </span><span style="font-family: "arial" , "helvetica" , sans-serif;">I'd decided to do my Azure talk rather than the soft-skills one.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Paraphrasing my own blurb, there's so many parts
to Azure, it's sometimes hard to decide what to use and when. Do I use
TableStore or CosmosDB? Would BlobStore be better? Should I host a full-fat
.Net service in a VM, or stand up an ASP.Net Core WebApi? What about functions?
The choices are myriad. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2q_Pg_hxwiOSZZPdl00EMbwW-85wsgQglFTIztTaAQ6SFikZoDtlQAIM8XuGcYEreKSEepZFob4MEDoQamw0mkVgQgNC9JJz3p_flPXvvL41h7YcGKR0kiR5DhNpdhz6iJq3NKw/s1600/IMG_0104.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" data-original-height="711" data-original-width="1600" height="142" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2q_Pg_hxwiOSZZPdl00EMbwW-85wsgQglFTIztTaAQ6SFikZoDtlQAIM8XuGcYEreKSEepZFob4MEDoQamw0mkVgQgNC9JJz3p_flPXvvL41h7YcGKR0kiR5DhNpdhz6iJq3NKw/s320/IMG_0104.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Speaker's Eye View</td></tr>
</tbody></table>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">I described how at Landmark we made these kind of decisions as we implemented some
new features in our product. I talked about the questions you need to ask to
make those decisions, where we went wrong, and how we succeeded in the end. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Finally I described in
detail how we used CosmosDB, Azure Functions and Service Bus together to
provide a Compliance Audit trail feature that would scale properly, work
reliably, be trivial to use, and that wouldn't break the bank, using a complete end-to-end sample code-base, lifted-and-shifted from the code we wrote at Landmark.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr4UTezC6iGImBKN0IAjcMnBMNIkL6ftMBK8A6WI-sTYSd8Yy7CFV5ke9DY_e-Jb6r_gQCCo3uwz1Abjqo4GxmXNHNV1p7cX9uztnUscA1tMEnPqfEOgQV5ySOscAjQnwCcRU2uw/s1600/IMG_0115.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="953" data-original-width="1338" height="227" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr4UTezC6iGImBKN0IAjcMnBMNIkL6ftMBK8A6WI-sTYSd8Yy7CFV5ke9DY_e-Jb6r_gQCCo3uwz1Abjqo4GxmXNHNV1p7cX9uztnUscA1tMEnPqfEOgQV5ySOscAjQnwCcRU2uw/s320/IMG_0115.JPG" width="320" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">For a first outing, I'm really pleased with how this went - the slides gave the background and context I wanted, and the code demos pretty much all worked perfectly. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Certainly the questions asked by the audience and the feedback I've received has been great. Thanks all.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">It's been great to have such support from Landmark too - allowing me to effectively open-sourcing our Compliance Audit framework as the reference implementation to go along with this talk.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Once again, <a href="https://twitter.com/IJohnson_TNF" target="_blank">Ian Johnson</a> captured the essence in one of his legendary sketchnotes - thanks, Ian!</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">For the curious, <a href="http://bit.ly/CloudAuditDeck" target="_blank">the slides</a> and code are all available online:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div style="text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><a href="http://bit.ly/CloudAuditRepo">https://github.com/JoelHT-Landmark/CloudAudit</a></span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoXer1Bpszw879kxVYn0m6RCIx-z2BVxspBi0VzJsOPlUapWjdawrbJr1H_2CYMH3hD9twAjBXV_Pbrdg4-EaBGSh90hSyIHapGTGkV9LcelrHj9nHJyVDDpo5Arkafp2ovj86Fw/s1600/IMG_0105.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoXer1Bpszw879kxVYn0m6RCIx-z2BVxspBi0VzJsOPlUapWjdawrbJr1H_2CYMH3hD9twAjBXV_Pbrdg4-EaBGSh90hSyIHapGTGkV9LcelrHj9nHJyVDDpo5Arkafp2ovj86Fw/s200/IMG_0105.jpg" width="200" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">After the obligatory pastie lunch (sponsored by Dyson this year), punctuated with interesting conversations as always, it was on to the next session:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Session 4 - <a href="https://dddsouthwest.com/proposed-talks/71" target="_blank">"What's That Smell" with Anthony Dang</a></span></h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiktfyt7TSm-916V02_v0eyvFWfvHLPP5K8MRwQPlhrogbDDWT80vm1yzaih0o65kET-ERFY-0d7K40vP8z-vlSDxtNA_qOh8vIizBvCOdVJY5j5vNKcC3PgIJVkXl2waR89f-pQ/s1600/IMG_0106.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiktfyt7TSm-916V02_v0eyvFWfvHLPP5K8MRwQPlhrogbDDWT80vm1yzaih0o65kET-ERFY-0d7K40vP8z-vlSDxtNA_qOh8vIizBvCOdVJY5j5vNKcC3PgIJVkXl2waR89f-pQ/s200/IMG_0106.JPG" width="200" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><a href="https://twitter.com/anthonydotnet" target="_blank">Anthony</a>'s session was an entertaining review of a series of "gotcha's" he's experienced in a Digital Agency environment, specifically when taking on other people's projects. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Whilst focused a little on Umbraco (<a href="https://thecogworks.com/" target="_blank">The CogWorks</a> is an Umbraco Gold Partner), his advice is applicable to anyone scratching their head about web application performance.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">One thing that jumped out at me was his suggestion that the simple act of turning off all caching can actually improve performance, and certainly show up the real underlying issues. It's all to easy as a developer to over-use (or over-engineer) caching in your application and bring in all sorts of un-testable issues.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh-u9U8W-fQvyYhTaA2mw-Uenw-Tdij-YUA51P2SVaopy2f9jK8XtgT1zV10nqFozcBBrm_4XLX84xbInp52f-u3zSxdMeTwewAo1rK9UXOoxPQAQqw1cjAe1YVh6_604NwKtbzg/s1600/IMG_0108.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh-u9U8W-fQvyYhTaA2mw-Uenw-Tdij-YUA51P2SVaopy2f9jK8XtgT1zV10nqFozcBBrm_4XLX84xbInp52f-u3zSxdMeTwewAo1rK9UXOoxPQAQqw1cjAe1YVh6_604NwKtbzg/s200/IMG_0108.jpg" width="150" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Another break, more coffee, more chat and most importantly the Cream Teas (sponsored by Landmark). </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">I was good and only had a couple. Really.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Then it was time for</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Session 5 - <a href="https://dddsouthwest.com/proposed-talks/87" target="_blank">"Lessions learned - ingesting, processing and securing 200 million messages / day" with Jess Panni</a></span></h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCz_n3jXMlF8f0ufPxpukkA1EEBTf3HH8b-qv95CvYgd2YIKXnzUuSrunRkpKkJAAB3qfDHdqH74jYuxLH68hqu_8dT5ulIph327cxOJbyFqM2wG2kU1N7oHTIvt92iZ9PznMhBw/s1600/IMG_0111.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCz_n3jXMlF8f0ufPxpukkA1EEBTf3HH8b-qv95CvYgd2YIKXnzUuSrunRkpKkJAAB3qfDHdqH74jYuxLH68hqu_8dT5ulIph327cxOJbyFqM2wG2kU1N7oHTIvt92iZ9PznMhBw/s320/IMG_0111.jpg" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">This was probably the talk most relevant to my day-to-day job, and boy did Jess deliver.</span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span><span style="font-family: "arial" , "helvetica" , sans-serif;">Jess described how Endjin ingest Radius data via a UDP-listener service, and pipe this to Azure Data Lake via Functions. He described the "Swiss Cheese" model of providing more and more security along the pipeline, how Shared Access Signature Tokens provide better security than Shared Access Policies (at the expense of somewhat more complicated code flows), particularly when used with Key Vault.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Jess also demonstrated how a "2-key launch control" could be implemented for software - requiring two independent operators to start an update to a system.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Finally, he showed how Azure Data Lake Analytics are used to process the 200 million events into useful data points for reporting and monitoring using uSQL.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">All in all, a really interesting - and very fast paced - talk to finish up the day before the final wrap up and swag.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBeSlGgt_AnJfRGXLHtVYbQ5hPmbnnSJXsfjJWOk76NjbtlAQvfAA-8EJ3oUdYkqgnHwNoFgkDfNF4nt8pyuA7aX9gpeXmNhOGRhrns3keg2EOJ9r7BBYRLrm6ZRDEq5MaI97BcA/s1600/IMG_0114+%25281%2529.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="522" data-original-width="1600" height="130" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBeSlGgt_AnJfRGXLHtVYbQ5hPmbnnSJXsfjJWOk76NjbtlAQvfAA-8EJ3oUdYkqgnHwNoFgkDfNF4nt8pyuA7aX9gpeXmNhOGRhrns3keg2EOJ9r7BBYRLrm6ZRDEq5MaI97BcA/s400/IMG_0114+%25281%2529.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Wrap up and swag</td></tr>
</tbody></table>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Afterwards, it was off to Just Eat towers for more chat over beer and pizza - although I had to forgo both as I was driving home. 😞</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">All credit has to go to the DDDSW team - another excellent event this year - and to all the attendees and speakers who made it a great day.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-52044099395363049732017-11-17T12:16:00.001+00:002017-11-17T12:16:31.918+00:00Meetup: Leaders in Tech, Reading<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJQt5Q2NynYIodseINe9A9e82i3ElrY9iBYzklU-QnKhyphenhyphenhCQAIihaWGP4_7goOy1Nub1Qk_-YvZhUElpmeYUiYflZI0wXoTqPbI4a1kdTw9yufDvzM2rD0wh-SLABi1eQXbxomow/s1600/IMG_0551.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJQt5Q2NynYIodseINe9A9e82i3ElrY9iBYzklU-QnKhyphenhyphenhCQAIihaWGP4_7goOy1Nub1Qk_-YvZhUElpmeYUiYflZI0wXoTqPbI4a1kdTw9yufDvzM2rD0wh-SLABi1eQXbxomow/s200/IMG_0551.JPG" width="150" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Last night, I had the pleasure of attending the <a href="https://www.meetup.com/Leaders-in-Tech-Reading/events/243269011/" target="_blank">inaugural Meetup</a> of "<a href="https://www.meetup.com/Leaders-in-Tech-Reading/" target="_blank">Leaders in Tech: Reading</a>" at <a href="https://www.meetup.com/pro/austin-fraser/" target="_blank">Austin Fraser</a>'s offices in central Reading.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "arial" , "helvetica" , sans-serif;">Billed as a group "<span style="background-color: #f6f7f8; color: #2e3e48; font-family: "graphik meetup" , "helvetica" , "arial" , sans-serif; font-size: 16px;">for CTOs, CIOs, VPs, Heads of IT and other senior technology leaders to get together and discuss current tech trends", this first event was a </span></span><span style="font-family: "arial" , "helvetica" , sans-serif;">20 minute whistle-stop tour by <a href="https://www.linkedin.com/in/andy-smith-776665/" target="_blank">Andy Smith</a> on the "What, Why & How of Whole Enterprise Agility".</span></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "arial" , "helvetica" , sans-serif;">Preparing <a href="https://www.austinfraser.com/en/blog-leaders-in-tech-reading-enterprise-agility/" target="_blank">a blog post interviewing the speaker</a> prior to the event was genius - giving an insight into what to expect that the event.</span></span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEwBeEnAwYovvmAQw7AIt8Jys0j_5KVlMDD9mEqmTGY4n77jCb5sV_ajBosKpRYfqCun09qSKOb4it03GZhMwVuk_6HeBo0Yu_aEsmXPXI4iJbHQCXwZTXJATQBJKNSTqBvMkUBA/s1600/IMG_0547.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEwBeEnAwYovvmAQw7AIt8Jys0j_5KVlMDD9mEqmTGY4n77jCb5sV_ajBosKpRYfqCun09qSKOb4it03GZhMwVuk_6HeBo0Yu_aEsmXPXI4iJbHQCXwZTXJATQBJKNSTqBvMkUBA/s200/IMG_0547.JPG" width="200" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The central Reading venue works perfectly for me (and many others, based on conversations I had) - just a short bus trip from work and handy for the station for that late train home.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Greeted in the impressive lobby of Thames Tower, we were guided up to the 11th floor offices of Austin Fraser, where drinks and hors d'oevres awaited with the opportunity to meet the other attendees before the event.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Unlike I've experienced at some of these sort of events, the hosts made a great effort to engage the attendees before the presentation - getting conversations started so that everyone was comfortable and the "wall-flower" effect was minimised.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicZkZQokBSKYiD9yOomwRzj3foiUAk3hc44olmz2VUcyhxO7-ML2u6H3uNSsqK6JuVG-hAly-nlF-gX6LGAgS-aR9AzotDJa-ml4E-zSYLLLKNPJEvAraijpKrfRTVVcVeXhKVmA/s1600/IMG_0549.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicZkZQokBSKYiD9yOomwRzj3foiUAk3hc44olmz2VUcyhxO7-ML2u6H3uNSsqK6JuVG-hAly-nlF-gX6LGAgS-aR9AzotDJa-ml4E-zSYLLLKNPJEvAraijpKrfRTVVcVeXhKVmA/s200/IMG_0549.JPG" width="150" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The presentation itself was held in the break-out area between the foosball tables and the putting green, underneath a hanging garden (I kid you not). Austin Frasier have clearly taken to heart the need to provide a work environment that will appeal.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Andy started with a little history, comparing enterprise organisation in the 20th Century (slow, regulated, competitive) with what's emerged in the 21st - fast, distruptive, collaborative enterprises, where millennials demand a vibrant working environment whilst expecting to move at least 4 times before they're half way through their 30's.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">He discussed the "Elastic Band of Culture" - and how unless agile transformation is invoked across an entire organisation, then those business functions not involved will only be a drag on those others.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">There were so many things to take away from Andy's talk, but it could all be distilled into one soundbite:</span><br />
<blockquote class="tr_bq" style="text-align: center;">
<hr />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><i><b>"Organisational Agile is a change in the mindset and culture</b></i></span> </blockquote>
<blockquote class="tr_bq" style="text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><i><b><u>for a whole organisation</u>."</b></i></span><br />
<hr />
</blockquote>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIq_sjVKW-zW_qkCOPGgccuNOtTZTTOByJM7QlnnpeKG7I2PEkr6GKbSm7fEywvqLILpsC0uKGS3LNrwT2UBpGOMaQ0hoFYK4kTTDoXkfADmSh9p_HN5mXoT3CEytvdEB6AaGeDw/s1600/IMG_0550.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIq_sjVKW-zW_qkCOPGgccuNOtTZTTOByJM7QlnnpeKG7I2PEkr6GKbSm7fEywvqLILpsC0uKGS3LNrwT2UBpGOMaQ0hoFYK4kTTDoXkfADmSh9p_HN5mXoT3CEytvdEB6AaGeDw/s320/IMG_0550.JPG" width="320" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">After the presentation, the Q&A session turned into an excellent round-table discussion of the issues raised - lots of interaction with and contribution from the attendees that lasted longer than the presentation itself.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Finally, more networking and casual discussion (as well as more drinks and nibbles) rounded the evening off.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">All credit has to go to the Austin Fraser team for hosting this event and making it a success - I'm going to be going again. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-50429017554422128832017-11-09T09:55:00.000+00:002017-11-09T09:55:32.587+00:00The 6 Step Happy Path to HTTPS on Amazon S3 and Cloudfront<span style="font-family: "arial" , "helvetica" , sans-serif;"><a href="https://twitter.com/troyhunt" target="_blank">Troy Hunt</a> <a href="https://www.troyhunt.com/life-is-about-to-get-harder-for-websites-without-https/" target="_blank">called it back in July</a>, and now the HTTPS tipping point is here. From Chrome 62 onwards, sites are going to be flagged as <b><i><u>dangerous</u></i></b> if they don't have strong security in place. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">If you haven't already, read his article now - I'll wait.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div style="text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><a href="https://www.troyhunt.com/life-is-about-to-get-harder-for-websites-without-https/" target="_blank">Life is about to get a whole lot harder for websites without HTTPS</a></span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Of course it doesn't have to be hard to implement - Troy has himself blogged on the "<a href="https://www.troyhunt.com/the-6-step-happy-path-to-https/" target="_blank">The 6-Step 'Happy Path' to HTTPS</a>" - but I'm hosting my websites out of <a href="https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjp_-bO3q7XAhXRzKQKHXgxBm0QFgg_MAA&url=https%3A%2F%2Faws.amazon.com%2F&usg=AOvVaw10TqNx6EBJNugFGyuTZwOa">Amazon AWS</a>, so my "6-step 'Happy Path' to HTTPS on Amazon S3 and Cloudfront" is a little different.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Step 1 - Get a free certificate</span></h2>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Difficulty level: Easy</span></h4>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">So whilst I can't use LetsEncrypt, Amazon gives us the tools to add a custom SSL certificate to my Cloudfront distribution.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Go to the AWS Console and the <a href="https://console.aws.amazon.com/cloudfront/home" target="_blank">Cloudfront Management module</a>.</span><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyw_WrLkGkkZ606pbgTjHYCy1l8eoec-irV0Ve4uBrltI_3S7nDb6X5aWzZxApUs0tlspsq83EwWJ5sYD7pTaL0Qbm_iLZI6h1TYdeHo3MIXoNczyoky4oRYrgo77QhXJKY_eb4g/s1600/Cloudfront_SSL_Settings.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="766" data-original-width="1322" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyw_WrLkGkkZ606pbgTjHYCy1l8eoec-irV0Ve4uBrltI_3S7nDb6X5aWzZxApUs0tlspsq83EwWJ5sYD7pTaL0Qbm_iLZI6h1TYdeHo3MIXoNczyoky4oRYrgo77QhXJKY_eb4g/s320/Cloudfront_SSL_Settings.png" width="320" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">Select the distribution for your website, and click on "Edit" on the General tab. Amongst all the setting, you get the options shown right for selecting what certificate to use.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">We want a custom SSL certificate, and all we have to do is click on "Request or Import a Certificate with ACM" to start the request process in a new window / tab</span><br />
<blockquote class="tr_bq">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><b>NOTE</b><i>: You </i><b style="font-style: italic;"><u>must</u></b><i> have your AWS console configured for the N. Virginia region when going through the certificate request process. Whilst this should happen automatically, it didn't always for me. YMMV.</i></span></blockquote>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiKy-EKKzx8SeRqpgm2w_ucVhR21Zty8KP0pp8Dl0d3WUDH5lhe4DJHdkhZwKeUcMQhDNVMYIjA5JJdtdsOepZsOQNyEZ6F0vBnL5CQBh3pfixzcbVDGjDsGq9PX52HuVXQo_irA/s1600/AWS+Cert+Process.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="997" data-original-width="1600" height="199" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiKy-EKKzx8SeRqpgm2w_ucVhR21Zty8KP0pp8Dl0d3WUDH5lhe4DJHdkhZwKeUcMQhDNVMYIjA5JJdtdsOepZsOQNyEZ6F0vBnL5CQBh3pfixzcbVDGjDsGq9PX52HuVXQo_irA/s320/AWS+Cert+Process.png" width="320" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">Working through the ACM wizard to get a certificate is simple enough that I'll not detail it here - but remember to add both the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>www.mydomain.com</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> entry and the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>*.mydomain.com</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> wildcard if you've got sub-domains.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">When your cert has been created and validated, go back to the Cloudfront distribution page and hit the refresh button beside the certificate drop-down. Your shiny new certificate should be shown, so select it and save changes.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">When the distribution has updated, you'll now be able to access your website using https and the ACM certificate.</span><br />
<br />
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Step 2 - Add a 301 "Permanent Redirect"</span></h2>
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Difficulty level: Easy</span></h4>
<span style="font-family: "arial" , "helvetica" , sans-serif;">This step is all about telling browsers to always use HTTPS - and Cloudfront has you covered here too.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Select the distribution for your website in the </span><a href="https://console.aws.amazon.com/cloudfront/home" style="font-family: Arial, Helvetica, sans-serif;" target="_blank">Cloudfront Management module</a><span style="font-family: "arial" , "helvetica" , sans-serif;"> again and this time choose the "<i>Behaviours</i>" tab. I had only a single default behavior, you may have more - if so</span><span style="font-family: "arial" , "helvetica" , sans-serif;">, then you'll need to make the following change for each.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Check the checkbox and click on the "Edit" button to edit the behaviour. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYqALB0z5Z-CCMxvppIN8BbnglduSjTmeHWOJhQvq83RMd8CXrtSteBiD1LW3X-iuw8WATlsYX7SvyfwWAnaGqXwH6xxPlLJd_ksfon901Bpesnr8OTBX07AAzAp9EGgYmIj86GA/s1600/Behaviour+Viewer+Protocol+Policy+Settings.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="146" data-original-width="1188" height="39" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYqALB0z5Z-CCMxvppIN8BbnglduSjTmeHWOJhQvq83RMd8CXrtSteBiD1LW3X-iuw8WATlsYX7SvyfwWAnaGqXwH6xxPlLJd_ksfon901Bpesnr8OTBX07AAzAp9EGgYmIj86GA/s320/Behaviour+Viewer+Protocol+Policy+Settings.png" width="320" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">The setting we're interested in is "<i>Viewer Protocol Policy</i>" (shown right). </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Set this to "Redirect HTTP to HTTPS" and click on the save button (which is helpfully labelled "<b><i>Yes, Edit</i></b>") at the bottom - when the distribution finishes updating y</span><span style="font-family: "arial" , "helvetica" , sans-serif;">our website will now redirect HTTP requests to HTTPS.</span><br />
<br />
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Step 3 - Add HSTS</span></h2>
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Difficulty level: Medium-Hard</span></h4>
<span style="font-family: "arial" , "helvetica" , sans-serif;">This step is actually the meat of this blog post. Serving your website out of S3 and CloudFront may be cheap, but you don't get all the self-serve features offered by CloudFlare for adding standard security headers.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">But all is not lost - we can use AWS Lambda to post-process all responses as they leave CloudFlare.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">First, open the <a href="https://console.aws.amazon.com/lambda/home?region=us-east-1#/" target="_blank">Lambda Management module</a> (ensuring you're in the N. Virginia region).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAwywr-XciXLMQHebmlOzmxfBEzlQPDTC5NrPmji40ZlmgyzQSZvpYzEbI9KgRd4Yz7IsH57NSLZz4Z87q8-N2UmePZHaCAnBdku8ScxV3upTJ4l31S8gpH7uwReX0NM1kT6LciA/s1600/Create+Lambda.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="464" data-original-width="1492" height="99" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAwywr-XciXLMQHebmlOzmxfBEzlQPDTC5NrPmji40ZlmgyzQSZvpYzEbI9KgRd4Yz7IsH57NSLZz4Z87q8-N2UmePZHaCAnBdku8ScxV3upTJ4l31S8gpH7uwReX0NM1kT6LciA/s320/Create+Lambda.png" width="320" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">We need to create a new function for each website you're serving from S3 / CloudFront - I've got 3 websites, and have completed this exercise on 2 so far as you can see right.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO1_sbJquMFqCezWLQebDAqTeoP0tPSQMI2uz0_ALiyLAmEKSmr4zVscJzcsUgeDWWwr8JmAV993WEr_XvYiIaIQGkhxJa9KaawYNclI_INW-k1Xh72MbVqnS5eZfg_tUZo-12aQ/s1600/Lambda+Blueprints.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="589" data-original-width="1600" height="117" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO1_sbJquMFqCezWLQebDAqTeoP0tPSQMI2uz0_ALiyLAmEKSmr4zVscJzcsUgeDWWwr8JmAV993WEr_XvYiIaIQGkhxJa9KaawYNclI_INW-k1Xh72MbVqnS5eZfg_tUZo-12aQ/s320/Lambda+Blueprints.png" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Click on the "<b><i>Create Function</i></b>" button and you'll be presented with a "Blueprints" page shown right. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">We want the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>cloudfront-modify-response-header</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> blueprint, so click on the title of that card.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Now we're going to have to add some information about the Lambda function before we can create it. Interestingly, we're not actually able to edit the code for the function until after it's been created - we have to take the boiler-plate code as is for now.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWfA-kp1fWIpI2WJjZoMfOuajM2fvXrsZTLN-V7DWP97hkPOP9Vtm1v_rhWNQ4x4RoJIiLF7qzIVG_p7bf2F-YlSFXNtI8dTuiVBsYg8B-gEP130Z3wtUWHNWyuMko0XZft04vyg/s1600/Lambda+Basic+Information.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="905" data-original-width="1600" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWfA-kp1fWIpI2WJjZoMfOuajM2fvXrsZTLN-V7DWP97hkPOP9Vtm1v_rhWNQ4x4RoJIiLF7qzIVG_p7bf2F-YlSFXNtI8dTuiVBsYg8B-gEP130Z3wtUWHNWyuMko0XZft04vyg/s320/Lambda+Basic+Information.png" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Enter a name for your function - remembering that you'll create a new function within your account for each website you host. Something like </span><span style="font-family: "courier new" , "courier" , monospace;">AddSecurityHeadersForMyDomain</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> might be a good choice here.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">If you've never created a Lambda, you'll need to create a role, so select "<b><i>Create New Role from Template</i></b>", give it a name and choose "<b><i>Basic Edge Lambda permissions</i></b>" as the policy template.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Once you've done that, you can select "<b><i>Choose an existing role</i></b>" and pick the role you previously completed - roles <u>can</u> be shared across Lambda functions.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2SdtMss99IPv2BLbWa21ySKPalw4R3VuiwncoYwBUhWwffXY6r4VbYSaz9tX19bz6hO_GGtGaekWzCrA0p7J40lWyXoVGfHSKlhPZ3oKfrBh6SeViYRLYUFt2QvvodFOUIXSiQ/s1600/Lambda+CloudFront.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="998" data-original-width="1600" height="199" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2SdtMss99IPv2BLbWa21ySKPalw4R3VuiwncoYwBUhWwffXY6r4VbYSaz9tX19bz6hO_GGtGaekWzCrA0p7J40lWyXoVGfHSKlhPZ3oKfrBh6SeViYRLYUFt2QvvodFOUIXSiQ/s320/Lambda+CloudFront.png" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Next, we need to configure how the Lambda links to CloudFront.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Critical here is to select the correct CloudFront distribution - which is of course just a nice long code string. (sigh)</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Leave the "<i>Cache Behavior</i>" option set to "<b><i>*</i></b>" (the default), and for "<i>CloudFront Event</i>" select "<b><i>Viewer Response</i></b>".</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">You have to check the "<i>Enable trigger and replicate</i>" option at this point to proceed - even though the "<b><i>Create Function</i></b>" (Save) button is way down the page below the boilerplate code. Click on that and you've successfully created your Lambda and bound it to your CloudFront distribution.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">But, of course, we've yet to actually edit the code for this function to do what we want - namely add the HSTS header.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi36Al0XImLA0LQv3CTxVSHF8uJpFMOYYL2V9SzUmhG7wxzzuAK5Gcf0LzMVFoLNCVRD1gHrQKAGiHFUBHm4BoYd2KmSBzp6_Ivi5ZZ5kvjrTUQBiwo3r7BLKGi8JO3SQDASSWpjg/s1600/Lambda+Boilerplate+Code.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="1308" data-original-width="1562" height="267" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi36Al0XImLA0LQv3CTxVSHF8uJpFMOYYL2V9SzUmhG7wxzzuAK5Gcf0LzMVFoLNCVRD1gHrQKAGiHFUBHm4BoYd2KmSBzp6_Ivi5ZZ5kvjrTUQBiwo3r7BLKGi8JO3SQDASSWpjg/s320/Lambda+Boilerplate+Code.png" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Click on the "Configuration" tab and you can see the boilerplate code. Helpfully AWS tells us that we can't edit the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>V1</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> function we just created, but have to switch to </span><span style="font-family: "courier new" , "courier" , monospace;"><b>$LATEST</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> - Lambda functions are versioned.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Let's pause though to have a look at what the boilerplate function is doing before we change it.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The function modifies the outbound headers - it takes the value from the "</span><span style="font-family: "courier new" , "courier" , monospace;">X-Amz-Meta-Last-Modified</span><span style="font-family: "arial" , "helvetica" , sans-serif;">" header set by S3 as the origin and pastes it into the more standard "</span><span style="font-family: "courier new" , "courier" , monospace;">Last-Modified</span><span style="font-family: "arial" , "helvetica" , sans-serif;">" header. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">It's all fairly obvious Node.js stuff, so let's add the HSTS header. Click on "Click here to go to $LATEST" and you'll be presented with an editable code pane.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The code we want to add is almost trivial, and we need to add it just above the </span><span style="font-family: "courier new" , "courier" , monospace;">callback(null, response)</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> line:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> const hstsName = 'Strict-Transport-Security';</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> const hstsValue = 'max-age=31536000; includeSubDomains';</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> headers[hstsName.toLowerCase()] = [{</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> key: hstsName.toLowerCase(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> value: hstsValue,</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> }];</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Click on "<b><i>Save</i></b>" (in the activity bar at the top of the page) to save the Lambda.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4RHUCsPXRQ0JmAh5IXZsJUNYWk43O2SIPtAGgnnPEV5j5yW0Lcxn5U1FlwQRAJW3A2A7tWsS4He6Xcx0uWVUbRXr4iu6nLp1NWyUra4m_uqxzxP6BVfSv-kwBWMugcwJ_FczvhA/s1600/Lambda+Save+And+Test.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="134" data-original-width="926" height="46" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4RHUCsPXRQ0JmAh5IXZsJUNYWk43O2SIPtAGgnnPEV5j5yW0Lcxn5U1FlwQRAJW3A2A7tWsS4He6Xcx0uWVUbRXr4iu6nLp1NWyUra4m_uqxzxP6BVfSv-kwBWMugcwJ_FczvhA/s320/Lambda+Save+And+Test.png" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">AWS Lambdas have an in-built test harness, so we should configure this - but it's not automated or obvious.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_EVKi0pbTlxa8wgx6XXcQsidA8J_mZcA1Q-4REWjY__mQ6_Vjh3aXQLcq8Fssbs3-jr_vDO42OsgILMWK3vGtDMnrkAR4ytDtz9V53ZesBrKjYtNHxQiiYDKmwBhQ-c8hrj_Whw/s1600/Lambda+Configure+Test+Events.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="642" data-original-width="1342" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_EVKi0pbTlxa8wgx6XXcQsidA8J_mZcA1Q-4REWjY__mQ6_Vjh3aXQLcq8Fssbs3-jr_vDO42OsgILMWK3vGtDMnrkAR4ytDtz9V53ZesBrKjYtNHxQiiYDKmwBhQ-c8hrj_Whw/s320/Lambda+Configure+Test+Events.png" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Click on the "<i>Select a test event...</i>" dropdown and click on "<b><i>Configure test events</i></b>" to bring up the Create / Edit dialog.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">Give your test a name (you can have 10 per function) and click on "Create" to save the test.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Now click on "<b><i>Save and test</i></b>" and your Lambda function is run - you should get a "success" banner to say all's well.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5DBIIrF0pgWWXdHsU9GAou1CogF6Zn9RYP5NVOlWpqezzZKPC-G23oTOI7AYpKrr5OpqvqCF8ZCHeE6ZjCIHtHCk7zP67GAwBTQaCRqAnTxsjY3p2bpoAYueFo2Px0i4ocCN7yg/s1600/Lambda+Test+Success.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="584" data-original-width="1600" height="116" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5DBIIrF0pgWWXdHsU9GAou1CogF6Zn9RYP5NVOlWpqezzZKPC-G23oTOI7AYpKrr5OpqvqCF8ZCHeE6ZjCIHtHCk7zP67GAwBTQaCRqAnTxsjY3p2bpoAYueFo2Px0i4ocCN7yg/s320/Lambda+Test+Success.png" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Expanding the details section lets you see the input and output of the function - and scrolling down the output area we see our HSTS header has been correctly added.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">We're nearly there, honestly.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiImNXKf5g697OM4oUO1MpJTUmM5YOaRSi84H8PTRt4eg5WDrjAGwB42-0cBtcY_eGRGxtsRRReln_YegkSZLwJM2V8DuLOEeziSrMjgRZ_aeIuReJzS2f4WeDOXGH_UTA9euQG3A/s1600/Lambda+Publish+New+Version.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="452" data-original-width="1344" height="107" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiImNXKf5g697OM4oUO1MpJTUmM5YOaRSi84H8PTRt4eg5WDrjAGwB42-0cBtcY_eGRGxtsRRReln_YegkSZLwJM2V8DuLOEeziSrMjgRZ_aeIuReJzS2f4WeDOXGH_UTA9euQG3A/s320/Lambda+Publish+New+Version.png" width="320" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">We have to publish and re-bind the function for it to take effect on our CloudFront distribution. Click on the "<i>Actions</i>" drop-down and click on "<b><i>Publish new version</i></b>". </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Enter a descriptive name for this version and click on "<b><i>Publish</i></b>".</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">You'll now be back to the Function details page, but with <i>V2</i> selected. Click on the "Triggers" tab - and there's nothing there! Our new version needs to be bound to CloudFront, replacing the obsolete V1 version.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9uAG9z8PCCWGCbguqk-zbuTfmnqJC9ehi95f8x9swxxo6AKmHfi4yHOVY1nNHrGxC7CY6PZdix5osTViy_-W0YQzIwtEQGk9YsqwfewFm4sZOqX3BZhggK0HMVstsvwxpOBW8dg/s1600/HSTS+Headers.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="802" data-original-width="1366" height="187" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9uAG9z8PCCWGCbguqk-zbuTfmnqJC9ehi95f8x9swxxo6AKmHfi4yHOVY1nNHrGxC7CY6PZdix5osTViy_-W0YQzIwtEQGk9YsqwfewFm4sZOqX3BZhggK0HMVstsvwxpOBW8dg/s320/HSTS+Headers.png" width="320" /></a><span style="font-family: "arial" , "helvetica" , sans-serif;">Click on "<b><i>+ Add Trigger</i></b>" and you get the trigger dialog. This should be pre-populated from the V1 settings so all you have to do is click on "Submit" to rebind to the <i>V2</i> function. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Load your site in a browse (you may need a hard-refresh) after a couple of seconds and using the developer tools you should be able see the HSTS header has been added.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Step 3 completed - finally.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Step 4 - Change insecure scheme references</span></h2>
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Difficulty level: Boring</span></h4>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Yes, it's boring - but also very easy - to go through your website looking for insecure scheme references.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Most of mine were relative references anyway, so it was only the few external ones that caused any issues - on the home page specifically my LinkedIn badge GIF.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Now you could, of course, use the Lambda we created in Step 3 to replace any '</span><span style="font-family: "courier new" , "courier" , monospace;"><b>http://</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">' found in the response body with '</span><span style="font-family: "courier new" , "courier" , monospace;"><b>https://</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">' to get the same effect as flicking the switch in <a href="https://www.cloudflare.com/" target="_blank">CloudFlare</a> does, but for my noddy sites that's overkill.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">A quick check using <a href="https://developer.chrome.com/devtools" target="_blank">Chrome DevTools</a> very quickly digs out the references - the Security tab is your friend here.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Actually getting the CloudFront distribution pushed so that the latest build of the codebase was being served was more problematic than anything else. Go figure.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Step 5 - Add the "upgrade-insecure-requests" CSP</span></h3>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Difficulty level: Easy</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">This step is actually easier in S3 and Cloudfront than in CloudFlare, in my opinion.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Now we've got a Lambda that modifies headers, all we need to do is add a couple more lines to add the CSP header:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> const cspName = 'Content-Security-Policy';</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> const cspValue = 'upgrade-insecure-requests';</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> headers[cspName.toLowerCase()] = [{</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> key: cspName.toLowerCase(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> value: cspValue,</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> }];</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Of course, we have to go round the loop of creating a new version of the function and re-binding it, but I'll leave that to you as an exercise.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<h2>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Step 6 - Monitor CSP reports</span></h2>
<br />
<h4>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Difficulty level: Trivial</span></h4>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Things have progressed since Troy wrote his article - he's recently joined <a href="https://twitter.com/Scott_Helme" target="_blank">Scott Helme</a> as a partner in <a href="https://report-uri.com/" target="_blank">Report-Uri</a> to build out that service.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">So all we do for this step is sign up for the </span><a href="https://report-uri.com/" style="font-family: arial, helvetica, sans-serif;" target="_blank">Report-Uri</a><span style="font-family: arial, helvetica, sans-serif;"> </span><span style="font-family: arial, helvetica, sans-serif;">service and get a reporting URL from there. Implementing monitoring is then another simple change to our Lambda to add another header:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> const csprName = 'Content-Security-Policy-Report-Only';</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> const csprValue = 'default-src https:;report-uri https://<u><i>mysecretapikey</i></u>.report-uri.com/r/d/csp/enforce';</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> headers[csprName.toLowerCase()] = [{</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> key: csprName.toLowerCase(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> value: csprValue,</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> }]; </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">And we're done - that's the 6-step Happy Path to HTTPS on Amazon S3 and Cloudfront.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Of course, you should go further - running your site through <a href="https://twitter.com/Scott_Helme" target="_blank">Scott Helme</a>'s <a href="https://securityheaders.io/" target="_blank">SecurityHeaders.io</a> gives a load of advice on headers you can add with your Lambda. My personal site got an '<b>F</b>' rating before I started this exercise - now it's an '<b>A'</b>. Win!</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmYGp5UPF7yZZEq-EDIb-GczhyphenhyphenZSwYXPVTiVWz5u1g4NvkVHMHAhDvm3fX_iWlktBCfTBDByDgsuE5MX8x7Oh-CsOTjt_zk0qL1oeHMycXN5_vWBVJci9bHHQxx7MjiUjGTZ4YhQ/s1600/A-Rated.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="379" data-original-width="1600" height="92" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmYGp5UPF7yZZEq-EDIb-GczhyphenhyphenZSwYXPVTiVWz5u1g4NvkVHMHAhDvm3fX_iWlktBCfTBDByDgsuE5MX8x7Oh-CsOTjt_zk0qL1oeHMycXN5_vWBVJci9bHHQxx7MjiUjGTZ4YhQ/s400/A-Rated.png" width="400" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">So here's the full code for the Lambda that gets me the '<b>A</b>' rating...</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<script src="https://gist.github.com/Rammesses/18cc4dad314d0cb9d3aa29224097d1eb.js"></script>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Enjoy.</span>
Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-45448772794617504162016-10-04T00:04:00.002+01:002016-10-04T00:04:28.771+01:00DDDNorth 2016 - A Retrospective<span style="font-family: Arial, Helvetica, sans-serif;">Another year, and another amazing <a href="http://www.dddnorth.co.uk/" target="_blank">DDD North</a> event.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">This time I was day-tripping it over from family in Manchester, so had an early start (i.e. completely in the dark) to catch the train over the Penines. A brisk 20 minute walk up the hill from Leeds station and I was at the Mechanical Engineering building of the University of Leeds.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">A couple of coffees and a brief speaker briefing and I was ready for the day.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">First up was <a href="https://twitter.com/MartinKearn" target="_blank">Martin Kearn</a> from Microsoft with "<a href="http://www.dddnorth.co.uk/Sessions/Details/235" target="_blank">Machine Learning for Muggles</a>". </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Martin showed how ML is used to find patterns in data - the bigger the sample set, the more interesting patterns can be found. After some fun samples, he used Azure ML Studio to create a car pricing model, based on first a few, and then many parameters - and then making that usable via a web API with a few drag-and-drop-and-clicks. Impressive stuff.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Next, he introduced <a href="http://howhappy.co.uk/">HowHappy.co.uk</a> - an ML experiment that used Azure LUIS and Azure Facial Recognition to assess his audience. Martin has <a href="https://blogs.msdn.microsoft.com/martinkearn/2016/03/22/introducing-howhappy-co-uk/" target="_blank">blogged</a> about this in detail - very cool stuff.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">For a change I was on in the second session of the morning. My "<a href="http://www.dddnorth.co.uk/Sessions/Details/240" target="_blank">10 more things</a>" talk was a second new one this year - clearly the appetites of the DDD North audience were very different to that of the DDD (Reading) audience.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">It all went well - bang on time, not too rushed, lots of interaction when the audience warmed up - and I'm really pleased with the feedback. Thanks again to everyone that came to see me - links to the slide deck can be found on <a href="http://www.hammond-turner.org.uk/#/speaking" target="_blank">my speaking page</a>.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">After the second break, it was time for some containerisation. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://twitter.com/naeemsarfraz" target="_blank">Naeem Sarfraz</a>'s session on "<a href="http://www.dddnorth.co.uk/Sessions/Details/201" target="_blank">Developing Apps in Windows Containers on Docker</a>" was a great introduction to the current state of play with Dockerisation (is that a thing?) with Windows. The newly released Windows Core / DotNet 462 image is going to be useful at work for a start.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Lunch was the usual brown-bag affair, with lots of catching up with old friends. The Onion Bhaji rolls were a revelation to a lot of people, I think!</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">First session after lunch was <a href="https://twitter.com/gshutler" target="_blank">Garry Shutler</a>'s "<a href="http://www.dddnorth.co.uk/Sessions/Details/270" style="background-color: white;">Designing an API for Developer Happiness</a>", where he replayed some very sensible lessons learned from creating the <a href="https://www.cronofy.com/" target="_blank">Cronofy</a> API. Three solid pages of notes (and 19 individual items to consider) later, and I've got a load of work to do to bring those learnings to the teams at work.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Finally, was one of the stand-out talks of the day - <a href="https://twitter.com/Chris_Alexander" target="_blank">Chris Alexander'</a>s "</span><a href="http://www.dddnorth.co.uk/Sessions/Details/292" style="background-color: white; color: #333333; font-family: "Segoe UI", Verdana, Helvetica, sans-serif;">Software Development for Formula 1</a><span style="font-family: Arial, Helvetica, sans-serif;">". </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Working at <a href="https://twitter.com/McLarenF1" target="_blank">McLaren F1</a>, Chris's talk was always going to have an immediate draw for me - and his use of classic F1 imagery (as well as amazing pictures of amazing McLaren road cars) was very much "toys for the boys". But he also gave an insight into the way software is developed there - not quite Agile, and very much tailored to delivering in time for the next race weekend. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">With the swag given out and thanks paid to the organisers, it was home time - in a Saturday night deluge. (Although that swift pint and final chat did warm me for the trip).</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Roll on next year.</span><br />
<br />Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-13295888573569130432016-08-19T14:30:00.003+01:002016-08-19T14:30:31.877+01:00Friday Quickie - Setting up Powershell as an App on MacOs<span style="font-family: Arial, Helvetica, sans-serif;">So yesterday, Microsoft announced that <a href="https://blogs.msdn.microsoft.com/powershell/2016/08/18/powershell-on-linux-and-open-source-2/" target="_blank">Powershell was open source and runs on MacOS</a>. Cool!</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">But the default installer doesn't make it available as an App within MacOS - you have to open a terminal first. :(</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">It's actually pretty easy to set this up tho'... </span><br />
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">TLDR</span></h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Create an Automator script and save it to Applications.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Step by Step:</span></h4>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUjMXB4S6T10Q5eItAheNce1Zv1TaMezXCy9OYKfAGG7IHUOaf2FEjPVLFWi1N8ErkLYOf4IVTL_GJtCsAGIy-EzbTMIzwcmVlxch3sO4SDIk3dwq58EVLs8Dm4uSRmFj6oNIGMQ/s1600/Grab.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUjMXB4S6T10Q5eItAheNce1Zv1TaMezXCy9OYKfAGG7IHUOaf2FEjPVLFWi1N8ErkLYOf4IVTL_GJtCsAGIy-EzbTMIzwcmVlxch3sO4SDIk3dwq58EVLs8Dm4uSRmFj6oNIGMQ/s200/Grab.png" width="200" /></a><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Open Automator and File -> New. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">In the New Script dialog, select Application.</span><br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">Add an AppleScript task from the Utilities section to the script by dragging it onto the design surface.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-Bq10wdcB8U_T7gnZlmttkVEYrR4w0WkN4NlByByOfAhiv8PlXArDz0VNsnCs635IcB5hyphenhyphenQbP3jXr2Y6RrEO9fZiMRQ23_ow6irYeps2Y1ATLsPZcQg3HW1SmBXFY4KnQBloCOg/s1600/Grab2.png" imageanchor="1"><img border="0" height="33" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-Bq10wdcB8U_T7gnZlmttkVEYrR4w0WkN4NlByByOfAhiv8PlXArDz0VNsnCs635IcB5hyphenhyphenQbP3jXr2Y6RrEO9fZiMRQ23_ow6irYeps2Y1ATLsPZcQg3HW1SmBXFY4KnQBloCOg/s200/Grab2.png" width="200" /></a></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Then add the following in the script.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwd1zKTuRK5bLpEHaZ3rdiwxIMPvla-X_BbF7iHoCrXgiQNjTs277_CzkW2_TZN5FmUj-EohtlOXy-JlrlSlUf2CwP9cDjl54m0kyiiyuvtg5zrWpI6oG07trQB7wGwU9F6gxpIA/s1600/Grab3.png" imageanchor="1"><img border="0" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwd1zKTuRK5bLpEHaZ3rdiwxIMPvla-X_BbF7iHoCrXgiQNjTs277_CzkW2_TZN5FmUj-EohtlOXy-JlrlSlUf2CwP9cDjl54m0kyiiyuvtg5zrWpI6oG07trQB7wGwU9F6gxpIA/s640/Grab3.png" width="640" /></a> </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaqBCsuIMakgYXL_3yExTwMAaTkqPI7p4vKl-sKT3j1I6qO8KWF65XR7LyGfh7xDxripdF6TrMUW8qj8UaxAmvOm1rlo6ybV1M_7zn__SrAhNSgxxhFj1KpRLKhhI6xiQ_CP3Jdw/s1600/Grab4.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaqBCsuIMakgYXL_3yExTwMAaTkqPI7p4vKl-sKT3j1I6qO8KWF65XR7LyGfh7xDxripdF6TrMUW8qj8UaxAmvOm1rlo6ybV1M_7zn__SrAhNSgxxhFj1KpRLKhhI6xiQ_CP3Jdw/s320/Grab4.png" width="320" /></a><span style="font-family: Arial, Helvetica, sans-serif;">Finally, save the script to the Applications folder and you're done - Powershell is available as an app through finder. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">For bonus points, find an icon you like on the web, copy the image to your clipboard, GetInfo on the script you just created, select the icon at the top left (it'll get a blue outline), and you can paste the new icon for extra shininess.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Job done.</span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-25412628146866269902016-07-04T11:30:00.000+01:002016-07-05T16:36:36.814+01:00Monday Quickie: Git Aliases for Proxy Settings<div class="p1">
<span class="s1">If, like me, you find yourself working from home occasionally flipping the proxy setting on and off for <b><span style="font-family: Courier New, Courier, monospace;">GIT</span> </b>becomes tiresome.</span></div>
<div class="p1">
<span class="s1"><br /></span></div>
<div class="p1">
<span class="s1">So here's a snippet to give you two new <b><span style="font-family: Courier New, Courier, monospace;">GIT</span> </b>commands for setting and resetting the http.proxy setting that </span><b><span style="font-family: Courier New, Courier, monospace;">GIT</span> </b>uses.</div>
<div class="p1">
<br /></div>
<div class="p2">
<span class="s1"><b><span style="font-family: Courier New, Courier, monospace;">git config --global alias.noproxy 'config --global --unset http.proxy'</span></b></span></div>
<div class="p2">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1"><b>git config --global alias.setproxy 'config --global http.proxy </b><span class="s2"><b>http://<proxyUrl></b></span></span><span class="s1"><b>:<proxyPath></b></span><span class="s4"><b>'</b></span></span></div>
<div class="p1">
<br /></div>
<br />
<div class="p1">
<span class="s1">Now you can just use '</span><span class="s5"><b><span style="font-family: Courier New, Courier, monospace;">git noproxy</span></b></span><span class="s1">' when at home to turn the proxy off and '</span><span class="s5"><b><span style="font-family: Courier New, Courier, monospace;">git setprox</span>y</b></span><span class="s1">' when you're back in the office.</span></div>
Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-20978992942022027712015-10-30T08:24:00.000+00:002015-10-30T08:24:13.060+00:00Friday Quickie - Search, Filter and Copy matching files in Powershell<span style="font-family: Arial, Helvetica, sans-serif;">Another little aide-memoire - I want to find all files in a directory containing a specific string that were created on a specific date and copy them to another directory.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Using Powershell it's quite easy, with just a little wrinkle in the copy-item syntax:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"><b>PS C:\SourceFolder> get-childitem | where-object { $_.CreationTime -ge "10/29/2015" -and $_.CreationTime -le "10/30/2015" } | select-string -pattern "80029" | group path | select name | <span style="background-color: yellow;">% { $_.Name | copy-item -destination C:\temp\TargetFolder }</span></b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-57383260823981655912015-09-22T14:48:00.001+01:002015-09-22T14:48:20.375+01:00HTML5, AngularJS and hosting on AWS S3 - Oh my!<span style="font-family: Arial, Helvetica, sans-serif;">So I've not done a big "how to" post in a l-o-n-g while, so I thought it'd be useful to document the process of moving from an <i>effectively</i> static ASP.Net MVC web site to an <b><i>actually</i></b> static web site that can be hosted directly from an S3 bucket.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Why? Well, my "toy" sites have no real dynamic content, so why maintain a micro-VM on Azure just to host them?</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">So this will be a step-by-step guide - partly for my own recollection, and also because finding some of the incantations needed to publish a web site successfully to AWS S3 took a fair bit of effort.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<h2>
<span style="font-family: Arial, Helvetica, sans-serif;">Step 0 - Setup</span></h2>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">As I'm going to try and maintain these sites 'properly', I'm going to put the source code into <a href="http://github.com/" target="_blank">GitHub</a>.</span><br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>cd Projects/</b></span></span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">joel$ <b>mkdir mywebsite.co.uk</b></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>cd </b></span></span><b style="font-family: 'Courier New', Courier, monospace;">mywebsite</b><span style="font-family: Courier New, Courier, monospace;"><span class="s1"><b>.co.uk</b></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>git init</b></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1"><i>Initialized empty Git repository in /Users/joel/Projects/mywebsite.co.uk/.git/</i></span></span></blockquote>
<span style="font-family: Arial, Helvetica, sans-serif;">So, I set up a new repository on GitHub with an Apache license and a default README.md file, and connected by empty project folder to that:</span><br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>git remote add origin https://github.com/Me/mywebsite.co.uk</b></span></span><b> </b> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">joel$ <b>git pull origin master</b></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1"><i>From https://github.com/Me/mywebsite.co.uk</i></span><span class="s1"><i> * branch master -> FETCH_HEAD</i></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>ls</b></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1"><i>LICENSE<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>README.md</i></span></span></blockquote>
<br />
<h2>
<span style="font-family: Arial, Helvetica, sans-serif;">Step 1 - Scaffolding</span></h2>
<span style="font-family: Arial, Helvetica, sans-serif;">Scaffolding a sensibly structured HTML5/AngularJS site is amazingly easy using <a href="http://yeoman.io/" target="_blank">Yeoman</a>. A quick check first that we're good to go...</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>yo --version && bower --version && grunt --version</b></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1">1.3.2</span></i></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1"></span><span class="s1">1.3.12</span></i></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1"></span><span class="s1">grunt-cli v0.1.13</span></i></span></blockquote>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">then a whole AngularJS web site scaffolded with one command!</span><br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">joel$ <b>yo angular</b></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i>... </i></span></blockquote>
<br />
<div class="p1">
Commit and push to GitHub gives me a baseline against which I can start working on the site</div>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>git add .</b></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>git commit -m "Initial scaffolding"</b></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1">[master 995f8ba] Initial scaffolding</span></i></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1"></span><span class="s1"> 26 files changed, 1640 insertions(+)</span></i></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1"></span><span class="s1">...</span></i></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><br /></span><span style="font-family: 'Courier New', Courier, monospace;">joel$ </span><span style="font-family: Courier New, Courier, monospace;"><span class="s1"><b>git push origin master</b></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i>...</i></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1">To https://github.com/Me/mywebsite.co.uk.git</span></i></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1"></span><span class="s1"> f3525d2..995f8ba master -> master</span></i></span></blockquote>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">
</span></span></div>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<h2>
<span style="font-family: Arial, Helvetica, sans-serif;">Step 2 - Working on the site</span></h2>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">I've got to admit I really like the workflow that's enabled by using VSCode and grunt file watching - a quick </span><span style="font-family: Courier New, Courier, monospace;"><b>grunt serve</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> and then just edit and save. With a two monitor setup, this is an absolute dream.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Capturing small changes as individual </span><b><span style="font-family: Courier New, Courier, monospace;">git commit</span></b><span style="font-family: Arial, Helvetica, sans-serif;">s feels "just right" too.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<h2>
<span style="font-family: Arial, Helvetica, sans-serif;">Step 3 - Setting up publishing to AWS S3</span></h2>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">This is where things get interesting. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Setting up a new bucket in S3 is easy - name the bucket after the web site url (</span><b><span style="font-family: Courier New, Courier, monospace;">mywebsite.co.uk</span></b><span style="font-family: Arial, Helvetica, sans-serif;"> in this example).</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">We then need to configure a </span><span style="font-family: Courier New, Courier, monospace;"><b>grunt</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> task to publish to that bucket - </span><span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://twitter.com/_rjm_" target="_blank">Rob Morgan</a> has a very good walkthrough <a href="http://robmorgan.id.au/post/101244431563/publishing-simple-static-sites-with-npm-grunt-and" target="_blank">here</a> of how to do this using the </span><span style="font-family: Courier New, Courier, monospace;"><b>grunt-aws</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> package.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1">joel$ <b>npm install grunt-aws-s3 --save-dev</b></span><span class="s1">...</span></span></blockquote>
<div class="p1">
<span class="s1"><br /></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;">And then we add some lines to the </span><span style="font-family: Courier New, Courier, monospace;"><b>Gruntfile.js</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> file:</span></span></div>
<div class="p1">
<span class="s1"><br /></span></div>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><b>grunt.loadNpmTasks('grunt-aws-s3');</b></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: 'Courier New', Courier, monospace;">// Configurable paths for the application</span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">var appConfig = {<br /> app: require('./bower.json').appPath || 'app',<br /> dist: 'dist',<br /> <b>s3AccessKey: grunt.option('s3AccessKey') || '',<br /> s3SecretAccessKey: grunt.option('s3SecretAccessKey') || '',<br /> s3Bucket: grunt.option('s3Bucket') || 'mywebsite.co.uk',</b><br /> };</span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">grunt.initConfig({<br /><i>...</i><br /><b>aws_s3: {<br /> options: {<br /> accessKeyId: appConfig.s3AccessKey,<br /> secretAccessKey: appConfig.s3SecretAccessKey,<br /> bucket: appConfig.s3Bucket,<br /> region: 'eu-west-1',<br /> },<br /> production: {<br /> files: [<br /> { expand: true,<br /> dest: '.',<br /> cwd: 'dist/',<br /> src: ['**'],<br /> differential: true }<br /> ]<br /> }<br /> }</b><br />});</span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><b>grunt.registerTask('deploy', ['build', 'aws_s3']);</b></span></blockquote>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace;"><span class="s1"></span></span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">Notice that my AWS secrets are injected via grunt command line parameters - so no chance of committing them into </span><a href="http://github.com/" style="font-family: Arial, Helvetica, sans-serif;" target="_blank">GitHub</a><span style="font-family: Arial, Helvetica, sans-serif;">!</span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="p1">
<h2>
<span style="font-family: Arial, Helvetica, sans-serif;">Step 4 - Configuring AWS permissions</span></h2>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">The biggest headache I found in this whole process was setting AWS permissions up correctly. I don't really want to push via my super-user account, and if I ever get a build server for all this working, I'd rather have a single user per web site with VERY limited permissions to push changes to AWS S3.</span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Create a deployment user</span><span style="text-align: center;"> </span></h4>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">In <a href="https://console.aws.amazon.com/iam/home?region=eu-west-1#home" target="_blank">AWS IAM Management</a>, I created a new user called </span><span style="font-family: Courier New, Courier, monospace;"><b>mywebsite.deploy</b></span><span style="font-family: Arial, Helvetica, sans-serif;">, with an associated <b>Access Key / Secret</b> pair that I downloaded and saved somewhere secure. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">There's no way to get back an access key, so be careful not to forget this step, or you'll have to regenerate the key pair! </span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">Actually, Amazon recommend rotating keys on a regular basis, so you'll be doing that anyway - but it's still not what you want to be doing every morning before you start.</span><br />
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Create a deployment group</span></h4>
</div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">Again in </span><a href="https://console.aws.amazon.com/iam/home?region=eu-west-1#home" style="font-family: Arial, Helvetica, sans-serif;" target="_blank">AWS IAM Management</a><span style="font-family: Arial, Helvetica, sans-serif;">, I created a new group called </span><span style="font-family: Courier New, Courier, monospace;"><b>mywebsite_deployment</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> and added the </span><span style="font-family: Courier New, Courier, monospace;"><b>mywebsite.deploy</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> user to that group. </span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">Next up - permissions.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Grant permissions on the bucket to the group</span></h4>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">To do this, we have to add an "Inline policy" to the </span><span style="font-family: Courier New, Courier, monospace;"><b>mywebsite_deploy</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> group to grant basic access to any users in the group. </span></div>
<br />
<pre style="background-color: white; border: none; color: #444444; font-family: Consolas, 'Bitstream Vera Sans Mono', Monaco, monospace; font-size: 14px; font-stretch: normal; line-height: 1.3em; margin-bottom: 5px; margin-top: 5px; overflow: auto; padding: 10px;">{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::mywebsite.co.uk"
}
]
}</pre>
<div>
</div>
<br />
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Grant restricted rights on the bucket to the deployment user</span></h4>
</div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">We don't want the </span><span style="font-family: Courier New, Courier, monospace;"><b>mywebsite.deploy</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> user to be able to do <i>anything</i> to the bucket (such as change permissions), so we restrict their access rights to the bucket contents by applying a policy to the bucket itself</span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="p1">
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">{</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"Id": "Policy1438599268262",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"Version": "2012-10-17",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"Statement": [</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"Sid": "Stmt1438599259521",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"Action": [</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"s3:DeleteObject",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"s3:GetObject",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"s3:GetObjectAcl",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"s3:PutObject",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"s3:PutObjectAcl"</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>],</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"Effect": "Allow",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"Resource": "arn:aws:s3:::mywebsite.co.uk/*",</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"Principal": {</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"AWS": [</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>"arn:aws:iam::765146773618:user/mywebsite.deploy"</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>]</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>]</span><span style="font-family: Courier New, Courier, monospace;">}</span></blockquote>
</div>
<div class="p1">
<h2>
<span style="font-family: Arial, Helvetica, sans-serif;">Step 5 - Deploying to AWS</span></h2>
</div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">With all that set up (phew!), then deploying the site to AWS S3 is a one-liner:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<blockquote class="tr_bq">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">joel$ <b>grunt deploy --s3AccessKey=<i><u><<your access key>></u></i> --s3SecretAccessKey=<i><u><<your secret>></u></i></b></span></span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">... </span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i><span class="s1">16</span><span class="s2">/</span><span class="s1">16</span><span class="s2"> objects uploaded to bucket </span><span class="s1">mywebsite.co.uk/</span> </i></span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><i>Done, without errors.</i></span></blockquote>
<br />
<h2>
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;">Step 6 - Set up Static Website Hosting</span></span></h2>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">In the </span><a href="https://console.aws.amazon.com/s3/home?region=eu-west-1" style="font-family: Arial, Helvetica, sans-serif;" target="_blank">AWS S3 console</a><span style="font-family: Arial, Helvetica, sans-serif;">, select the bucket and click on "Properties" to open the properties pane for the bucket.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;">Open the "Static Web Site Hosting" section and it's easy to enable hosting just by checking the option. Enter </span><span style="font-family: Courier New, Courier, monospace;"><b>index.html</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> as the default document.</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span>
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;">Click "Save", and your content is served from the default endpoint.</span></span><br />
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span><span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;">Now's a good time to check that your web app runs nicely by just hitting that endpoint in a browser - and get a warm fuzzy feeling.</span></span><span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span>
<br />
<h2>
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;">Step 7 - Domain setup</span></span></h2>
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span>
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;">The last thing to do is to switch over the DNS for the target domain so that </span><span style="font-family: Courier New, Courier, monospace;"><b>www.mywebsite.co.uk</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> is a CNAME for the AWS S3 endpoint.</span></span><br />
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span>
<span class="s1"><span style="font-family: Arial, Helvetica, sans-serif;">You can if you want set up <a href="https://console.aws.amazon.com/cloudfront/home" target="_blank">AWS CloudFront</a> delivery as well, but that's beyond the scope of this how-to.</span></span></div>
<div class="p1">
<br /></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com3tag:blogger.com,1999:blog-22825020.post-50377039119057338852015-07-29T16:34:00.003+01:002015-07-29T16:36:52.788+01:00Upgrading a Windows 8.1 VM to Windows 10<span style="font-family: Arial, Helvetica, sans-serif;">So now that Windows 10 has been released, I thought it was time to do more than just "play" with the Technical Preview.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">My <strike>victim</strike> candidate was the Windows 8.1 VM I have on my Macbook Pro for dev and demo work - if it all went pear shaped then I could just blow the VM away and start again.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Issue 1 - I didn't have the "Get Windows 10" icon on my start bar</span></h4>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">This has been bugging me for a while, as I've been expecting that to appear automagically over the past month. But it's been stoicly absent. Turns out that if you've got a domain joined PC you'll get the GWX app with the <a href="https://support.microsoft.com/en-gb/kb/3035583" target="_blank">relevant KB 3035583 update</a>, but it'll not work.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">So the only way forward was to <a href="https://www.microsoft.com/en-us/software-download/windows10ISO" target="_blank">download the ISO</a> and run the update from that.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Issue 2 - You need 9.5GB free to install Windows 10</span></h4>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Typically, I had less than 1GB free - until Disk Cleanup showed 5GB of Temporary files and 4Gb of old installers - better than trying to change the size of the physical BootCamp partition my VM was on.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Installing - was actually pretty easy</span></h4>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">About as painless as any other Windows install / upgrade - the install worked fine, letting me sign back in to complete the process... and then</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">OMG - Black Screen!</span></h4>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">It was all going far too well - there had to be a hitch... </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<table style="background-color: white;"><tbody>
<tr><td height="48" width="48"><blockquote class="tr_bq">
<span style="font-family: Arial, Helvetica, sans-serif;"><img height="48" src="data:image/png;base64,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" style="border: 2px solid white;" width="48" /></span></blockquote>
</td><td><span style="font-family: Arial, Helvetica, sans-serif;"><b>rammesses</b><br />Slightly worrying that my #Windows10 upgrade has been stuck showing a black screen for the last 20 minutes. Cursor moves, so still #Hopeful<br /><a href="https://twitter.com/rammesses/status/626385985128005632">29/07/2015 14:37</a></span></td></tr>
</tbody></table>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">It seems several people have had this problem when a PC (virtual or otherwise) boots for the first time into Windows 10. There's a thread </span><a href="http://answers.microsoft.com/en-us/insider/forum/insider_wintp-insider_install/black-screen-with-mouse-pointer-after-cold-boot/6dcac7f7-4e39-4bf3-99b9-e20b9718bd8d?auth=1" style="font-family: Arial, Helvetica, sans-serif;" target="_blank">here</a><span style="font-family: Arial, Helvetica, sans-serif;"> about it - but the upshot is that you just need a reboot!</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">In VMWare Fusion I just triggered that from the Virtual Machine menu and I was back... but only at 1924x768 resolution.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">Drivers!</span></h4>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">There wasn't anything I could find on the web indicating whether the Bootcamp and VMWare Tools drivers would work with Windows 10 - so I crossed my fingers and gave it a go... and it worked!</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://pbs.twimg.com/media/CLF0Q_KWUAAYp77.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="239" src="https://pbs.twimg.com/media/CLF0Q_KWUAAYp77.jpg" width="320" /></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">All that was left was to tweet that I'd succeeded... </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<table style="background-color: white;"><tbody>
<tr><td height="48" width="48"><blockquote class="tr_bq">
<img height="48" src="data:image/png;base64,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" style="border: 2px solid white;" width="48" /></blockquote>
</td><td><blockquote>
<span style="font-family: Arial, Helvetica, sans-serif;"><b>rammesses</b></span><span style="font-family: Arial, Helvetica, sans-serif;">#Windows10 running under #VMware Fusion on a MBP in #Retina resolution - #Done http://t.co/30Oeh2lfWM</span><span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://twitter.com/rammesses/status/626409658450841600">29/07/2015 16:11</a></span></blockquote>
</td></tr>
</tbody></table>
Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-23766315651537314142015-06-02T11:44:00.002+01:002015-06-02T11:44:51.861+01:00Tuesday Quickie - Transaction Manager Errors are not always what they seem<span style="font-family: Arial, Helvetica, sans-serif;">This one bit me today for the second time, so I thought I'd blog about the problem - more than as a reminder to myself than for any other reason.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">On one of our environments, database changes weren't being saved with the following cryptic error message:</span><br />
<blockquote class="tr_bq">
<span class="s1"><b><span style="font-family: Courier New, Courier, monospace;">Communication with the underlying transaction manager has failed.</span></b></span><span style="font-family: Courier New, Courier, monospace;"><span class="s1">-- COMException - The MSDTC transaction manager was unable to pull the transaction from the source transaction manager due to communication problems. </span>Possible causes are: a firewall is present and it doesn't have an exception for the MSDTC process, the two machines cannot find each other by their NetBIOS names, or the support for network transactions is not enabled for one of the two transaction managers.</span></blockquote>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">The actual cause?</span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">A <b><u><i>single</i></u></b> rogue space in the connection string.</span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">Go figure!</span></div>
Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-3945107514941817042015-05-20T08:38:00.000+01:002015-05-20T09:16:50.477+01:00Tuesday Quickie - Suppressing SignalR in the Developer Console<span style="font-family: Arial, Helvetica, sans-serif;">This quickie came from <a href="https://twitter.com/bart_read/status/600618378387132416" target="_blank">a conversation Bart Read and I had on Twitter</a> about how hard all the traffic SignalR generates makes using the Network tab in the Chrome Developer Tools.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">In the end, <a href="https://twitter.com/rammesses/status/600665901902503937" target="_blank">I had a brainwave</a> and found a simple solution - with a little digging and experimentation.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">All you need to do is click on the filter icon on the Network tab's toolbar and enter the following magic incantation</span><br />
<br />
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace; font-size: large;"><b>-transport -negotiate</b></span></div>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">This pretty much kills all the SignalR traffic and lets you get back to debugging your own code.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2kScVVpj70RbQZ-zsC_OJkqiG3n8utue4mWRmKQb2E1EFC45T5f8oalaqRh8QxZAT2pqcFGaQnuQ84C7MJNy32wQqSmgTldNRodRKYKI-b5porxTiqwO_3MIuorooQ2B3dsYn3A/s1600/SignalR-Suppressions.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2kScVVpj70RbQZ-zsC_OJkqiG3n8utue4mWRmKQb2E1EFC45T5f8oalaqRh8QxZAT2pqcFGaQnuQ84C7MJNy32wQqSmgTldNRodRKYKI-b5porxTiqwO_3MIuorooQ2B3dsYn3A/s400/SignalR-Suppressions.png" width="400" /></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<br />Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-83425827905682989792015-02-27T14:23:00.003+00:002015-02-27T14:23:53.214+00:00Friday Quickie - dumping parameters from a TFS build definition<span style="font-family: Arial, Helvetica, sans-serif;">So here's the scenario - Ops have changed the TFS build infrastructure underneath you and the build definitions for an "older" project aren't working.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgR95Hw1sEQJjkKEPHa1ceco3Xx_-Wvw6Zy_tN1litaEWSC5UV_pmMYZkyIxPSV4KumnhplSmmz2UnSfqEw43Z1cIwHO0l5YkI61zQ9Kas7VN8RfHacEu_tPjB2IzRO8UJj_Z7HQ/s1600/TFS+Build+-+Bad+Properties+Warning.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgR95Hw1sEQJjkKEPHa1ceco3Xx_-Wvw6Zy_tN1litaEWSC5UV_pmMYZkyIxPSV4KumnhplSmmz2UnSfqEw43Z1cIwHO0l5YkI61zQ9Kas7VN8RfHacEu_tPjB2IzRO8UJj_Z7HQ/s1600/TFS+Build+-+Bad+Properties+Warning.PNG" /></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;">You open the build definition in Visual Explorer, and lo and behold, there's a warning triangle on the Process tab. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw-1kRfdNX77pmJCdc8G60yefqP6zAYO9BPJ1llY8tjgyks9F5ljMPo_HxG7jAEyDXkAZJdO3oa4JZ3mtbzqxIHx5nr7GJwGyznGknsPPLR7c9Ib0HI4Bd76PZzW3ruamf4T5f5Q/s1600/TFS+Build+-+Property+Error.PNG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw-1kRfdNX77pmJCdc8G60yefqP6zAYO9BPJ1llY8tjgyks9F5ljMPo_HxG7jAEyDXkAZJdO3oa4JZ3mtbzqxIHx5nr7GJwGyznGknsPPLR7c9Ib0HI4Bd76PZzW3ruamf4T5f5Q/s1600/TFS+Build+-+Property+Error.PNG" /></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;">Opening that, and you find that the one of the properties (in this case a deployment script) is now empty and showing an error circle.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">The problem is that because it's invalid, the editor has cleared the property - even opening the dialog doesn't help - it's all gone.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">So how do you find out what the property WAS so you can fix it?</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Well, first, close the build definition <b><i><u>WITHOUT SAVING IT</u></i></b>!</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Next, fire up a Visual Studio Command Prompt and CD to the folder that's mapped to the root of the source code in TFS.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">What you need is </span><span style="font-family: Arial, Helvetica, sans-serif;">command line </span><span style="font-family: Courier New, Courier, monospace; font-weight: bold;">tfpt.exe</span><span style="font-family: Arial, Helvetica, sans-serif;"> tool from</span><span style="font-family: Arial, Helvetica, sans-serif;"> <a href="https://visualstudiogallery.msdn.microsoft.com/f017b10c-02b4-4d6d-9845-58a06545627f" target="_blank"><b>TF Power Tools</b></a> (you had that installed already, didn't you?)</span><span style="font-family: Arial, Helvetica, sans-serif;">. This has a handy </span><span style="font-family: Courier New, Courier, monospace;"><b>BuildDefinition /dump</b></span><span style="font-family: Arial, Helvetica, sans-serif;"> option that will show you what's in the build definition - regardless that it's invalid.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfR5SYh8uuoGu5GhgN_e3NeUxzIp_TTWG4gawHQWqKFrCZc3w-8S88iQQQIi_24QbDYx3EPGbFOWrpPIZl3rGPqG9NANo7S13bfzu435TiACYO4TA3c-sIv48TOSltgt9JeaCO8w/s1600/TFS+Build+-+TFPT+Command.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfR5SYh8uuoGu5GhgN_e3NeUxzIp_TTWG4gawHQWqKFrCZc3w-8S88iQQQIi_24QbDYx3EPGbFOWrpPIZl3rGPqG9NANo7S13bfzu435TiACYO4TA3c-sIv48TOSltgt9JeaCO8w/s1600/TFS+Build+-+TFPT+Command.PNG" height="42" width="400" /></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">You can now open the text file in notepad and see what the property WAS - job done.</span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-70311451286279403532014-09-21T14:33:00.000+01:002014-09-21T14:33:24.407+01:00Pushing the Octopus South...<span style="font-family: Arial, Helvetica, sans-serif;">On Thursday last (18th Sept), I was privileged to take my <a href="http://www.meetup.com/DeveloperSouthCoast/events/197711632/" target="_blank">OctopusDeploy</a> talk on the road again at <a href="http://devsouthcoast.com/" target="_blank">Developer South Coast</a> in Southampton.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">I'd been having trouble </span><span style="font-family: Arial, Helvetica, sans-serif;">the previous evening </span><span style="font-family: Arial, Helvetica, sans-serif;">with the VMs I used at ChesterDevs, and had not been able to access them, so I took a gamble and instead of demonstrating Octopus on a prepared rig, started from scratch installing the server and tentacle onto new VMs.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Even that wasn't enough difficulty for the <a href="https://twitter.com/demogods" target="_blank">Demo Gods</a>, clearly, as both my Macbook and the WindowsVM on it rebooted during the talk, and my Mifi dropped its signal out to the point that I had to borrow connectivity from a kind member of the audience at the break.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">But in spite of all these problems, I managed to get through the demo and show that you can actually get Octopus up and deploying from scratch within about an hour.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">All the resources for the talk, including the slide-deck, sample solution, etc can be found here:</span><br />
<br />
<blockquote class="tr_bq">
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://github.com/Rammesses/ddd-octopus">https://github.com/Rammesses/ddd-octopus</a></span></blockquote>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">I've got to thank <a href="https://twitter.com/Imaji" target="_blank">John McLoughlin</a> for inviting me to talk - my company Landmark Information Group (<a href="http://www.landmark.co.uk/">http://www.landmark.co.uk</a>, <a href="http://twitter.com/LandmarkUK" target="_blank">@LandmarkUK</a>) for supporting me as I share our experiences, and to the <a href="https://twitter.com/devsouthcoast" target="_blank">@devsouthcoast</a> audience for their patience and enthusiasm.</span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-3503681684138928342014-09-15T10:41:00.001+01:002014-09-15T10:41:29.148+01:00Monday Quickie - Using IIS Application Initialization for keeping ASP.Net Apps alive.This came about from trying (and failing) to remember that one liner for registering components with IIS for correct teardown.<br />
<blockquote class="tr_bq">
<span style="background-attachment: initial !important; background-clip: initial !important; background-color: white; background-image: none !important; background-origin: initial !important; background-position: initial !important; background-repeat: initial !important; background-size: initial !important; border: 0px; color: #2b91af; font-family: monospace, consolas, 'courier new'; font-size: 14px; letter-spacing: 0.100000001490116px; line-height: 20.7930450439453px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre;">HostingEnvironment</span><span style="background-attachment: initial !important; background-clip: initial !important; background-color: white; background-image: none !important; background-origin: initial !important; background-position: initial !important; background-repeat: initial !important; background-size: initial !important; border: 0px; font-family: monospace, consolas, 'courier new'; font-size: 14px; letter-spacing: 0.100000001490116px; line-height: 20.7930450439453px; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre;">.RegisterObject(launcher);</span></blockquote>
I finally came across the article by <a href="https://twitter.com/rickstrahl" target="_blank">Rick Strahl</a> that I'd been looking for, which covers everything:<br />
<br />
<blockquote class="tr_bq" style="background-color: white; border: 0px; color: teal; font-family: Geneva, Verdana, 'DejaVu Sans', sans-serif; font-size: 1.4em; line-height: inherit; margin: 0px; outline: 0px; padding: 0px; text-align: center; vertical-align: baseline;">
<a href="http://weblog.west-wind.com/posts/2013/Oct/02/Use-IIS-Application-Initialization-for-keeping-ASPNET-Apps-alive" style="border: 0px; color: teal; font-family: inherit; line-height: inherit; margin: 0px; outline: 0px; padding: 0px; text-decoration: none; vertical-align: baseline;">Use IIS Application Initialization</a><span style="background-color: transparent;"> </span></blockquote>
<blockquote class="tr_bq" style="background-color: white; border: 0px; color: teal; font-family: Geneva, Verdana, 'DejaVu Sans', sans-serif; font-size: 1.4em; line-height: inherit; margin: 0px; outline: 0px; padding: 0px; text-align: center; vertical-align: baseline;">
<a href="http://weblog.west-wind.com/posts/2013/Oct/02/Use-IIS-Application-Initialization-for-keeping-ASPNET-Apps-alive" style="border: 0px; color: teal; font-family: inherit; line-height: inherit; margin: 0px; outline: 0px; padding: 0px; text-decoration: none; vertical-align: baseline;">for keeping ASP.NET Apps alive</a></blockquote>
<div>
<br /></div>
<div>
Seemples.</div>
<br />
<br />
<br />Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-89331866753655616542014-09-11T11:17:00.002+01:002014-09-11T11:17:21.379+01:00Thursday Quickie - Which of my packages does my code use?<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">I had the problem today of wanting to see what versions of my private packages were being used by a specific branch of my codebase.</span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">The solution is a very small powershell script that parses packages.config files and finds the unique dependency packages who's name matches '</span><b><u><i><span style="font-family: Courier New, Courier, monospace;">MyNamespace</span></i></u></b><span style="font-family: Arial, Helvetica, sans-serif;">'.</span></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">Get-ChildItem -recurse -include "packages.config" | </span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: 'Courier New', Courier, monospace;">select-string -pattern "<b><i><u>MyNamespace</u></i></b>" |</span></blockquote>
<blockquote class="tr_bq">
<span style="font-family: 'Courier New', Courier, monospace;">%{ $data = $_ -match 'id="([\w\d.]*)" version="([\d.])*"'; write-output $matches[0] } |</span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: 'Courier New', Courier, monospace;">sort </span><span style="font-family: 'Courier New', Courier, monospace;">| select -uniq</span></blockquote>
<br />
<div class="p1">
<br /></div>
<div class="p1">
<span style="font-family: Arial, Helvetica, sans-serif;">Quick and simple.</span></div>
Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-21992253350344321592014-08-31T15:57:00.002+01:002014-08-31T15:57:24.888+01:00On the road once again.<span style="font-family: Arial, Helvetica, sans-serif;">As the autumn draws in, I'm on the road again and am privileged to have been asked to speak at the following developer community events:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="MsoListParagraphCxSpFirst" style="margin-left: 36.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -18.0pt;">
<!--[if !supportLists]--><span style="font-family: Arial, Helvetica, sans-serif;"><span lang="EN-US"><span style="mso-list: Ignore;">·<span style="font-size: 7pt; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">
</span></span></span><!--[endif]--><span lang="EN-US"><a href="http://www.dddeastanglia.com/Session/Details/3139" target="_blank">DDD East Anglia – So you want to be a Tech Lead? 10 things you need to do to succeed.</a><br />
13 September 2014<br style="mso-special-character: line-break;" />
<!--[if !supportLineBreakNewLine]--><br style="mso-special-character: line-break;" />
<!--[endif]--><o:p></o:p></span></span></div>
<div class="MsoListParagraphCxSpMiddle" style="margin-left: 36.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -18.0pt;">
<!--[if !supportLists]--><span style="font-family: Arial, Helvetica, sans-serif;"><span lang="EN-US"><span style="mso-list: Ignore;">·<span style="font-size: 7pt; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">
</span></span></span><!--[endif]--><span lang="EN-US"><a href="http://www.meetup.com/DeveloperSouthCoast/events/197711632/" target="_blank">Developer South Coast - Lookout! Here comes the Kra, erm, Octopus!</a><br />
18 Sept 2014<br style="mso-special-character: line-break;" />
<!--[if !supportLineBreakNewLine]--><br style="mso-special-character: line-break;" />
<!--[endif]--><o:p></o:p></span></span></div>
<!--[if gte mso 9]><xml>
<o:OfficeDocumentSettings>
<o:RelyOnVML/>
<o:AllowPNG/>
</o:OfficeDocumentSettings>
</xml><![endif]-->
<!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:TrackMoves/>
<w:TrackFormatting/>
<w:PunctuationKerning/>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:DoNotPromoteQF/>
<w:LidThemeOther>EN-GB</w:LidThemeOther>
<w:LidThemeAsian>JA</w:LidThemeAsian>
<w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
<w:Compatibility>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:SplitPgBreakAndParaMark/>
<w:EnableOpenTypeKerning/>
<w:DontFlipMirrorIndents/>
<w:OverrideTableStyleHps/>
<w:UseFELayout/>
</w:Compatibility>
<m:mathPr>
<m:mathFont m:val="Cambria Math"/>
<m:brkBin m:val="before"/>
<m:brkBinSub m:val="--"/>
<m:smallFrac m:val="off"/>
<m:dispDef/>
<m:lMargin m:val="0"/>
<m:rMargin m:val="0"/>
<m:defJc m:val="centerGroup"/>
<m:wrapIndent m:val="1440"/>
<m:intLim m:val="subSup"/>
<m:naryLim m:val="undOvr"/>
</m:mathPr></w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true"
DefSemiHidden="true" DefQFormat="false" DefPriority="99"
LatentStyleCount="276">
<w:LsdException Locked="false" Priority="0" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Normal"/>
<w:LsdException Locked="false" Priority="9" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="heading 1"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/>
<w:LsdException Locked="false" Priority="39" Name="toc 1"/>
<w:LsdException Locked="false" Priority="39" Name="toc 2"/>
<w:LsdException Locked="false" Priority="39" Name="toc 3"/>
<w:LsdException Locked="false" Priority="39" Name="toc 4"/>
<w:LsdException Locked="false" Priority="39" Name="toc 5"/>
<w:LsdException Locked="false" Priority="39" Name="toc 6"/>
<w:LsdException Locked="false" Priority="39" Name="toc 7"/>
<w:LsdException Locked="false" Priority="39" Name="toc 8"/>
<w:LsdException Locked="false" Priority="39" Name="toc 9"/>
<w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/>
<w:LsdException Locked="false" Priority="10" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Title"/>
<w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/>
<w:LsdException Locked="false" Priority="11" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/>
<w:LsdException Locked="false" Priority="22" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Strong"/>
<w:LsdException Locked="false" Priority="20" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/>
<w:LsdException Locked="false" Priority="59" SemiHidden="false"
UnhideWhenUsed="false" Name="Table Grid"/>
<w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>
<w:LsdException Locked="false" Priority="1" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 1"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 1"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 1"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>
<w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/>
<w:LsdException Locked="false" Priority="34" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>
<w:LsdException Locked="false" Priority="29" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Quote"/>
<w:LsdException Locked="false" Priority="30" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 1"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 1"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 2"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 2"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 2"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 2"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 2"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 3"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 3"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 3"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 3"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 3"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 4"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 4"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 4"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 4"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 4"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 5"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 5"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 5"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 5"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 5"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 6"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 6"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 6"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 6"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 6"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>
<w:LsdException Locked="false" Priority="19" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>
<w:LsdException Locked="false" Priority="21" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>
<w:LsdException Locked="false" Priority="31" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>
<w:LsdException Locked="false" Priority="32" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>
<w:LsdException Locked="false" Priority="33" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>
<w:LsdException Locked="false" Priority="37" Name="Bibliography"/>
<w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/>
</w:LatentStyles>
</xml><![endif]-->
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:10.0pt;
mso-para-margin-left:0cm;
line-height:115%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Palatino Linotype";
mso-ascii-font-family:"Palatino Linotype";
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:"Palatino Linotype";
mso-hansi-theme-font:minor-latin;
mso-ansi-language:EN-US;}
</style>
<![endif]-->
<!--StartFragment-->
<!--EndFragment--><br />
<div class="MsoListParagraphCxSpLast" style="margin-left: 36.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -18.0pt;">
<!--[if !supportLists]--><span style="font-family: Arial, Helvetica, sans-serif;"><span lang="EN-US"><span style="mso-list: Ignore;">·<span style="font-size: 7pt; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;">
</span></span></span><!--[endif]--></span><span lang="EN-US"><span style="font-family: Arial, Helvetica, sans-serif;"><a href="http://www.dddnorth.co.uk/Sessions" target="_blank">DDD North – So you want to be aTech Lead? 10 things you need to do to succeed.</a><br />
18 October 2014</span></span></div>
<div class="MsoListParagraphCxSpLast" style="margin-left: 36.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -18.0pt;">
<span lang="EN-US"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span></div>
<div class="MsoListParagraphCxSpLast" style="margin-left: 36.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -18.0pt;">
<span lang="EN-US"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span></div>
<div class="MsoListParagraphCxSpLast" style="margin-left: 36.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -18.0pt;">
<span lang="EN-US"><span style="font-family: Arial, Helvetica, sans-serif;">See you all there!</span></span></div>
<div class="MsoListParagraphCxSpLast" style="margin-left: 36.0pt; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -18.0pt;">
<span lang="EN-US"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></span></div>
Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-67300460716892076382014-07-01T10:27:00.003+01:002014-07-01T10:27:55.690+01:00Tuesday Quickie - Transforming App.Config<span style="font-family: Verdana, sans-serif;">Another aide-memoire...</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<div style="text-align: center;">
<span style="font-family: Verdana, sans-serif; font-size: large;">By default, app.config files are <b><u><i>NOT</i></u></b> transformed in the same way as web.config files.</span></div>
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">But there's a fix... involving editing the project file (sigh).</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Gunnar Peipmann covers the process in detail here: </span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;"><a href="http://gunnarpeipman.com/2013/11/using-web-config-transforms-with-app-config-files/">http://gunnarpeipman.com/2013/11/using-web-config-transforms-with-app-config-files/</a></span>Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0tag:blogger.com,1999:blog-22825020.post-8695102021350819252014-03-06T10:55:00.000+00:002014-03-06T10:55:48.822+00:00Pushing the Octopus to Chester<span style="font-family: Arial, Helvetica, sans-serif;">Last night I was up in Chester presenting my "Introduction to OctopusDeploy" talk to the <a href="http://twitter.com/chesterdevs" target="_blank">ChesterDevs</a> group - my first real user group presentation (as opposed to DDD or in-work ones).</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">The audience was attentive, asked good questions and were enthusiastic about what OctopusDeploy could bring, so </span><span style="font-family: Arial, Helvetica, sans-serif;">I think it went very well in spite of some technical issues - having to use my MiFi for internet connectivity wasn't ideal and meant I couldn't demonstrate a build pushing to MyGet. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">The post-event chat in the pub was excellent and engaging too - continuing the discussion of how good process can help with delivering better software.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">All the resources for the talk, including the slide-deck, sample solution, etc can be found here:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://github.com/Rammesses/ddd-octopus">https://github.com/Rammesses/ddd-octopus</a></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">I've got to than Fran Hoey for inviting me to talk - my company Landmark Information Group (<a href="http://www.landmark.co.uk/">http://www.landmark.co.uk</a>, <a href="http://twitter.com/LandmarkUK" target="_blank">@LandmarkUK</a>) for letting me take a day out of the office to share our experiences, and to the ChesterDevs audience for their patience and enthusiasm.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />Joel Hammond-Turnerhttp://www.blogger.com/profile/09042429991046814678noreply@blogger.com0