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...