I was recently investigating a piece of non-performant code that essentially boiled down to a loop that pulled items off a “working list”, and when the work was done, removed it from the list. Now even me describing this code now you’re probably thinking.. Well that sounds like a “Queue” type. And you would be right, it basically is a queue but written using a List object.

Maybe this sounds like a real rookie mistake, but there is definitely a common theme among C# developers (myself included), that use List as basically the catch all for any sort of collection. Arrays, queues, stacks and pipelines are all pretty much non-existent in any sort of business logic code I write, and as we’re about to find out, maybe that’s to my own detriment.

Back to the code I was talking about, it looked something like this :

//Somewhere in the code we add a bunch of items to the working list. 
var workingList = new List<object>();
workingList.Add(new object());

//And then later on we have a loop that looks like so : 
while(workingList.Any())
{
    var item = workingList.First();
    workingList.Remove(item);
    //do some work
}

Immediately looking at this code I realized it’s basically a makeshift queue built ontop of a list type, but with some clear performance issues in mind. Just how much performance can be squeezed out of this we will certainly delve into, but let’s look at the problems of this code in a nutshell.

  1. We have a call to “Any()” to check if we have items. This is probably pretty fast, but we do this as an additional check rather than just trying to “pop” an item immediately.
  2. We remove the item from the front of the list. This actually means that the list itself all shifts up 1 place, a much larger operation than I first thought.
  3. Our removing code requires us to compare object references within the list rather than remove it by index (Although this is the least of our problems).

Just touching on number 3, we could instead change the remove line to be :

workingList.RemoveAt(0);

But that’s not our actual issue.

The problem is we are trying to use a List type for a job that is clearly suited to Queue. But how much faster would Queue actually be? What if we only have a hundred items? Is there actually any noticeable difference?

Well, there’s an easy way to solve this using BenchmarkDotNet.

Here’s my benchmark that I set up :

[SimpleJob(RuntimeMoniker.NetCoreApp31)]
public class QueueVsListBenchmark
{
    [Params(100, 1000, 10000)]
    public int size;

    private Queue<object> queue = new Queue<object>();
    private List<object> list = new List<object>();

    [IterationSetup]
    public void Setup()
    {
        queue = new Queue<object>();
        list = new List<object>();
    }

    [Benchmark]
    public void ComputeQueue()
    { 
        for(int i=0; i < size; i++)
        {
            queue.Enqueue(new object());
        }

        while(queue.TryDequeue(out var item))
        {
        }
    }

    [Benchmark(Baseline = true)]
    public void ComputeList()
    {
        for (int i = 0; i < size; i++)
        {
            list.Add(new object());
        }

        while(list.Any())
        {
            var item = list.First();
            list.Remove(item);
        }
    }
}

Not too complicated. We simply insert X amount of items, and then dequeue until we are done. We also have different sizes of queues to just compare how the size of the queue may affect the performance.

And the results?

|       Method |  size |          Mean | Ratio |
|------------- |------ |--------------:|------:|
| ComputeQueue |   100 |      4.080 us |  0.19 |
|  ComputeList |   100 |     21.917 us |  1.00 |
|              |       |               |       |
| ComputeQueue |  1000 |     28.066 us |  0.12 |
|  ComputeList |  1000 |    242.496 us |  1.00 |
|              |       |               |       | 
| ComputeQueue | 10000 |    205.809 us |  0.02 |
|  ComputeList | 10000 | 10,033.700 us |  1.00 |

So swapping a queue, even at a relatively small size of 100 items, is 5x faster. And the larger the queue, the more performance we can squeeze out of not using a list.

Now is this over thinking everything? Maybe. But it’s one I’m very comfortable with. Not only is performance that much better using a queue, but it’s actually the right data type anyway. We aren’t doing some “hack” to squeeze juice out of it. We are actually using the correct data type for the correct use. Anyone looking at our code and seeing a “Queue” type is going to know exactly what it’s doing.

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

Some time back I wrote a post specifically on writing PDFs in C#/.NET Core. At the time, I had very specific requirements for turning an HTML file into a PDF and was really looking for the cheapest library that fit the bill, regardless of how much effort I had to do to get it working. I think I probably underestimated how bad support for generating PDFs actually was in C#. It turned into a maze of open source libraries that “kinda” worked complete with Github issue trackers that hadn’t been answered in years, all the way to paid libraries with seemingly black hole support.

Well a continual thing that came out of that post was people asking me “But.. doesn’t Adobe do this for you?”. At the time as I understood it, Adobe did not have an programming interface at all for PDF’s, they were just dealing with desktop software. But as it turns out, that’s because they partnered with a company called Datalogics who are their official vendor for a C# PDF SDK.

Better yet, Datalogics just announced their support for .NET Core and actual support for non-Windows environments. e.g. Linux. I put that in bold because people left comments on my previous post saying that even though a company said they supported Linux, they were actually just guessing and didn’t actually provide any support for it. So naturally, with my past post giving a few open source options and third party companies selling their own SDK, it makes sense to try the real deal.

Getting Started

You can head over to Datalogics and grab a free trial here : https://www.datalogics.com/products/pdf-sdks/adobe-pdf-library/. It looks scary filling in the contact form but don’t worry, you get an automated email back with all the details on how to grab the library immediately without having someone calling you 15 seconds after you hit submit.

As part of the download, you are given a package with over 70 sample projects that demonstrate how the library works! It’s actually somewhat refreshing to be given that many sample apps that work right out of the box without having to muck about working out how all the pieces fit together. Not only are all the sample applications there, but all the sample PDF’s with their own features (For example, a PDF with images to show image extraction) are all their ready for you to just run and step through the code.

Better yet, chances are one of these sample apps are exactly what you are looking for a PDF library for. Just an example of the sort of samples you get :

  • A WinForms application showing opening PDF’s, viewing and being able to edit them inside a Winforms control.
  • A simple console application that showcases true text redaction (Not just dark rectangles drawn over the top of a PDF)
  • An application to extract text from PDF’s that is among one of the best I’ve seen
  • An OCR application that reads text from images and adds them to a PDF file (To be honest, forget the PDF writing, this was easily the most impressive sample here!)

If you are interested, you can even view the sample code/applications here : https://dev.datalogics.com/adobe-pdf-library/sample-program-descriptions/net-sample-programs/working-with-actions-in-pdf-files/ to see if it does what you need before even jumping in.

