Tuesday, 6 February 2018

Span the best part of the .net core 2.1 roadmap

The newly announced .net core 2.1 performance enhancements in build time and Http Client are great, but the best addition is the Span<T> and Memory<T> types in C# 7.2 that follow the low memory allocation fashion started with ValueTask<T> in C#7.
The .net environment has became one of the top contenders performance-wise, and although this new features won't probably be extensively used by most .net developers; now, I can only think of all the services where I could have or will use them.

Thursday, 25 January 2018

Reverse Proxying Kestrel with URL Rewrite for IIS

As said in previous posts, we have been developing new services using Asp.net Core and self-hosting as Windows services using Kestrel. A new interesting problem arised, as Kestrel can not share the Http/Https port with IIS or Owin self hosted services we had to use a different port to host each service. In he past we had this problem when hosting APIs with f# suave, and had overcome it redirecting the requests in the F5 Big Ip load balancer. That solution works, but sometimes I feel like it crosses in to the domain of infrastructure instead of development. So in order to contain all the deployment and configuration in TeamCity/Octopus, I decided to use IIS to reverse proxy the calls made to these microservices as explained in: https://weblogs.asp.net/owscott/creating-a-reverse-proxy-with-url-rewrite-for-iis
Basically requests coming to http://+/newmicroserviceapi/ will be rewritten to http://localhost:<microserviceport>/
This is the Octopus Deploy step I created to automate all this:

PowerShell Script:
$siteName = $OctopusParameters['ReverseProxy.IISSiteName']
$pathBase = $OctopusParameters['ReverseProxy.PathBase']
$port = [int] $OctopusParameters['ReverseProxy.Port']
$site = "iis:\sites\$siteName"
$filterName="Reverse proxy inbound $pathBase"
$filterPath = "system.webServer/rewrite/rules/rule[@name='$filterName']"
Write-Host 'Adding reverse proxy rule to '$siteName' for '$pathBase'/*'
Clear-WebConfiguration -pspath $site -filter $filterPath
Add-WebConfigurationProperty -pspath $site -filter "system.webServer/rewrite/rules" -name "." -value @{name=$filterName; patternSyntax='Regular Expressions'; stopProcessing='True';}
Set-WebConfigurationProperty -pspath $site -filter "$filterPath/match" -name "url" -value "$pathBase/(.*)"
Set-WebConfigurationProperty -pspath $site -filter "$filterPath/conditions" -name "logicalGrouping" -value "MatchAny"
Set-WebConfigurationProperty -pspath $site -filter "$filterPath/action" -name "type" -value "Rewrite"
Set-WebConfigurationProperty -pspath $site -filter "$filterPath/action" -name "url" -value "http://localhost:$port/{R:1}"


Octopus Step:




Note that the Application Request Routing IIS pluging is needed.

Tuesday, 23 January 2018

Refactoring Monolith Services and Git Contribution Stats

Today, a friend was having a look at my GitHub account and asked me about the large number of  private contributions I have. That made me look at the stats myself and then I noticed that I have been committing so much more than I expected to a single repository.
Of course, this is the repository of the "big monolith" my team and I have been refactoring and splitting in to multiple repositories for the last year, and the reason of that many commits to this "soon to be obsolete" repository is the approach we are taking.
Instead of rewriting the functionality in a new service straightaway, I have found that for very complex parts of the system, a good approach is to feature flag the functionality that is being rewritten and then rewrite it in the same solution along the old code using bridges and adapters to interface it. This way we can easily switch back an forth easily from old to new code and it also allows to write tests that can run on both implementations, but mainly it allows for a more progressive and less aggressive rewriting of the functionality.
A small trick is to create all the new projects in the same folder, that way when the code is stable enough, that folder can be split in to a new repository maintaining the history.

Sunday, 21 January 2018

Asynchronously wait for Task to complete with timeout

This week I found the following code in Stack Overflow to await for the completion of an async operation with a timeout and really liked the solution.

  int timeout = 1000;
  var task = SomeOperationAsync();
  if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
      // task completed within timeout
  } else {
      // timeout logic  
  }

MongoDB c# driver debugging

