Performance Improvements in .NET 6

There have been a large number of Performance Improvements in .NET 6 as evidenced in Stephen Toub’s blog post. Most of the time we don’t care about assembly level performance optimisations because the bottleneck is usually accessing some external resource, such as a database or web service.

If you need to benchmark .NET code take a look at a great tool, BenchmarkDotNet and also take a look at the book referenced there, Pro .NET Benchmarking as getting benchmarking correct can sometimes be quite tricky.

If you’re not yet on .NET 6, and you have code in a large loop that you want to squeeze some performance out of it (and it won’t make the code hard to understand and maintain!) here are a couple of simple tips:

  • Testing if n is even: replace (n % 2 == 0) with ((n & 1) == 0)
  • Dividing by 2: replace n / 2 by n >> 1 (but be aware of the unsigned / signed behaviour of right shift)

.NET: Disable Insecure TLS protocols

TLS1.1 and TLS1.0 (and lower) protocols are insecure and should no longer be used.

For .NET 4.7 or later, you do not need to set System.Net.ServicePointManager.SecurityProtocol. The default value (SecurityProtocolType.SystemDefault) allows the operating system to use whatever versions it has been configured for, including any new versions that may not have existed at the time your application was created.

If you want to explicitly code this in .NET, rather than specify the allowed protocols, disable the disallowed protocols before making any connections:

// TLS must be 1.2 or greater. Disable SSL3, TLS1.0 and TLS1.1 [Note: this is the default behaviour for .NET 4.7 or later] 
ServicePointManager.SecurityProtocol &= (~SecurityProtocolType.Ssl3 & ~SecurityProtocolType.Tls & ~SecurityProtocolType.Tls11);


Configurable Retry Logic in Microsoft.Data.SqlClient

Microsoft have recently released a long awaited retry mechanism for .NET SqlClient

I’m a fan of Polly for retry logic:

Polly is a library that allows developers to express resilience and transient fault handling policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner.

It will be interesting to see how they compare in terms of ease of use.

Configurable retry logic in SqlClient introduction

.NET Core Standalone Executable

.NET Core 1.0 came out June 27, 2016. 4 years later, and who knows how many hundreds of thousands of person hours development, I figured it would be quite mature.

On that premise, feeling quite hopeful, I decided to see what’s involved in converting a .NET 4.7.1 standalone console application to .NET Core 3.1, which you’d think would be relatively straight forward.

Three hours later, my 5MB standalone console application has ballooned to 74MB! If you select ‘PublishTrimmed=true’, then the size drops to 44MB but then the application doesn’t work. Apparently, trimming is not able to work out what’s needed, even when reflection isn’t involved.

Turns out even the un-trimmed 74MB app. still doesn’t work as you can’t use the built-in encrypted connection strings section in app.config file. (It hasn’t currently been implemented in .NET Core, along with DbProviderFractory, and a few other surprises…)

I went looking for resources and other people’s experiences converting to .NET Core.

https://docs.microsoft.com/en-us/dotnet/core/porting/
https://docs.microsoft.com/en-us/dotnet/standard/analyzers/api-analyzer
https://github.com/hvanbakel/CsprojToVs2017
https://ianqvist.blogspot.com/2018/01/reducing-size-of-self-contained-net.html

Scott Hanselman gets really excited about making a 13MB+ “Hello world” .Net Core application. He even calls it tiny!! (and that’s after he got it down from 69MB). His post starts out with the line “I’ve always been fascinated by making apps as small as possible, especially in the .NET space.” Irony, or what? In what kind of insane world is a “Hello World!” application 13MB!?!

On a tangential side note; just ditched ILMerge for creating standalone executables. In the past I’ve used Jeffrey Richter’s technique of embedding assemblies in the resource manifest, adding a startup hook to load assemblies into the app. domain at runtime, but like a FOOL, I thought that ILMerge was the ‘better’, more .NETway of doing things.

The amount of pain ILMerge has caused me over the last few years is staggering. It has to be one of the most fragile tools out there. If the planets aren’t aligned it spits the dummy. If there’s ever a problem it spits out an unhelpful cryptic “exited with error X” message. Good luck finding the problem!

Just moved over to using Fody/Costura; it uses that same technique of embedding assemblies in the executable.

It worked the very first time! Unlike ILMerge. As an added bonus it automatically compresses/decompresses assemblies, and my .NET 4.7.1 standalone executable is 2 MB smaller!

Reducing Azure Functions Cold Start Time