While Datalogics do have a library for turning an HTML file into a PDF, I want to look at maybe some of the more complex sample applications and see just how good they are.

PDF Visual Editor

Yes OK, this is .NET Framework (for now) as most WinForm apps are, but I do want to touch on it because I found it pretty impressive to use and was probably the feature that I hadn’t seen before in a PDF library for C#. I think most SDK’s focus on manipulating PDF’s from code and any samples given are all in the form of console applications. So it was a bit of a change of pace to fire up an actual GUI application that showcases PDF editing functionality.

(Ignore the actual PDF in the screenshot, my partner has been getting a bit too much into cross stitch lately!)

This is the sample application that comes with the library, built in .NET, and has the ability to both read PDF’s and even edit them on the fly. See what I mean when I say that the samples are pretty good? This is a fully fledged application that even if you needed just one of these features, be it just be viewing a PDF in a WinForms application, editing a PDF, printing, whatever it may be! This application has the code right there in front of you for you to debug and actually use.

Redacting Text Inside A PDF

A really impressive example app in the sample suite is a small console application that redacts text. I actually went back and checked other PDF libraries for C#, both paid and free, and I couldn’t find any tools for redacting text inside a PDF. More importantly, redacting text is *not* simply drawing a rectangle over a word and calling it a day.

Quite famously, in the Mueller investigation vs Paul Manafort, a “redacted” legal response was released to the public that you could literally just copy and paste the “black box” into a notepad doc and read all of the “redacted” text. (Further reading here on that fail : https://www.vice.com/en_us/article/8xpye3/paul-manafort-russia-case-redaction-fail).

The sample application uses a simple weather PDF that will redacts all instances of the word “cloudy”. Impressively it actually outputs two sample documents, the first is it finding all instances of the word and drawing a box where it’s found it, and then another completely redacted version.

Before

After Identifying

After Redaction

And again, this is not simply drawing a a rectangle over it MSPaint style, this is truly identifying the text and redacting it completely.

Extracting Text From A PDF

I guess this is basically a staple for all PDF SDK’s, but I was really impressed with the quality from the Datalogics SDK. Again, they have a great sample application to show you what it can do.

Take this PDF section for example, it’s on Page 5 of a sample PDF.

And the text output :

Now I kinda get that all this is doing is reading text from a PDF and that doesn’t sound that impressive. But I found other libraries (Especially free ones), basically read the text as one big long string and gave you that. The entire structure of the page was lost, especially the line breaks.

On a previous project of mine I was tasked to build an application that given the page and line number of a PDF, I had to extract out the text. Can you imagine the headaches when the entire structure of the PDF is lost and I have to come up with all sorts of crazy ways of reverse engineering the line number? I love a library that does what it says on the tin.

Image PDF OCR

Is it weird that a PDF library impresses me the most by showcasing it’s image optical character recognition powers (OCR)? This thing actually blew my mind.

In the sample, they give you a PDF that is one big image, including tables :

Again, this is an image inside a PDF. You cannot highlight this text or copy it out. Nor can you use any old PDF reader to actually “read” the text because the text isn’t actually there. It’s an image. Then the sample application reads all text inside the PDF, re-does the entire PDF, and resaves it including the table, but with the text now OCR’d and input as actual text and not an image.

So you can now copy out the text just like you could if it was text inside a PDF in the first place. There just something crazy about the fact that it can not only OCR the text, but then also recognize the fact that text is inside a table etc and basically redraw everything pixel perfect, but now with the text perfectly selectable.

In the screenshot above, it does look like the text is sort of disjointed, but I can assure you when you copy that text out it’s a complete sentence in order :

Required)The type of annotation that this dictionary describes;
must be Redact for a redaction ann

Part of the reason this is so impressive to me is because I’ve actually been part of teams that have attempted to OCR billing invoices. Where there are tables of charges as an image, inside a PDF, and we are trying to read the line items from invoices to input them into a database. It took months of work and in some cases, we just said “can’t be done”. But I would love to give it another try with this library.

Who Is This Library For?

So here’s the thing. It’s not free. Let’s just get that out of the way. But this is easily the most comprehensive, if not *the* most comprehensive PDF library I’ve used. For extremely simple applications that turn a pretty plain HTML file into a PDF, yeah maybe it’s not for you. But there were features in this library that I hadn’t seen anywhere else, and had actual working examples for you to just copy and paste into your own application.

The thing that most surprised me about my previous post on PDF support in C#/.NET Core is just the share amount of libraries that didn’t even do what they say on the tin. It was this sort of mish-mash of partly working features and zero support. If you’re working on a business critical piece of functionality that involves PDF’s (e.g. Generating thousands of invoices that cannot be delayed due to you waiting for a response on your Github issue), then the Datalogics C# SDK might just be right for you.


This is a sponsored post however all opinions are mine and mine alone. 

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

This little “warning” has been the bain of my life recently…

warning CS1998: This async method lacks ‘await’ operators and will run synchronously. Consider using the ‘await’ operator to await non-blocking API calls, or ‘await Task.Run(…)’ to do CPU-bound work on a background thread.

And after a bit of searching around, I just wanted to touch on it because I think it’s a fairly common warning in C# code, and one that can either point to imminent danger, or be absolutely meaningless depending on your code. And it seems like there are all sorts of hokey “fixes” that don’t address why this happens in the first place.

Why/Where This Happens

The most common place I’ve seen code like this is where I’ve had to implement an interface that expects that your method likely needs to be async, but you don’t actually need anything async.

As an example, I had an interface for “validating” accounts. Something like so :

public interface IAccountValidator
{
    Task Validate(Account account);
}

But one of my implementations for this code was simply checking if the username was “admin” or not.

public class AccountValidatorRestrictedAdmin : IAccountValidator
{
    public async Task Validate(Account account)
    {
        if (account.Username == "admin")
            throw new Exception("Unable to use username admin");
    }
}

Now this particular piece of code is not async and does not contain async code. But other validators *are* async. So I run into a warning for this method. Oof. There isn’t really a great way to avoid this sort of implementation because

  1. Creating non-async code upfront is likely to come back and bite me later if I actually do need to be async. Since we try and preach “async all the way down”, to then break this will be a pain.
  2. I don’t want to have two different methods/interfaces, one async and the other sync to do the same thing.

Now actually, this warning can be “ignored” (Well.. Kinda) in most cases…..

The Imminent Danger Code

Before we get into the talk of where this warning isn’t a problem, let’s talk about the warning where your code is going to blow up.

