Thursday, September 30, 2021

C# 10 - Implicit (global) usings

Yesterday I thought that my journey in discovering possibilities of the ‘using’ keyword had ended, but further reading introduced me to a new .NET 6 feature: implicit (global) using directives.

You can enable this feature by adding a <ImplicitUsings>enable</ImplicitUsings> setting inside a <PropertyGroup> in your .csproj file.

Remark: The project templates in the .NET 6 SDK include this setting by default

Enabling this feature will automatically generate a global usings file for you. You can see the generated file by looking inside the obj folder that gets created when you build a project. In here you'll find a subfolder named for your build configuration(e.g. Debug, Release, ...) containing a net6.0 folder. Inside there you'll find a file called something like ExampleApp.GlobalUsings.g.cs.

The content of this file will look something like this:

The set of included namespaces changes according to the project type.

You can control what is generated inside this file by adding MSBuild Item Group. To add namespaces you should use the <Using Include />:

And to remove namespaces you can use <Using Remove />:

Wednesday, September 29, 2021

C# 10–Global using

I continue my journey in discovering possibilities of the ‘using’ keyword and arrive at an upcoming feature in C# 10: global using directives.

C# 10.0 allows you to define using directives globally, so that you don’t have to write them in every file. Let’s take a look at a simple example.

I created a GlobalUsings.cs class in my project and added the following 2 lines:

By doing this the 2 namespaces above are available in every C# file in my project.

Remark: In this example I’ve put my global usings in a seperate file. This isn’t necessary, you can put the global usings in any code file, although I would recommend isolating it to make them easier to discover and maintain.

Now I can simplify my Program.cs file:

You can combine this feature with the using static as well:

This allows me to even further simplify my Program.cs file:

More information: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive#global-modifier

Tuesday, September 28, 2021

C#–Using static

While writing my blog post yesterday about class aliases, I was reading through the documentation about the using keyword and noticed another feature I almost forgot: ‘using static’.

Through ‘using static’ you can import static members of types directly into the current scope. This can safe you from some extra typing work if you need a specific static class over and over again.

An example:

In the code above I have to repeat the ‘Console’ static class for each call. Now let’s rewrite this example with the help of ‘using static’:

More information: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive#static-modifier

Monday, September 27, 2021

Confuse your colleagues by using class aliases in C#

C# supports the concept of namespaces aliases for a long time. This allows you to create an alias for long namespaces so you don’t have to specify the whole name every time.

An example:

Did you know that this does not only work for namespaces but also for classes? It is also possible to alias a specific class name.

An example:

This feature could be fun if you start using aliases that match with class names used somewhere else in your codebase. Like in the example above where I assigned the Product class an Order alias. Can’t be any more confusing! So please don’t do this at work and choose a good alias name instead…

Friday, September 24, 2021

Learning the ins and outs of web development through web.dev

If you are new to web development or want to further expand your web development skills , go check out all the learning material provided at web.dev.

At the moment of writing this post, you can find courses about CSS, performance, web frameworks, and much more…

Monday, September 20, 2021

Azure DevOps–Export wiki to PDF

If you ever want to export your Azure DevOps wiki, you can use the AzureDevOps.WikiPDFExport tool.

  • Start by cloning your Azure DevOps wiki to a local folder.

Troubleshooting

While executing the tool I encountered some issues so here are some troubleshooting tips.

Tip 1 – Ignore the Qt: Could not initialize OLE (error 80010106) warning

If you see a Qt: Could not initialize OLE (error 80010106) warning while executing the tool, don’t worry. You can just ignore this message.

Tip 2 – Be aware about the .order file

The first time I executed the tool only a few of my wiki pages were included. I found out that this was the case because when it detects a .order file it will only include the pages mentioned inside the .order file.

So make sure that all wiki pages are mentioned inside the .order file.

Tip 3 – Specify the ‘—attachments-path’ when your wiki pages include images

When trying to export a wiki page containing images it failed with the following error message:

C:\example\Docs>azuredevops-export-wiki

    WARN: Removing Table of contents [[_TOC_]] from pdf

ERR: Something bad happend.

