Ahaaas! - August 2020

New month, new exciting moments from my life as a developer. I hope you will enjoy reading about these flashes of clarity, that come suddenly after solving unfamiliar problems. Or as I like to call them - Ahaaas!

.NET

  • Instead of using BlockingCollection, recommended implementation of producer/consumer pattern for .NET Core should utilize Channels. Besides granting full control of number of consumers, it is completely asynchronous and does not lead to thread blocking.

  • If writing a custom ASP.NET Core middleware, pay attention how scoped services are injected. As middlewares are registered as singletons, scoped services cannot be injected via constructor https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write#middleware-dependencies.

  • There is no simple way to resolve implementations of IHostedService or BackgroundService from DI container. Event though hosted services should not be injected into other services, if you absolutely need to, you can do one of the following (ordered by recommendation, from “yes, please” to “why would you do that”):

    • Do not implement IHostedService directly, but create a hosted wrapper which injects your service and activates it on start; inject service elsewhere and not the hosted wrapper.
    • Register service both as hosted service and a singleton; same instance will be resolved when injecting.
    • Inject IEnumerable<IHostedService> and use LINQ to find instance by concrete type.
  • Use the following pattern if you require your event publisher to wait for asynchronous consumers. This can prove useful in case you are testing event driven units and require consumers to complete execution before code following publisher invocation continues. Another example is having application shutdown event, which could wait for consumers before exiting gracefully. Source code was obtained from Stack Overflow but for the life of me I could not find the original question again, hence no direct link :(

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public event Func<T, Task> ItemQueued;

public async Task OnNewItemAsync(T item)
{
if (ItemQueued is null) return;
Func<T, Task> handler = ItemQueued;
Delegate[] invocationList = handler.GetInvocationList();
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<T, Task>)invocationList[i])(item);
}
await Task.WhenAll(handlerTasks);
}
  • When developing server side Blazor application, HTML markup cannot be changed without having to rebuild the whole application. As this is something naturally supported by other SPA frameworks, you can achieve similar behaviour by running application with dotnet watch run. It will react to any change in source files, re-build and re-run application. It is not a perfect method in any way, but removes the need to manually stop, build and run every time.

  • If you use Visual Studio you can have Sass in Blazor! It can be achieved by installing an extension and including a specific NuGet package to projects with .scss files. In VS Code, you can use Live Sass Compiler extension.

  • Having trouble finding NuGet package storage and caches on your PC? Just use dotnet nuget locals all –list to show all relevant paths. Documentation about additional commands for managing NuGet sources can be found here.

  • Selective testing using dotnet test --filter argument https://docs.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests?pivots=xunit.

  • Even though health checks were introduced in ASP.NET Core 2.2, there are certain issues with initial implementation. Majority of them, mostly related to IHealthCheckPublisher host service and options, were fixed in version 3.0. But, if you are still using 2.2, you might want to check issue description and workarounds.

Azure

  • Even if you don’t think you’d need it, I recommend turning on soft delete on all blob storages, for at least a period of 7 days. It is one of few features that can protect you from accidental blob removal, as blob storage is currently not supported by Azure Backup. More details on how to enable this option can be found in official documentation.

  • In order to test timer triggered Azure Functions, Portal can be used to manually invoke them. From the blade of your Function App, go to Functions, select specific function by name, go to Code + Test and click Test\Run button. Function will be immediately invoked and you can even check its log output.

  • If you used official template to deploy Elasticsearch cluster to Azure, be sure to replace data disks on each node. They are deployed as standard HDD by default, but I would recommend using standard or, even better, premium SSD. The price difference is negligible, if you are not using very large disks. Obvious benefit is having query response time reduced by approximately 50%. To replace the disk, simply power down node VM, select data disk from Disks blade and switch it to SSD directly from Portal. Repeat for each node in your cluster.

  • When consuming Azure Service Bus queues/subscriptions, make sure MaxAutoRenewDuration is greater than LockDuration. As best practice, you should leave LockDuration to its default value of 1 minute, and set MaxAutoRenewDuration to maximum time it can take your consumer to process 1 message. If you want to learn more on how Service Bus consumers handle message locking, check this great answer on Stack Overflow.

Containers

  • Found a great online workshop showcasing Docker and Kubernetes for .NET developers https://dak4.net.

  • Virtual Kubelet for Azure Container Instances does not support pod liveness, readiness or startup checks https://github.com/virtual-kubelet/azure-aci. This can seriously limit its usage in production scenarios, as Kubernetes service will not be able to determine pod health. I recommend using ACI kubelet only for bursts of short-running operations. As a bonus piece of information, you can have only 100 ACI instances per subscription, which means virtual kubelet can handle maximum of 100 pods.

  • At the moment it is not possible to turn off performance monitoring for Azure Kubernetes Service. Collection of various logs can be tweaked, but performance telemetry cannot be configured in any way. This can result in not so small charges for data ingested in Log Analytics, especially if running lots of pods, as telemetry is gathered for every single one of them. Only option is to disable monitoring altogether.

Miscellaneous

Azure Functions Deep Dive So you want to be an Azure Solutions Architect Expert - Part 2

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×