Suppose I have the following method :

public async Task Validate(Account account)
{
    CheckSomethingAsync();
}

Where CheckSomethingAync() truly is async. Then I’m going to get the same warning again, but I’m also going to get another.

Warning CS4014 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the ‘await’ operator to the result of the call.

These often come in two’s because one is saying that your method is async, but doesn’t await anything. But the second one tells you exactly why that is the case, because you’re actually *calling* an async method, but not awaiting it. This is generally speaking, a warning that *cannot* be ignored.

I’ll repeat, if you get warning CS4014 saying that an actual call is not awaited, in almost all cases your code requires an await somewhere and you should fix it!

The Overheads of Async/Await

Now if you’ve made it this far, and your code isn’t in the danger zone, we can talk about why exactly you get the warning on an async method running synchronously. After all, if a method is marked as async, and it runs sync, is there really a problem?

I really don’t profess to be an expert in all things async. In fact, all I really know on the subject is from a pluralsight course from Jon Skeet dating back to ~2016 (Which by the way, has since been taken down which is a great shame because it was incredible!). But from what I can tell, there is no actual issue with a method marked as async, that does not call async methods.

The only thing that I could find is that when you have a method like so :

public async Task Validate(Account account)
{
    if (account.Username == "admin")
        throw new Exception("Unable to use username admin");
}

There is an overhead in creating the state machine for an asynchronous method that won’t ever be used. I really couldn’t find much by way of measuring this overhead, but I think it’s relatively safe to say that it’s minimal as it would be the same overhead if your method was actually async.

So I feel nervous coming to this conclusion but generally speaking, other than the annoying warning, I can’t find anything dangerous about this code and it seems to me to be relatively safe to ignore (As long as you don’t have the second error labelled above!)

Using Task.FromResult/Task.CompletedTask

Many guides on this warning point to the usage of Task.FromResult to hide it. For example :

public Task Validate(Account account)
{
    if (account.Username == "admin")
        throw new Exception("Unable to use username admin");

    return Task.CompletedTask;
}

Instead of the method being async, it still returns a Task (To conform with an interface as an example), but instead returns Task.CompletedTask. If you have to return a result, then returning Task.FromResult() is also a valid way to do this.

This works but, to me it makes the code look bizarre. Returning empty tasks or values wrapped in tasks implies that my code is a lot more complicated than it actually is. Just in my opinion of course, but it is a suitable way of getting rid of the warning.

Suppressing Warnings

This is going to see my be eaten alive on Twitter I’m sure, but you can also supress the warnings in your project if you are sure that they are of no help to you.

To do so, edit your csproj file and add the following :

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <NoWarn>1998</NoWarn>
  </PropertyGroup>
...
</Project>

Where 1998 is the original warning code. Again, *do not add 4014* as this, in almost all cases, is an example of code that’s about to blow up in your face.

Do Not Task.Yield()

Finally, the absolute worst thing to do is to add a “do nothing” Task.Yield().

public async Task Validate(Account account)
{
    if (account.Username == "admin")
        throw new Exception("Unable to use username admin");

    await Task.Yield();
}

This also gets rid of the warning, but is incredibly bad for performance. You see, when you call await, in some cases it may not need to “juggle” the process at all. It may just be able to continue along the execution path. However when you call Task.Yield(), you actually force the code to await. It’s no longer an “option”.

If that doesn’t make too much sense, that’s OK, it doesn’t really make much sense when I say it out loud either. But just know that adding a Task.Yield() for the sole purpose of bypassing a warning in your code is up there in terms of the worst things you can do.

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

Since the early days of C# 9, I’ve been doing writeups on all of the new features including init-only properties, record types, top level programs and more. And ever since those writeups, I’ve had people say “Yeah, I get I can read that, but can you just give me the gist of how to use the feature?”. I thought that a single page writeup would be short enough but I do get that it’s sometimes easier to explain in a 1 minute video. And so that’s what I’ve done!

I’ve created a completely free C# 9 video course that walks you through all of the features at a high level, to get you up and running as soon as possible. There’s no waffle. There’s no me writing screeds of code on video while you wait for me to get to the point. They are all one take wonders of me doing my best explanation of every C# 9 feature I can think of. And best of all, you can watch the entire series on your lunch break and come back in the afternoon ready to put C# 9 into action.

Interested? Grab the videos here for free!




Watch Now

If you are more of a text person, again, all of the information is available in posts below  :

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

So anyone who uses Entity Framework/EF Core knows that you can run migrations from powershell/package manager console like so :

Update-Database

And you probably also know that with EF Core, you can also use the dotnet ef command like so :

dotnet ef database update

But in rare cases, you may have a need to run migrations on demand from your C#/.NET Core code, possibly by calling an API endpoint or from an admin screen. This was generally more of an issue in older versions of Entity Framework that had real issues with the “version” of the database versus the “version” that the EF Code thought it should be. Infact, put simply, it would bomb out.

In EF Core, this is less of an issue as your code won’t die until it actually tries to do something that it can’t complete (e.g. Select a column that doesn’t exist yet). But there are still some cases where you want to deploy code, test it works in a staging environment against the live database, *then* run database migrations on demand.

Migrating EF Core Database From C#

It’s actually very simple.

var migrator = _context.Database.GetService<IMigrator>();
await migrator.MigrateAsync();

Where _context is simply your database context. That’s it! Crazy crazy simple!

Checking Pending Migrations

It can also be extremely handy checking which migrations need to be run before attempting to run them. Even then, it can be useful to know which state the database is in from an admin panel or similar just to diagnose production issues. For example, if you roll a manual process of updating the production database, it can be useful to see if it’s actually up to date.

await _context.Database.GetPendingMigrationsAsync()

Really simple stuff.

Migrating EF Core On App Startup

In some cases, you really don’t care when migrations are run, you just want them to migrate the database when the app starts. This is good for projects that the timing of the database migration really doesn’t matter or is an incredibly small rollout window. For example, a single machine of a low use web app probably doesn’t need all the bells and whistles for a separate database rollout, it just needs to be on the latest version at any given time.

For that, .NET Core has this new paradigm of a “StartupFilter”. The code looks like so :

public class MigrationStartupFilter<TContext> : IStartupFilter where TContext : DbContext
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return app =>
        {
            using (var scope = app.ApplicationServices.CreateScope())
            {
                foreach (var context in scope.ServiceProvider.GetServices<TContext>())
                {
                    context.Database.SetCommandTimeout(160);
                    context.Database.Migrate();
                }
            }
            next(app);
        };
    }
}