You can host a serverless function in Azure in two different modes: Consumption plan and Azure App Service plan. The Consumption plan automatically allocates compute power when your code is running. Your app is scaled out when needed to handle load, and scaled down when code is not running. You don’t have to pay for idle VMs or reserve capacity in advance.

The consumption plan is likely the one you opted to use. You get 1 million free executions and 400,000 GB-s of resource consumption per month and pay-as-you-go pricing beyond that. It can also scale massively. The downside of using the consumption plan is that if there is no activity after five minutes (the default), your code will be unloaded by the Azure Functions host. The next time your function is invoked, your function will be loaded from scratch. I’ve experienced start up times ranging from a few seconds to several minutes.

With version 1.x of Azure functions you can raise the unload functiontimeout to 10 minutes in the host.json settings file.

If you want to keep your functions in memory, you either need to be calling them more frequently than the function timeout setting, or you could create another function in the same app. service plan that gets called periodically using a timer trigger:


using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;

namespace SQLFrontlineLoaderFunctionApp
{
    public static class KeepAliveTimerFunction
    {
        // Timer trigger is in UTC timezone 
        [FunctionName("KeepAliveTimerFunction")]
        public static void Run([TimerTrigger("0 */9 * * * *")]TimerInfo myTimer, TraceWriter log)
        {
            log.Info($"Alive: {DateTime.Now}");
        }
    }
}

This empty function will be called every 9 minutes (“0 */9 * * * *”). You could also keep your functions warm during a certain period during the day. This timer trigger cron expression would run every 9 minutes between 4am and 10am (UTC time zone): TimerTrigger(“0 */9 4-10 * * *”)]

Refs.

Azure Queues: Retry Poison Messages

Currently, the Microsoft Azure Storage Explorer doesn’t have the ability to move messages from one Azure queue to another. During development, I sometimes need to retry messages that are in the poison message queue. A poison message is a message that has exceeded the maximum number of delivery attempts to the application. This happens when a queue-based application cannot process a message because of errors.

It’s not difficult to write, but thought it might save someone a few minutes, so I’m posting it here. You’ll need to add a NuGet package reference to Microsoft.NET.Sdk.Functions


using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;

void Main()
{
    const string queuename = "MyQueueName";

    string storageAccountString = "xxxxxx";

    RetryPoisonMesssages(storageAccountString, queuename);
}

private static int RetryPoisonMesssages(string storageAccountString, string queuename)
{
    CloudQueue targetqueue = GetCloudQueueRef(storageAccountString, queuename);
    CloudQueue poisonqueue = GetCloudQueueRef(storageAccountString, queuename + "-poison");

    int count = 0;
    while (true)
    {
        var msg = poisonqueue.GetMessage();
        if (msg == null)
            break;

        poisonqueue.DeleteMessage(msg);
        targetqueue.AddMessage(msg);
        count++;
    }

    return count;
}

private static CloudQueue GetCloudQueueRef(string storageAccountString, string queuename)
{
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccountString);
    CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
    CloudQueue queue = queueClient.GetQueueReference(queuename);

    return queue;
}

How to send large amounts of data securely

RSA public/private key cryptography is limited in the amount of data that it can encrypt. With the commonly used v1.5 padding and the largest RSA key (currently 2048-bits), the maximum size of data that can be encrypted is 245 bytes.

If you want to encrypt and securely send more data than that you need to use a combination of asymmetric and symmetric encryption algorithms.

In practice, RSA is used to exchange an encrypted key between communicating endpoints that is then used to symmetrically encrypt/decrypt the large data.

Encryption by sender:

  1. Generate a cryptographically strong random key, K, of the length required for a symmetrical encryption technique such as Rijndael (maximum key size is 256 bits for Rijndael).
  2. Symmetrically encrypt your data using Rijndael using the random key generated in step 1.
  3. Using RSA, asymmetrically encrypt the random key generated in step 1 with the public part of the recipient’s RSA key.
  4. Send the RSA encrypted random key AND the encrypted data from steps 2 and 3 to recipient.

Decryption by recipient:

  1. Decrypt the encrypted key using your private RSA key.
  2. Decrypt the original data using the RSA-decrypted symmetric key from step 1.