System.ArgumentNullException: Value cannot be null. (Parameter 'path1')

   at System.IO.Path.Combine(String path1, String path2)

   at azuredevops_export_wiki.WikiPDFExporter.CorrectLinksAndImages(MarkdownObject document, FileInfo file, MarkdownFile mf) in D:\Git\WikiPDFExport\AzureDevOps.WikiPDFExport\WikiPDFExporter.cs:line 674

   at azuredevops_export_wiki.WikiPDFExporter.ConvertMarkdownToHTML(List`1 files) in D:\Git\WikiPDFExport\AzureDevOps.WikiPDFExport\WikiPDFExporter.cs:line 497

   at azuredevops_export_wiki.WikiPDFExporter.Export() in D:\Git\WikiPDFExport\AzureDevOps.WikiPDFExport\WikiPDFExporter.cs:line 149

To fix this error I had to include the ‘--attachments-path’ option and explicitly specify the location of the images:

C:\example\Docs>azuredevops-export-wiki --attachments-path C:\example\Docs\.attachments

Tip 4 – Use the –h option for a good TOC

The tool doesn’t support the TOC (Table of Contents) tag and will be removed from the pdf. As a workaround you can use the ‘-h’ option to create a heading for every wiki page in the PDF file. This doesn’t replace this feature but already helps to make your PDF more accessible.

Friday, September 17, 2021

ASP.NET Core: Share a cookie between subdomains

By default when you create a cookie in ASP.NET Core it is only applicable to that specific subdomain.

For example, a cookie created in subdomain.mydomain.com can not be shared with a second subdomain secondsubdomain.mydomain.com.

To change this behavior,  you need to add the following code in Startup.ConfigureServices:

By specifying a common domain in the Cookie.Domain property, the cookie will be shared between subdomain.mydomain.com and secondsubdomain.mydomain.com.

Thursday, September 16, 2021

Azure App Service Health check

Azure App Service has a built-in health check feature. Through this feature Azure can automatically check the health endpoint of your web app and can take an unhealthy instance out of the load balancer until it's healthy again, or even restart or replace it.

To enable Health check, browse to the Azure portal and select your App Service app.

Under Monitoring, select Health check.

Select Enable and provide a valid URL path on your application, such as /hc or /api/health. Click Save.


Remark: Notice the Load balancing slider. Here you can specify the time an app can be unhealthy before being removed from the load balancer.

Azure only looks at the HTTP response the page gives. If the response is in the 2XX range the instance is considered healthy, else it is shown as degraded or unhealthy. It also doesn't follow redirects. If your webapp settings allow http the check by Azure is done over http. If it is set to HTTPS only then Azure used https calls to check the endpoint. In case your health checks return HTTP 307 response make sure you set your webapp to only use https or remove the redirect from your code.

You can further control the Health check behavior through the following appsetings:

  • WEBSITE_HEALTHCHECK_MAXPINGFAILURES : The required number of failed requests for an instance to be deemed unhealthy and removed from the load balancer. For example, when set to 2, your instances will be removed after 2 failed pings. (Default value is 10)
  • WEBSITE_HEALTHCHECK_MAXUNHEALTHYWORKERPERCENT : By default, no more than half of the instances will be excluded from the load balancer at one time to avoid overwhelming the remaining healthy instances. For example, if an App Service Plan is scaled to four instances and three are unhealthy, two will be excluded. The other two instances (one healthy and one unhealthy) will continue to receive requests. In the worst-case scenario where all instances are unhealthy, none will be excluded.

More information: Monitor App Services instances using Health Check

Wednesday, September 15, 2021

Model binding in ASP.NET Core

While converting an existing ASP.NET MVC application to ASP.NET Core I noticed it was using a custom model binder. That made me wonder how I could achieve the same thing in ASP.NET Core.

In ASP.NET MVC a model binder had to implement the IModelBinder interface:

To use the model binder you had to let the ASP.NET MVC framework know the existence of the custom model binder. In the original codebase we were using Unity and we created a small extension method that allowed us to register the Modelbinder:

That extension method allowed us to write the following code:

Let’s find out how to achieve the same result in ASP.NET Core…

In ASP.NET Core you should also implement a IModelBinder interface, although the contract is different(and async):

To use this custom model binder you can either create a custom ModelBinderProvider or use the ModelBinder attribute:

More information: Custom Model Binding in ASP.NET Core

Tuesday, September 14, 2021

Visual Studio Code–Draw.io extension

While pair programming with a colleague I noticed he was using  draw.io directly inside Visual Studio Code. This was made possible by the following extension: https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio

It offers some great features like:

  • Using draw.io offline
  • Work together on a diagram using the liveshare feature of VS Code
  • Link diagram elements to code fragments

I’m a fan!

Monday, September 13, 2021

The ‘async void’ trap

A colleague contacted me that he had trouble using a library I created. This library is used to abstract away the used mailing system. He told me that when the mail couldn’t be send succesfully, the error message got lost and that the library doesn’t return anything useful.

I started by running my integration test suite against this library(these are the moments you are extremely happy that you’ve spend so much time on writing tests) but all tests returned green.

I’ll asked the colleague to send me the code he was using. Do you notice what’s wrong?

The title of this post already gives you the answer. He was using ‘async void’ instead of ‘async Task’. ‘async void’ should only be used by event handlers.

I recommended using AsyncFixer to avoid this kind of issues in the future.

Friday, September 10, 2021

Azure DevOps - User is not available

I got a question from a colleague who was asking how long it took before a user that was added to Azure AD is available in Azure DevOps. The answer is simple; instant.

So why was this person asking this question then? The reason is that there is a difference in behavior depending if the user is already added to the Azure DevOps organisation or not.

If the user is not part of the organisation yet, when you search for the user by firstname and lastname, nothing will be found.

But if you search for the user by his email address, you will find the user.

It is only after the user is added for the first time to an Azure DevOps organisation that you will be able to find a user by his name. Until then you should use the email address to search for the user in Azure AD.

Thursday, September 9, 2021

MassTransit–Message Initializers

Let’s have a look at a small example that shows how to publish a message in MassTransit:

What is maybe not immediatelly obvious in the code above, is that when you call publishEndpoint.Publish<OrderSubmitted> a lot of magic is going on.

The generic argument would make you think that the  Publish method expeccts a message of type OrderSubmitted. But we are passing an anonymous object??? And to make it even stranger, we only have the OrderSubmitted interface, we never created a class that implements it???

What is happening? How this even works? The answer to all this magic are Message Initializers.

When calling the Publish method above, you are using a specific overload:

Task Publish<T>(object values, CancellationToken cancellationToken = default) where T : class;

Message initializers make it easy to produce interface messages using anonymous objects. The message initializers will try to match the values of an anonymous object with the properties of the specified interface. While doing that it can use tricks like type conversions, conversion of list elements, matching nested objects, specify header values and even use invariant variables(guaranteeing that the same value is used everywhere inside a message).

Check out the documentation to learn more about what is possible through message initializers: https://masstransit-project.com/usage/producers.html#message-initializers

 

Wednesday, September 8, 2021

C# switch expressions

A lot of the examples of switch expressions you can find are where a function directly maps to an expression. For example:

This could make you think that you cannot use a switch expression inside a method body. It certainly is possible. The only important thing is that you assign the result of your switch expression to a variable. Let’s rewrite the example above:

Tuesday, September 7, 2021

Copy files through MSBuild

So far I’ve always used xcopy in a pre or post build event to copy files between projects:

But did you know that you don’t need this and that it can be done by standard msbuild features? (By the way the code above doesn’t even work on Linux)

To achieve the same thing you can use the following msbuild configuration in your csproj file:

2 important things to notice:

  1. You can use file patterns in the 'Include' to specify a set of files
  2. You can use ‘LinkBase’ to specify a target folder

Monday, September 6, 2021

Avoid concurrent test runs by using XUnit Collection Fixtures

Last week I blogged about XUnit Collection Fixtures. Something I wasn’t fully aware of but does make sense if you think about it is that by using the [Collection] attribute all tests that share the same context in the same thread. So you don’t need to worry about concurrent test runs.

By default XUnit tests that are part of the same test class will not run in parallel. For example, in the code below Test1 and Test2 will never run at the same time:

If you want to achieve the same behavior while having tests in multiple classes, you can put tests in the same collection:

Friday, September 3, 2021

Troubleshoot Kubernetes deployments

In case your deployments on Kubernetes fails, the following diagram can help:

(It is created by the people from learnk8s who provide Kubernetes training)

A PDF version of this diagram can be found here: https://learnk8s.io/a/a-visual-guide-on-troubleshooting-kubernetes-deployments/troubleshooting-kubernetes.v2.pdf

Thursday, September 2, 2021

XUnit Collection fixtures

While reviewing some XUnit unit tests, I noticed the usage of the [Collection] attribute.

I didn’t know the attribute. So I took a look at the XUnit documentation and discovered the existence of Collection fixtures. It allows you to create a single test context and share it among tests in several test classes, and have it cleaned up after all the tests in the test classes have finished.

In the code I was reviewing it was used to spin up a test server and shut it down after all tests has been completed.

I don’t find it very intuitive how it should be used but it is well explained in the documentation. In case you are too lazy to click on the link, here are the steps:

  • Create the fixture class, and put the startup code in the fixture class constructor. If the fixture class needs to perform cleanup, implement IDisposable on the fixture class, and put the cleanup code in the Dispose() method.
  • Create the collection definition class, decorating it with the [CollectionDefinition] attribute, giving it a unique name that will identify the test collection. Add ICollectionFixture<> to the collection definition class.
  • Add the [Collection] attribute to all the test classes that will be part of the collection, using the unique name you provided to the test collection definition class's [CollectionDefinition] attribute. If the test classes need access to the fixture instance, add it as a constructor argument, and it will be provided automatically.

Wednesday, September 1, 2021

Azure Pipelines - Ubuntu 16.04 LTS environment is deprecated

When trying to run a release pipeline in Azure DevOps, the following warning started to appear for all our builds:

Ubuntu 16.04 LTS environment is deprecated and will be removed on September 20, 2021. Migrate to ubuntu-latest instead.

To get rid of this warning, we had to explicitly specify the vmImage property inside our YAML build template:

More information: https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema%2Cparameter-schema#pool