Startup Filters in .NET Core are basically like Filters in MVC. They intercept the startup process and do “something” before the application starts, and only on startup. I actually haven’t made much use of them in the past but recently I’ve found them to be incredibly handy. If you ever made use of the global.asax startup methods in Full Framework .NET, then this is pretty similar.

We can then add our this filter to our startup pipeline by editing our startup.cs file like so :

services.AddTransient<IStartupFilter, MigrationStartupFilter<Context>>();

Where Context is our database context. Again, super simple stuff but something that you’ll probably end up using in every new project from now on!

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

Getting Setup With C# 9

If you aren’t sure you are using C# 9 and/or you want to start using some of the new shiny features in the C# language, be sure to read our quick guide on getting setup with C# 9 and .NET 5. Any feature written about here is available in the latest C# 9 preview and is not a “theoretical” feature, it’s ready to go!

C# 9 Features

We are slowly working our way through all new C# 9 features, if you are interested in other new additions to the language, check out some of the posts below.

Free C# 9 Video Course

Are you one of those people that sees a big wall of text on a programming blog and instantly tunes out? Well you aren’t alone! In fact, I got hassled so much with people asking me “Can’t you just quickly share your screen and show me?” rather than reading a blog post, I decided I may as well quickly record the need to know bits of C# 9. So that’s what I’ve done!

My “What’s New In C# 9” course is completely free and will get you up and using C# 9 features in less than an hour (seriously!). Did I mention it’s FREE?

Watch For Free Now!

Init-Only Properties In C# 9

Before we go much further, I highly recommend reading our guide on Init-Only Properties in C# 9 here. Record types in C# 9 are borderline an extension of the level of immutability that init-only properties give, and so much of this article will refer back to that.

Record Types Crash Course

The gist of a record type is that it provides an easier way to use the immutability features within C# 9 (init) and provides better equality comparisons…. Or that’s the theory anyway.  I will say that everything within this guide is working right now in the latest SDK. I’ve read a bunch of tutorials that are simply wrong or don’t work.(mini rant) It happens every single C# release where people want to be the first to do a writeup about something that they do guides with “pesudocode”.

I think as well it’s more frustrating than ever with Records because everyone is just copy and pasting the happy path given out in the .NET Core announcements. Rather than actually playing with the code and seeing what it actually does, and where it’s short comings are.

Anyway. Back to records! If we look at a simple record definition like so :

public record Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Now if you wrote code like so, you might expect it to throw an exception (Because everyone is talking about how records are immutable!)  :

var person = new Person();
person.Name = "John Smith";//No Exception

But it doesn’t.

We’ll soon find out how to make it throw an error but it’s a little confusing when you first start using Records because everyone has talked about immutability and how records solve that problem when in reality, they only solve it in very specific scenarios. Depending on which documentation you read, it can be very confusing.

I found a good Github Issue against the dotnet docs here : https://github.com/dotnet/docs/issues/20601 that goes into some of the confusing wording. I think that the idea is that Records *help* you write immutable code, but records themselves are actually not always immutable.

I think the best comment on how to change the docs was this :

It would be good to word it so that no one can come away thinking “if I see a record, I know it’s immutable.”

Which is totally true. Records *can* be immutable, but not always (Like our example above).

To make each property be immutable, with an error, you have to make each property use the init keyword like so :

public record Person
{
    public string Name { get; init; }
    public int Age { get; init; }
}

Now I saw some writeups claim that you can simply do this :

public record Person
{
    string Name;
    int Age;
}

The thinking behind it is that every property on a record is automatically public (Kinda like an interface property), and then every property automatically has a get and init accessor placed on it if you don’t specify. This doesn’t work for me. I don’t know if it worked in a previous version, or people just wrote what they “thought” it should do, but this certainly doesn’t work on the latest SDK.

With that all being said this shorthand way of defining a record *does* work.

public record Person(string Name, int Age);

And this code now throws (two) errors :

var person = new Person(); // Throws an exception because you need to provide the constructor values
person.Name = "John Smith";//Throws an exception because you cannot assign an init only property after creation

There is a small caveat that for some reason, whenever I started writing this syntax, my Visual Studio would crash! This was version 16.7.1, once I upgraded to 16.7.4.. Suddenly I could write shorthand records without Visual Studio restarting on me which was nice.

If you read the arguments around immutability and you hear people say “It’s only immutable when it’s a positional record”, this is what they mean. Why positional? Because it’s dependent on the constructor positioning, for example this does not work :

var person = new Person //Error that we haven't used the constructor and given the Name. 
{
    Name = "John Smith", 
    Age = 30
};

If you want to be able to use the object initializer syntax instead of the constructor syntax, then you need to create your record completely, and provide the init only accessors on your properties that you want to be immutable…. It’s kinda… meh.

It may seem like I’m down on Records, and.. In some ways I am. There are lots of caveats that make me feel like the the entire premise of Records don’t quite work the way I would expect. I’m almost certain that in C# 10, there will be all sorts of improvements and then we will all be happy. Sort of like when (Value)Tuples were added to C# and you had to use .Item1 and Item2 etc and people were pretty horrified, then they added Named Tuples and everything was fine (More reading here : https://dotnetcoretutorials.com/2020/01/06/intro-to-c-tuples/).

Record Equality

All this talk of immutability with Records has meant that the equality features have sort of skipped by. And it’s interesting because you could create records, that are not immutable at all, just to use the equality features.

Let me demonstrate. If we create a class and a record that are essentially identical :

public class PersonClass
{
    public PersonClass(string name, int age)
    {
        this.Name = name;
        this.Age = age;
    }

    public string Name { get; init; }
    public int Age { get; init; }
}

public record Person(string Name, int Age);

Then say we have the following code :

var personClassA = new PersonClass("Jim", 30);
var personClassB = new PersonClass("Jim", 30);

Console.WriteLine(personClassA.Equals(personClassB));

var personRecordA = new Person("Jim", 30);
var personRecordB = new Person("Jim", 30);

Console.WriteLine(personRecordA.Equals(personRecordB));

The output will be False then True. Comparing two classes will check the reference of those two objects. Even if the values within those classes are the same, they will not be equal. Records are different in that equality is done using the values within that record. This is some compiler magic behind the scenes but essentially it’s comparing each of your properties one by one to make sure their *values* are the same.