With the older versions of MongoDb c# drivers it was easy to convert to string any Mongo Update or Query generated using the driver. But with the introduction of the MongoDB.Driver.Builders<T> this useful functionality when debugging or troubleshooting is not as straightforward as before, but researching a bit I was able to found how to get the Bson representation of the query/update:

public static class MongoBuildersTestingExtensions
{
public static string RenderToString<T>(this UpdateDefinition<T> updateDefinition)
    {
var serializerRegistry = BsonSerializer.SerializerRegistry;
var documentSerializer = serializerRegistry.GetSerializer<T>();
var rendered = updateDefinition.Render(documentSerializer, serializerRegistry);
return rendered.ToString();
}
}

Thursday, 4 January 2018

Longer, slower and lazy path back to the start

Right before Christmas holidays I started some work on a new microservice and agreed with the team to use Asp.net Core on the .net Framework as it was a good opportunity to start introducing Asp.net Core in our stack without having to go to .net core straight away.
This morning I came back from my two weeks off just to find out that one of the guys had expended a considerable amount of time trying to setup a build in Teamcity for this solution only to give up and then "downgrade" it to Asp.net; and the worst part is that it wasn't because of a tight deadline and the code had not advanced much from the version I had left....
After taking a deep breath, and having a chat with the other members of the team that weren't on holiday we decided to use Asp.net Core again. As I predicted, getting the build to work in Teamcity was fairly straightforward as I had already installed and configured the agents a while ago when I was working on some Akka.net .net core projects. 
Unsurprisingly, most of the effort went into "rolling back" the downgrade and removing packages for injection of dependencies and logging that are not longer needed. So I'll keep my "fight" on for the team to learn and use new technologies where it makes sense instead of sticking to the "same old" out of pure laziness...

Tuesday, 19 December 2017

IIS and certificates

The other day the last "pure" DevOps engineer in our team left the company, so what is left of the team is filling that role.
One of the tasks that was left pending was to use SSL termination instead of having the certificates installed in each server, and surprise, surprise, the expiration date of the active certificate is within a week of writing this post.
So instead of addressing this issue properly, we decided to just add the new certificate. For that I created an Octopus Deploy project that simply runs the following powershell script:

$base64Certificate = $OctopusParameters['Base64Certificate']
$password = $OctopusParameters['Password']
Write-Host "Adding/updating certificate in store"
$certBytes = [System.Convert]::FromBase64String($base64Certificate)
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certBytes, $password, "Exportable,PersistKeySet,MachineKeySet")
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My", "LocalMachine")
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()

I had worked previously with certificates to sign and validate requests in webservices, and we simply referred to the certificate using distinct properties but not the certificate thumbprint, as that would force configuration to be updated when the certificate expires. That is why I was surprised of not finding a way to do the same in IIS, originally, the only way I found to bind the SSL port to a certificate was to specify the thumbprint. So I added the following step using netsh (https://msdn.microsoft.com/en-us/library/windows/desktop/cc307236(v=vs.85).aspx).

$port = [int] $OctopusParameters['Port']
$certThumbprint = $OctopusParameters['CertThumbprint']
$output = netsh http show sslcert ipport=0.0.0.0:$port | Out-String
Write-Host "Previous configuration: $output"
Write-Host "Remove ssl certificate port binding"
$output = netsh http delete sslcert ipport=0.0.0.0:$port | Out-String
if(($output -like "*Error*") -and ($output -notlike "*Error: 183*"))
{
    exit 1
}
Write-Host "Ensuring ssl certificate port binding"
$guid = [guid]::NewGuid()
$guidStr = "{$guid}"
$output = netsh http add sslcert ipport=0.0.0.0:$port certhash=$certThumbprint appid=$guidStr | Out-String
Write-Host $output
if(($output -like "*Error*") -and ($output -notlike "*Error: 183*"))
{
    exit 1
}
$output = netsh http show sslcert ipport=0.0.0.0:$port | Out-String
Write-Host "New configuration: $output"
exit 0

Later I found that IIS provides an option to automatically rebind renewed certificates, but I didn't went for that option as it would mean enabling it and wait for the expiration date to trigger the switch over without having seen it working beforehand. Instead, I have set up one of the lower environment boxes to use this method.