Here’s how to generate a 2048 bit public/private key in C#:

    using (rsaProvider = new RSACryptoServiceProvider(2048))
    {
        rsaProvider.PersistKeyInCsp = false;

        // Export public key to file
        publicKey = rsaProvider.ToXmlString(false);
        using (publicKeyFile = File.CreateText(publicKeyFileName))
        {
            publicKeyFile.Write(publicKey);
        }

        // Export private/public key pair to file
        privateKey = rsaProvider.ToXmlString(true);
        using (privateKeyFile = File.CreateText(privateKeyFileName))
        {
            privateKeyFile.Write(privateKey);
        }
    }

.NET Framework Design Guidelines (Book Review)

I believe that good technical books fall roughly into 3 categories:

  1. Required reading now but throwaway later: these books go out of date quickly (for instance, that thick copy of plain ASP 3.0, which is now almost completely useless!)
  2. Essential, technology agnostic, lifespan of more than 10 years: containing advice which applies across the board regardless of technology, language or version. These are often process related books. Examples of books in this category are “Code Complete”, and the excellent, recently released “Head First OO A & D” (review to follow shortly).
  3. Essential, technology specific, lifespan hard to measure due to possibility of rapid technology shifts: vital books targeted at some specific technology or language.

The Framework Design Guidelines by Brad Abrams and Krzysztof Cwalina falls mainly into the last category, but also overlaps somewhat with the second.


Who should read this book?

Architects, API and Framework designers, lead developers, junior developers who want to be senior developers(!). Basically, anyone who is designing frameworks or writing code targeting the .NET framework.

The book is divided into 9 chapters and 3 appendices. The guidelines are presented in 4 major forms: Do, Consider, Avoid and Do Not. The authors choose a single language for the examples (which are in C#), which rather being a snub to VB.NET developers is rather more of a complement, as they mention they wanted the book to appeal to the widest audience. A DVD is also included containing several hours of video presentations.

This book represents the condensed wisdom and best practices of literally hundreds of developers, and a number of well known and respected, industry heavyweights have annotated the book, providing discussion and reasoning behind the guidelines.

1. Introduction
This chapter is a brief introduction and discusses the qualities of a well designed framework and the philosophy behind the design. In summary, frameworks are: simple, expensive, full of trade-offs, borrow from previous designs, are designed to evolve, are integrated and last but not least, are consistent.

2. Framework Design Fundamentals
Offers principles and guidelines central to framework design. Talks about scenario-driven design (very similar to TDD), having a low barrier to entry, self documenting wherever possible, the principle of layered architecture, API usability studies.

3. Naming Guidelines
Consistent and accurate naming is an essential principle of designing and writing all code. Krzysztof writes: “The team that develops the .NET Framework Base Class Library spends an enormous amount of time on naming, and considers it to be a crucial part of framework development.” As a consultant, poor method naming is something I see often. As Steven Clarke notes, methods should be named according to what they do, not according to some implementation detail.

4. Type Design Guidelines
This chapter provides general guidelines for the design of types and covers some of the associated subtleties and tradeoffs. This is a heavily annotated chapter, brimming with excellent advice.

5. Member Design
This is one of the slightly longer chapters (57 pages), and follows on from chapter 4, covering basic guidelines that should be followed when designing members of any type. It covers the design of properties, constructors, events, fields, operator overloads, and parameters. I seem to learn something new each time I re-read this and the preceding chapter.

6. Designing for Extensibility
How do you ensure that your framework will be extensible and stand the test of time? This chapter covers unsealed classes, protected members, events and callbacks, virtual members and abstractions. The annotations in this chapter contain several gems of advice, including determining the trade off of extensibility versus performance and some of the subtleties of creating types with virtual members.

7. Exceptions
This chapter is surely the definitive reference for exception handling. It covers the reasoning and benefits behind using exceptions and the best practices in creating and using them within frameworks. Required reading for all developers. [David M Kean posted excellent advice on which exceptions to raise here.]

8. Usage Guidelines
This chapter covers guidelines for the use of common types in publicly accessible APIs, implementing common interfaces and extending common base classes.

9. Common Design Patterns
Chapter 9 does not cover the subject of design patterns in general; rather it discusses a limited set of patterns that are frequently used in the .NET framework.

Conclusion
There is little doubt that a few paragraphs can adequately capture what is contained in the Framework Design Guidelines, or the amount of cumulative effort that has gone into producing this distilled wisdom. If you are a serious .NET developer then you should definitely have access to a copy of this must-read book.

My favourite quotes from the book:
“I have always felt that a key characteristic of a framework must be consistency”, Anders Hejlsberg in the foreword.

“Frameworks must be designed starting from a set of usage scenarios and code samples implementing these scenarios.”