You can override how a record checks it’s equality… But you cannot do so with the shorthand syntax. You need to write out the full record defintion again :

public record Person : IEquatable
{
    public Person(string name, int age)
    {
        this.Name = name;
        this.Age = age;
    }

    public string Name { get; init; }
    public int Age { get; init; }

    public virtual bool Equals(Person person2)
    {
        return this.Name == person2.Name;
    }
}

And then this code, even with the Age property being different :

var personRecordA = new Person("Jim", 30);
var personRecordB = new Person("Jim", 31);

Console.WriteLine(personRecordA.Equals(personRecordB));

Will still return True.

But this is somewhat daft because at this point, there is very little difference between a class and a record (If any at all to be honest). While records give you helpful ways to do immutability and compare by value.. You have to opt in to some less than ideal scenarios (Must use a constructor, must compare all property values for equality).

I would also note that this also does not work :

var personRecordA = new Person("Jim", 30);
var personRecordB = new Person("Jim", 30);

Console.WriteLine(personRecordA.Equals(personRecordB)); //Returns True
Console.WriteLine(personRecordA == personRecordB); //Returns False

For that you need to override the operator ==, which also requires you to override the operator !=

public record Person : IEquatable
{
    public Person(string name, int age)
    {
        this.Name = name;
        this.Age = age;
    }

    public string Name { get; init; }
    public int Age { get; init; }

    public virtual bool Equals(Person person2)
    {
        return this.Name == person2.Name;
    }

    public static bool operator==(Person person1, Person person2)
    {
        return person1.Equals(person2);
    }

    public static bool operator!=(Person person1, Person person2)
    {
        return !person1.Equals(person2);
    }
}

Note that this is even if you don’t write your own equality operator. Even by default, records do not override the == operator which.. IMO is maybe the wrong decision and probably one that can’t be changed now. But it’s very confusing when personA==personB returns false, but personA.Equals(personB) returns true.

Using The “with” Keyword With Records

Let’s say you have a record with a dozen properties, all init only, and you want to create a new record with only one change. You would have to write out a massively long constructor taking each property from the existing record, and then drop in your one change. Kinda messy.

But there is a helper using the “with” keyword.

var personRecordA = new Person("Jim", 30);
var personRecordB = personRecordA with { Age = 31 };

This means it takes all the values of personRecordA, and creates a new Record with the Age changed. This feature I actually find pretty handy and honestly I wouldn’t be surprised if this was extended to other types (classes and structs) because I think it’s very very handy.

Should You Use Records?

I’ll be the first to admit it’s hard for me to grasp records because in general, immutability hasn’t been big on my wishlist. I personally don’t develop all that much in F#, or use other languages with immutable “record” types, so it’s sometimes hard for my to envisage where I would use them.

But I think that’s made worse by the fact that Records act very differently simply based on whether you use a shorthand syntax or not. The promised features of records actually only happen if you use records in a very precise way, otherwise you’re more or less just using a class. And I think that’s somewhat the problem here, is that the immutability features of records, you can get in a class anyway.

Let me know in the comments where you’ve used Records, or your intended use cases because, as I say, my experience on the need for immutable records is very very small.

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

While mentoring a junior developer and trying to help them understand dependency injection, I came across a topic that I didn’t find a really great explanation out there on the internet. That is, when you end up with circular references while using dependency injection.

I found that there was some great resources at understanding circular references in general, and obviously great articles on the .NET Core dependency injection system, but not so many options when trying to jam them together. These were my explanations and example classes on how things work, so that hopefully they help someone else!

The Problem

Imagine a “simple” piece of code like below.

public class UserService
{
    private readonly PhoneService _phoneService;

    public UserService(PhoneService phoneService)
    {
        _phoneService = phoneService;
    }

    public string GetUserPhoneNumber()
    {
        var userId = 123;
        return _phoneService.GetPhoneNumberById(userId);
    }
}

public class PhoneService
{
    private readonly UserService _userService;

    public PhoneService(UserService userService)
    {
        _userService = userService;
    }

    public string GetPhoneNumberById(int phoneNumberId)
    {
        return "+64123123123";
    }

    public string GetUserPhoneNumber()
    {
        return _userService.GetUserPhoneNumber();
    }
}

Now the circular reference in this case is rather.. idiotic and I don’t expect anyone to realistically run into this sort of code in production, but it demonstrates the issue quite well.

You see, first someone created a UserService. This dealt with everything about a user. Next came a PhoneService, that dealt with everything to do with phone numbers. A smart developer then said, well given I have a UserService, and I want to get the phone number of a user, I’ll inject the PhoneService into the UserService, and then get the current users phone number.

But then along comes another developer. They say, well, if I have the phone number service, since I am dealing only with phone numbers, then I want to get the current users phone number. They noticed that there is already a method called “GetUserPhoneNumber” on the UserService, so they just inject that and call it. Remember, they may not even know that the way that UserService actually finds the phone number is by calling the PhoneService itself, but alas, it does.

And now we have a problem. For the UserService to be constructed, we need a PhoneService. But for a PhoneService to be constructed, we need a UserService. This is a circular reference. Luckily for us, .NET Core is pretty good at picking these issues up at the earliest possible runtime (But not compile time), and we usually end up with an exception.

A circular dependency was detected for the service of type 'UserService'.
UserService -> PhoneService -> UserService

It even directly points out the exact services which depend on each other. Note that in some cases, the circle could be much larger. For example

UserService -> PhoneService -> AnotherService -> UserService

But as long as the circle is enclosed, then you will get an exception.

The “Lazy” Fix / Service Locator

This is a terrible bandaid and I never recommend using this. Ever. It’s simply a bandaid to a problem that is very very easy to get wrong. Previously in .NET, you could do something like :

public class UserService
{
    private readonly Lazy<PhoneService> _phoneService;

    public UserService(Lazy<PhoneService> phoneService)
    {
        _phoneService = phoneService;
    }


    public string GetUserPhoneNumber()
    {
        var userId = 123;
        return _phoneService.Value.GetPhoneNumberById(userId);
    }
}

All the Lazy modifier did was not try and request the service until it was actually required. This meant that the UserService could be created without actually needing the PhoneService until the actual execution path was called, and so theoretically, while the constructors were running, they did not enter an infinite loop.

.NET Core now picks this up however and if you try any sort of the above with Lazy, it will stop you from doing so.

A circular dependency was detected for the service of type 'UserService'.
UserService -> System.Lazy -> PhoneService -> UserService

So then, people would just inject some sort of ServiceLocator. For example :

public class UserService
{
    private readonly ServiceLocator _serviceLocator;

    public UserService(ServiceLocator serviceLocator)
    {
        _serviceLocator = serviceLocator;
    }


    public string GetUserPhoneNumber()
    {
        var userId = 123;
        return _serviceLocator.Get<PhoneService>().GetPhoneNumberById(userId);
    }
}

This does compile and actually run, but again is simply a band aid to the problem. You still have a circular reference, it’s just that at some point you are killing the circle by using a ServiceLocator. Ugh.

I would put the use of “Factories” in here as well. I’ve seen people get around the problem by using a “PhoneServiceFactory” that itself uses a ServiceLocator or similar to construct the PhoneService for the UserService, so again you are breaking the circle. But again, you still have a circular reference you are just hacking your way out of it.

Kill The Reference

Far and away the best option for digging your way out of this hole is to not reference each other at all and if at all possible, have a one way reference between the services. So we *could* change our code to simple remove the GetUserPhoneNumber method from the PhoneService, and if you want a users phone number, you have to use UserService to get it.

public class UserService
{
    private readonly PhoneService _phoneService;

    public UserService(PhoneService phoneService)
    {
        _phoneService = phoneService;
    }

    public string GetUserPhoneNumber()
    {
        var userId = 123;
        return _phoneService.GetPhoneNumberById(userId);
    }
}

public class PhoneService
{
    public string GetPhoneNumberById(int phoneNumberId)
    {
        return "+64123123123";
    }
}

In our example, we really only had a circular reference out of convenience and not because we actually needed the method on both services. In some cases simply having a one way reference doesn’t work in which case…

Create A “Joining” Service

While not a great working example, what you’ll often have to do is create a “JoiningService”, for example a “UserPhoneNumberService”, where either the UserService and PhoneService both reference this service, or vice versa.

Often you can put all the shared functionality that both services need into this service. Or you can have this as an entry point to then call both the UserService and the PhoneService to get data instead of them calling each other.

Runtime Stack Overflows

If you have a circular reference that you attempt to get around using Factories, Lazy’s, ServiceLocators, or some other bandaid. What you might find is that you end up with one of the following errors.

System.InsufficientExecutionStackException
The program '[4176] iisexpress.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'.

The most common reason is because you have registered a service as a factory in .NET Core DI :

services.AddTransient(s => new UserService(s.GetService()));

This is essentially a form of Lazy that the .NET Core DI container cannot pickup early on at runtime. What you are basically saying is “When you create the UserService, run this method”. Now “This method” is constructoring a new UserService, and trying to pull the PhoneService from the ServiceCollection. But because PhoneService references the UserService, we loop back on ourselves and execute this method again.

There aren’t really any safeguards against this because it’s hard to know at compile time exactly how things will be executed, but it’s a circular reference none the less.

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

Cloning objects in any programming language is tricky, but I think in C# that’s taken up an extra notch by giving you a couple of tools that look like they would probably solve your problem, but then not letting you know that it’s likely to only solve a very slim use case and nothing else. This guide is going to be half a guide on cloning, but also a quick refresher on what “cloning” actually means in the context of C#.

Shallow Clone vs Deep Clone

It’s worth starting at the basics. What is the difference between a shallow clone and a deep clone? (Also sometimes known as a shallow copy and a deep copy).

A shallow clone is a copy of an object that duplicates as little as possible. In C# this generally means that value types are duplicated, but reference types are not. Or as an example, let’s take the following object :

class Person
{
    public int Age { get; set; }
    public Person Father { get; set; }
    public Person Mother { get; set; }
}

If I made a shallow clone of this object and changed the age, the original object would not have it’s age changed. However, if I then changed a property on the cloned object’s father, then I would also affect the original object’s father because the reference isn’t cloned.

That may be a little confusing so thinking of it another way, in C#, when you do a shallow clone of an object, you are going “one level deep”, hence shallow. Any objects inside the object you want to clone are not themselves recursively cloned as well.

A deep clone is obviously the opposite. It keeps going down the tree and tries to clone all properties of your object, then the properties of that property etc.

Memberwise Clone

So if you’ve done any research at all into cloning in C#, you’ve probably come across the “memberwise” clone method. It’s available to every class but *only inside that class* as it’s a protected method of Object. You cannot call it on an object from another class.

For example :

class Person
{
    public string Name { get; set; }
    public Person Father { get; set; }
    public Person Mother { get; set; }

    public Person Clone()
    {
        return (Person)this.MemberwiseClone();
    }
}

However a quick look at the intellisense tells us something…

Creates a shallow copy of the current Object.

A shallow copy. Oof! So calling clone on this object will only shallow clone it, and not do a deep clone. If your object is purely primitives, then this can actually work for you and you can stop right here. But in most cases, we are looking to a deep clone. Even if for the sole reason that should someone add a property of another class here, then everything doesn’t suddenly break.

ICloneable Interface

So you might have also come across this interface called “ICloneable”. Unfortunately, it doesn’t really solve any problems an infact the documentation has this to say :

Because callers of Clone() cannot depend on the method performing a predictable cloning operation, we recommend that ICloneable not be implemented in public APIs.

Pretty stern words but it makes sense because if we look at how we might implement ICloneable.

class Person : ICloneable
{
    public string Name { get; set; }
    public Person Father { get; set; }
    public Person Mother { get; set; }

    public object Clone()
    {
        return this;
    }
}

Here we haven’t even cloned our object, we’ve just returned the same exact instance. While yes, we may expect a developer to know better, the point is that a caller doesn’t have any idea how the deep the clone goes, or if it’s even a clone at all. For this reason, people tend to stay away from the ICloneable interface.

Even if you get past that… It returns an object rather than a Person object which is annoying!

But with all that said, ICloneable doesn’t actually provide implementation details for cloning anyway. It just tells a caller “maybe call this and try your luck at getting a clone back”, but it doesn’t help a developer actually do a clone, shallow or deep.

Manually Deep Cloning

A sure fire way to know that you are deep cloning an object is to manually deep clone it yourself!

class Person
{
    public string Name { get; set; }
    public Person Father { get; set; }
    public Person Mother { get; set; }

    public Person Clone()
    {
        return new Person
        {
            Name = this.Name,
            Father = this.Father == null ? null : new Person { Name = this.Father.Name },
            Mother = this.Mother == null ? null : new Person { Name = this.Mother.Name }
        };
    }
}

In our clone method we are now creating new objects to completely clone our object and have no references to the original. This works great but it is time consuming. Any new property on this object means we have to modify our Clone method and re-test everything again.

On top of that, we are only going one level deep, for example we are not cloning our Father’s father, or our Mother’s mother.We may not need them for whatever we are then doing with our clones, but it’s also not a true “clone”. It’s just a clone of whatever we could be bothered mapping across!

With all those complaints out of the way however, it’s really not a bad option if it’s only a couple of classes that you really want to clone and they aren’t going to be modified that often.

Binary Serializer Cloning

An exceptionally common way of doing deep clones (Or atleast, more than just a shallow clone) is by serialising the data to another format and then back again.

Take this example of using a Binary Serializer on our Person class :

[Serializable]
class Person
{
    public string Name { get; set; }
    public Person Father { get; set; }
    public Person Mother { get; set; }

    public Person Clone()
    {
        IFormatter formatter = new BinaryFormatter();
        using (stream = new MemoryStream())
        {
            formatter.Serialize(stream, this);
            stream.Seek(0, SeekOrigin.Begin);
            return (Person)formatter.Deserialize(stream);
        }
    }
}

One very important thing to notice is that we’ve had to decorate our class with a [Serializable] attribute, without it we get :

Type 'Person' is not marked as serializable.

It’s also somewhat annoying to have to add this code to every class, so it’s far more likely that we create a static cloning service like this :

public static class CloningService
{
	public static T Clone<T>(this T source)
	{
		// Don't serialize a null object, simply return the default for that object
		if (Object.ReferenceEquals(source, null))
		{
			return default(T);
		}
		
		IFormatter formatter = new BinaryFormatter();
		using (stream = new MemoryStream())
		{
			formatter.Serialize(stream, source);
			stream.Seek(0, SeekOrigin.Begin);
			return (T)formatter.Deserialize(stream);
		}
	}
}

We still however have that issue of marking things as [Serializable].

JSON Serializer Cloning

This method is… Well.. a little rough but I’ve honestly found it works the best. You’ll first need to install the Newtonsoft.Json nuget package.

Install-Package Newtonsoft.Json

Then you can modify our cloning service like so :

public static class CloningService
{
	public static T Clone<T>(this T source)
	{
		// Don't serialize a null object, simply return the default for that object
		if (Object.ReferenceEquals(source, null))
		{
			return default(T);
		}

		var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
		var serializeSettings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
		return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source, serializeSettings), deserializeSettings);
	}
}

And can I just say, everytime I’ve had to do this I think “Converting this to JSON and back again really isn’t great….”. But it just works. It handles everything you throw at it and is pretty much faultless.

In my opinion, if you are looking for a sure fire, re-useable way to clone objects in your code. This is it.

Reference Loops When Cloning

Eagle eyed readers will notice that in the above JSON cloning service, we have a line to handle reference looping. This is a very very common occurence, especially in models that are used as part of a DataModel where the two classes will reference each other. No matter how you decide to clone objects, you will always have issues where objects reference each other and any attempt to clone just spirals into an endless loop.

So even though in the above code, we solve it using a setting, it’s worth pointing out that no matter which way you decide to clone objects, this is going to always be a problem.

What’s Your Solution?

Think this page is full of hacks (it is!), and have a much better way to clone objects? Feel free to drop a comment below.

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

Lately I seem to have run into a tonne of these types of errors when trying to host .NET Core applications inside IIS

HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure

and

HTTP Error 500.30 - ANCM In-Process Start Failure

And to be honest, they have been incredibly hard to debug. If you search for these errors on Google, you’ll find hundreds of stack overflow posts detailing people running into them, often with very little follow up on how they solved the issue. Sometimes they’ll even go as far to say “I re-installed everything and now it works” which in most cases, is not going to be viable. “Hey boss, let me just wipe this server real quick” generally doesn’t cut it.

But hopefully, fingers crossed, this will be the last blog post you’ll ever have to read on these error messages!

Why Are There Two Error Messages?

So first let’s touch on why there are two different messages (And error codes). Essentially, they are the exact same error but refer to different hosting models when running IIS infront of .NET Core. We won’t dive too deep into what these hosting models are, as at some point (.NET Core 2.1+ I believe) the default hosting model got swapped from Out-Of-Process to In-Process, so it very well could depend entirely on the version of .NET Core you are running.

Just know that for all practical purposes, these two error messages are the same so if you are following some blog post that is talking about one of these error messages, but you have the other, you can still follow along as it may well solve your problem.

Solution #1 – Incorrect Or Non-Existent .NET Core Hosting Bundle

So if you’re using something like Azure App Services that abstract away all the server management for you, then you can probably skip this, but if you are managing the server yourself (Or you’re trying to run a .NET Core application on your PC), then definitely read on.

If you followed our guide to running .NET Core on IIS (Which you definitely should) you would know that you need to install the .NET Core “Hosting Bundle” for .NET Core web apps to work inside IIS. This is also required even if you use self contained deployments. It is also required even if you install the .NET Core runtime on the machine. I’ll repeat, you cannot host .NET Core web applications inside IIS unless you install the hosting bundle.

If you are on your server and you aren’t sure if you have the hosting bundle installed, go to Add/Remove Programs in Windows and search for hosting :

If you don’t have this, then you can go here : https://dotnet.microsoft.com/download/dotnet-core/3.1 and download the hosting bundle :

It’s also important to note. Download the hosting bundle that matches the version of .NET Core you are running. I would presume that things are backwards compatible and if you download a newer version, it will work with older versions of .NET Core, but it’s super important to have atleast the same version as your actual code.

And finally. Restart your machine. I cannot make that any more clear. I cannot tell you how many people install everything under the sun and nothing seems to “work”, but it’s because they haven’t restarted. For the most part, you can get away with just an IISReset, but restarting the machine is often easier and just makes sure that you are restarting absolutely everything you need to.

For Shared Hosting, you may need to open a ticket with your provider. Again, I’ve seen providers only have the .NET Core 2 Hosting Bundle and people are trying to deploy .NET Core 3.1 applications. It pays to ask!

Still not working? Move onto Solution #2.

Solution #2 – .NET Core Startup Process Fails

This one took me an absolute lifetime to workout, but as it turns out, the .NET Core startup process has to start successfully before IIS can take over. That means if certain startup routines of .NET Core fail, then IIS doesn’t know how to handle the exception and just gives a generic error. Infact, that’s why it’s called an “ANCM Startup Failure”!

So what sort of things are we talking? Well for me, the most common one has been integrating with KeyVault. If you follow the official documentation here, it tells you to add it to your CreateHostBuilder method. CreateHostBuilder is ran on startup and needs to complete *before* IIS can take over, if for some reason your app cannot connect to KeyVault (Firewall, permissions etc), then your applicaiton will crash and IIS will have no option but to bail out as well.

Generally speaking, most of the times I see these ANCM startup failures has been when I’ve added code to the CreateHostBuilder method in my program.cs. Truth be told, it’s actually 100% of the time.

But how can we diagnose them? The easiest way is to actually run our application via Kestrel direct on the server. On a metal server (e.g. One you can RDP to), this means simply going to the folder where our application dlls are, and running “dotnet myapplication.dll” and seeing if it runs. What you should see is that the startup error is printed to the console and should point you in the right direction. Remember, in production configuration, firewalls, keys, and secrets could all be completely different so just because the application starts up fine on your local machine, on a remote machine it could completely blow up.

For sites hosted inside things like Azure App Services, you need to find a way to run the application manually yourself. On Azure, this means using Kudu, but on shared hosting services, you might be completely out of luck. If that’s you, you really have two options :

  • Open a support ticket to see if they can run your application manually in Kestrel like above, and hand you the error. (Again, this might be worth it to see if they even support the version of .NET Core you are intending to run).
  • Guess. Yes guess. Check your applications program.cs and how your HostBuilder is created. Start removing things and redeploying until you find the thing that is breaking it. If possible, create a simple hello world application and deploy it, if it also breaks, then it points more towards the hosting bundle than anything wrong with your startup code.

Debugging With stdout

Still need further debugging. Here’s another tip!

After publishing a .NET Core app, you will find in the publish directory there is a web.config with minimal information, but you should see something like so :

<aspNetCore processPath="dotnet" arguments=".\MyTestApplication.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />

Pretty obvious here, we just change stdoutLogEnabled=”false” to stdoutLogEnabled=”true” and redeploy. This should enable additional IIS logging to ./logs and allow us to debug further. Honestly, I’ve found this really really hit and miss. I’ve found that running the application directly from the console on the server to be much more helpful, but this is also an option if you have no other way.

Still Not Working?

Still not working? Or solved it a different way? Drop a comment below with a link to a GIT Repo and let the community help. This is honestly an infuriating error and I’ve had 20 year veteran programmers pull their hair out trying to solve it, so seriously drop a line. If you aren’t comfortable leaving a comment to your code, try wade[at]dotnetcoretutorials.com and I’ll see what I can do!

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

Getting Setup With C# 9

If you aren’t sure you are using C# 9 and/or you want to start using some of the new shiny features in the C# language, be sure to read our quick guide on getting setup with C# 9 and .NET 5. Any feature written about here is available in the latest C# 9 preview and is not a “theoretical” feature, it’s ready to go!

C# 9 Features

We are slowly working our way through all new C# 9 features, if you are interested in other new additions to the language, check out some of the posts below.

Free C# 9 Video Course

Are you one of those people that sees a big wall of text on a programming blog and instantly tunes out? Well you aren’t alone! In fact, I got hassled so much with people asking me “Can’t you just quickly share your screen and show me?” rather than reading a blog post, I decided I may as well quickly record the need to know bits of C# 9. So that’s what I’ve done!

My “What’s New In C# 9” course is completely free and will get you up and using C# 9 features in less than an hour (seriously!). Did I mention it’s FREE?

Watch For Free Now!

A Console Application Today

Start any new console application today from Visual Studio, and you’ll see something like this :

using System;

namespace TestTopLevelPrograms
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

A bog standard console application that says Hello World. Not a heck of a lot going on here. But in many ways, it’s ever so slightly over engineered. Show this to a new programmer as their “first” program. And they’ll say “But what’s this namespace thing?” “What does static mean?” “What are args? Do I use them or?”. There’s just ever so much going on for such a simple program.

And taking it further, this isn’t limited to newbie programmers. It can be frustrating when you just want to “script” something, and you have all this boiler plate. And that’s what Top Level Programs solves.

Top Level Programs

Top level programs (also referred to as Top Level Statements) does away with this. We can take our simple application and turn it into :

using System;

Console.WriteLine("Hello World!");

That’s it! No more namespace, no more program class, just a bog standard simple script. In some ways, if you are a fan of using things like Linqpad, this is a very similar experience.

And I mean.. That’s it.. That’s top level programs! There really isn’t much more to it!

If you want to get started, as of today, there isn’t a Visual Studio template for writing everything top level (Well.. I mean that would just be a blank file). But if you create a new console application, then ensure you are using C# 9 by editing your .csproj to match the below :

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <LangVersion>9.0</LangVersion>
  </PropertyGroup>
</Project>

Then you should be able to essentially delete everything in your program.cs and start fresh.

Using Async

Want to use an sync method, no problem. Check this out :

using System;
using System.Threading.Tasks;

await MyAsyncMethod();
Console.WriteLine("Hello World!");

async Task MyAsyncMethod()
{
    await Task.Yield();
}

Using await tells the compiler that the compiled main entry point should also be async. And we are also showing off the fact that you can add in local method to this top level file to. It may just be the return of the one file wonder!

Using Args

Missing Args? No problem.

using System;
Console.WriteLine(args[0]);

Your args are still there, just not as obvious!

Who Is This For?

So finally, a quick note on who this is for. I don’t really feel like this is aimed at any one level of C# developer. While it’s helpful for newbies to find their footing in a more “scripting” environment, the fact that you can now just whip up a quick one file wonder without all the cruft of your regular console app is actually amazingly useful at any level.

I actually have a sneaking suspicion that those developers who fell in love with NodeJS with it’s simple one file APIs may also like the simplicity of this one. Imagine just being able to create a dead simple API that can return some lookup value, and it’s just a matter of opening up an empty file and typing.

Troubleshooting

If you get the following error :

The feature 'top-level statements' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.

It means you are using a version of C# less than 9 (Or atleast not with the latest preview version). Check out our quick guide on getting setup with using C# 9 and all it’s features here : https://dotnetcoretutorials.com/2020/08/07/getting-setup-with-c-9-preview/

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.