This post is part of a series on .NET 6 and C# 10 features. Use the following links to navigate to other articles in the series and build up your .NET 6/C# 10 knowledge! While the articles are seperated into .NET 6 and C# 10 changes, these days the lines are very blurred so don’t read too much into it.

.NET 6

Minimal API Framework
DateOnly and TimeOnly Types
LINQ OrDefault Enhancements
Implicit Using Statements
IEnumerable Chunk
SOCKS Proxy Support
Priority Queue
MaxBy/MinBy

C# 10

Global Using Statements
File Scoped Namespaces


This is probably going to be my final post on new features in C# 10 (Well, before I do a roundup of everything C# 10 and .NET 6 related). But it doesn’t mean this post is any less useful. Infact, this one hits a very special place in my heart.

For a little bit of a story. Back in 2006-ish, I wanted to learn a new programming language. I was a teenager all hyped up on computers and making various utilities, mostly revolving around MSN Messenger auto replies and the like. I had mastered Pascal to a certain degree, and had moved on to Delphi. There was this new thing called “.NET” and a language called C# – and since anything starting with a C was clearly amazing in the programming world, I went down that rabbit hole.

I convinced a family member to buy me a C# tutorial book *I think* from Microsoft, I can’t exactly remember. I do remember it having a “tool” on the front so I can only presume it was this one or another in the series : https://www.amazon.com/Microsoft%C2%AE-Visual-2005-Step-Developer/dp/0735621292. Eagerly, I opened the book and inserted the CD Rom that came with it. And I can still remember my heart sinking.

Your operating system is not compatible

For reasons unknown to me at the time, I was using Windows ME. Quite possibly the worst operating system known to man. I mean, we didn’t have have a lot of money. It was a 1GHZ, 256MB RAM machine, Windows ME was the best we could do at the time. And so.. I was stuck. The CD ROM wouldn’t work, so I couldn’t install Visual Studio (These were days before broadband/ADSL for me), and so I did what any kid would do. I just read the book instead and took notes that someday I hoped I could use when writing C# code. Literally, I couldn’t even write C# code on my PC, and instead I just wrote it on paper and “pretended” it would work first time and I was learning. Ugh.

However, the actual point of the story is this. The first chapter of the blimmin book had the driest introduction to namespaces you could imagine. I thought maybe we could ease into “integers vs strings” or a nice “if statement”, but nope, let’s talk about how namespaces work. I just remember it being sooo off putting. And 15 years later, if a new programmer asked me to teach them C#, I would probably not even mention namespaces in the first month.

So with that story done, let’s look at the actual feature….

Introducing File Scoped Namespaces

We can take a namespace scoped class like so :

namespace MyNamespace.Services
{
    class MyClass
    {

    }
}

But in C# 10, we can now remove the additional parenthesis and have the code look like so :

namespace MyNamespace.Services;

class MyClass
{

}

And that’s… kinda it. It’s done for no other reason than it removes an additional level of indenting that really isn’t needed in this day and age. It just presumes that whatever is inside that file (hence file scoped) is all within the same namespace. I can’t think of a time literally in 15 years that I have ever had more than 1 namespace in the same file. So this addition to C# really does make sense.

Visual Studio 2019 vs 2022

I just want to put a huge caveat when using this feature. For a couple of months now, I tried this feature out in every .NET 6 preview SDK release. And each time I couldn’t get it to work, but I kept seeing people talk about it.

As it turns out, for whatever reason, I could not get this feature to work in Visual Studio 2019 (And actually, Minimal APIs in .NET 6 had similar issues), but it worked first try in Visual Studio 2022. So if you are getting errors such as :

{ expected

Then you probably need to try it inside Visual Studio 2022.

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 post is part of a series on .NET 6 and C# 10 features. Use the following links to navigate to other articles in the series and build up your .NET 6/C# 10 knowledge! While the articles are seperated into .NET 6 and C# 10 changes, these days the lines are very blurred so don’t read too much into it.

.NET 6

Minimal API Framework
DateOnly and TimeOnly Types
LINQ OrDefault Enhancements
Implicit Using Statements
IEnumerable Chunk
SOCKS Proxy Support
Priority Queue
MaxBy/MinBy

C# 10

Global Using Statements
File Scoped Namespaces


Reading through the new features introduced in .NET 6, something that I repeatedly glossed over was the new MaxBy and MinBy LINQ statements. I kept glossing over them because at first look, it doesn’t seem to be anything new but in reality.. They are actually extremely helpful!

Getting Setup With .NET 6 Preview

At the time of writing, .NET 6 is in preview, and is not currently available in general release. That doesn’t mean it’s hard to set up, it just means that generally you’re not going to have it already installed on your machine if you haven’t already been playing with some of the latest fandangle features.

To get set up using .NET 6, you can go and read out guide here : https://dotnetcoretutorials.com/2021/03/13/getting-setup-with-net-6-preview/

Remember, this feature is *only* available in .NET 6. Not .NET 5, not .NET Core 3.1, or any other version you can think of. 6.

Max/MinBy vs Max/Min

So it’s actually brutally simple.

I can run a simple Max statement like so across a list of numeric values :

List<int> myList = new List<int> { 1, 2, 3 };
myList.Max(); //Returns 3

Seems simple, and we output the maximum numeric value.

If I have a complex type, like a class of “Person”, then you might think I need to do something rinky dink to find the max age of those people (as shown below). I actually at first thought this was what “MaxBy” was all about. Like “Max By Property XYZ”. But infact, the regular max statement works just fine like so :

List<Person> people = new List<Person>
{
    new Person
    {
        Name = "John Smith", 
        Age = 20
    }, 
    new Person
    {
        Name = "Jane Smith", 
        Age = 30
    }
};

Console.Write(people.Max(x => x.Age)); //Outputs 30

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

So what happens if we change that same statement to MaxBy?

List<Person> people = new List<Person>
{
    new Person
    {
        Name = "John Smith", 
        Age = 20
    }, 
    new Person
    {
        Name = "Jane Smith", 
        Age = 30
    }
};

Console.Write(people.MaxBy(x => x.Age)); //Outputs Person (Jane Smith)

Instead of outputting the max property value, we output the entire object that has the max value. So instead of returning “30” we return the entire Person object of Jane Smith.

Another way to look at it, is it’s more or less a shortening of the following statement :

people.OrderByDescending(x => x.Age).First(); //Outputs Person (Jane Smith)

This is the crux of MaxBy/MinBy and is a pretty nifty addition that I totally didn’t know I needed until now.

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 post is part of a series on .NET 6 and C# 10 features. Use the following links to navigate to other articles in the series and build up your .NET 6/C# 10 knowledge! While the articles are seperated into .NET 6 and C# 10 changes, these days the lines are very blurred so don’t read too much into it.

.NET 6

Minimal API Framework
DateOnly and TimeOnly Types
LINQ OrDefault Enhancements
Implicit Using Statements
IEnumerable Chunk
SOCKS Proxy Support
Priority Queue
MaxBy/MinBy

C# 10

Global Using Statements
File Scoped Namespaces


For a long time now (Actually, almost since forever), we have been stuck with the DateTime type in .NET. By “stuck”, it hasn’t been like it’s always been a problem, and you can go months, if not years of using DateTime without any issue. But every now and again, those gremlins creep in when trying to use DateTime as either only a Date, or only a Time.

In the case of using only a Date, this is extremely common when storing things such as birthdays, anniversary dates, or really any calendar date that doesn’t have a specific time associated with it. But in .NET, you were forced to use a DateTime object, often with a time portion of midnight. While this worked, often the time portion would get in the way when comparing dates or wanting to manipulate a date without really worrying about the time. It was especially weird when working with a SQL database that has the concept of a “date” type (with no time), but when loading the data into C#, you had to deal with a DateTime.

If you only wanted to store a time, then you were really in trouble. Imagine wanting to set an alarm for a recurring time, every day. What type would you use? Your best bet was of course to use the “TimeSpan” type, but this was actually designed to store elapsed time, not a particular clock time. As an example, a TimeSpan can have a value of 25 hours because it’s a measure of time, not the actual time of day. Another problem was time wrapping. If something started at 11PM, and went for 2 hours. How would you know to “wrap” the end time around to be 1AM? This often meant using some sort of rinky dink DateTime object that now ignored the date portion, ugh.

And that’s why .NET 6 has introduced DateOnly and TimeOnly!

Getting Setup With .NET 6 Preview

At the time of writing, .NET 6 is in preview, and is not currently available in general release. That doesn’t mean it’s hard to set up, it just means that generally you’re not going to have it already installed on your machine if you haven’t already been playing with some of the latest fandangle features.

To get set up using .NET 6, you can go and read out guide here : https://dotnetcoretutorials.com/2021/03/13/getting-setup-with-net-6-preview/

Remember, this feature is *only* available in .NET 6. Not .NET 5, not .NET Core 3.1, or any other version you can think of. 6.

Using DateOnly

Using DateOnly is actually pretty easy. I mean.. Check the following code out :

DateOnly date = DateOnly.MinValue;
Console.WriteLine(date); //Outputs 01/01/0001 (With no Time)

An important distinction to make is that a DateOnly object never has a Timezone component. After all, if your birthday is on the 10th of May, it’s the 10th of May no matter where in the world you are. While this might seem insignificant, there are things like DateTimeKind and DateTimeOffset dedicated to solving timezone problems, of which, when we are using DateOnly we are uninterested in.

The thing to note here is that even if you didn’t intend to deal with timezones previously, you might have been conned into it. For example :

DateTime date = DateTime.Now;
Console.WriteLine(date.Kind); //Outputs "Local"

The “Kind” of our DateTime object is “Local”. While this may seem insignificant, it could actually become very painful when converting the DateTime, or even serializing it.

All in all, DateOnly gives us a way to give a very precise meaning to a date, without being confused about timezones or time itself.

Using TimeOnly

While DateOnly had fairly simple examples, TimeOnly actually has some nifty features that suddenly make this all the more a needed feature.

But first, a simple example :

TimeOnly time = TimeOnly.MinValue;
Console.WriteLine(time); //Outputs 12:00 AM

Nice and simple right! What about if we use our example from above, and we check how time is wrapped. For example :

TimeOnly startTime = TimeOnly.Parse("11:00 PM");
var hoursWorked = 2;
var endTime = startTime.AddHours(hoursWorked);
Console.WriteLine(endTime); //Outputs 1:00 AM

As we can see, we no longer have to account for “overflows” like we would when using a TimeSpan object.

Another really cool feature is the “IsBetween” method on a TimeOnly object. As an example :

TimeOnly startTime = TimeOnly.Parse("11:00 PM");
var hoursWorked = 2;
var endTime = startTime.AddHours(hoursWorked);

var isBetween = TimeOnly.Parse("12:00 AM").IsBetween(startTime, endTime); //Returns true. 

This is actually very very significant. In a recent project I was working on, we needed to send emails only in a select few hours in the evening. To check whether the current time was between two other datetimes is actually significantly harder than you may think. What would often happen is that we would have to take the time, and assign it to an arbitrary date (For example, 01/01/0001), and then do the comparison. But then the midnight wrap around would always choke us in the end.

In my view DateOnly and TimeOnly are significant additions to .NET, and ones that I think will be used right from release. On top of this, it doesn’t mean DateTime will be a relic of the past, instead, DateTime can be used only when you want to point to a specific date and time past, present or future, and not one or the other.

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 post is part of a series on .NET 6 and C# 10 features. Use the following links to navigate to other articles in the series and build up your .NET 6/C# 10 knowledge! While the articles are seperated into .NET 6 and C# 10 changes, these days the lines are very blurred so don’t read too much into it.

.NET 6

Minimal API Framework
DateOnly and TimeOnly Types
LINQ OrDefault Enhancements
Implicit Using Statements
IEnumerable Chunk
SOCKS Proxy Support
Priority Queue
MaxBy/MinBy

C# 10

Global Using Statements
File Scoped Namespaces


A fairly common interview question I have for any C#/.NET Developer revolves around the difference between First and FirstOrDefault LINQ statements. There’s a general flow to the questions that basically go something like :

What’s the difference between First and FirstOrDefault

When answered, I follow it up with :

So when FirstOrDefault can’t find a value, what does it return?

Commonly, I actually have people say things like it always returns null. Which is incorrect, it returns the “default” value for that type. Essentially, doing something like default(T). But if they get this part right, then I follow it up with things like

So what is the default value then? What would be the default value for a type of integer?

The correct answer to the above is 0. I’m not sure if it’s a difficult set of questions or not (Certainly many get it wrong), but it’s definitely something you will run into a lot in your career if you develop in C# for any length of time.

One of the main reasons I ask this question, is often I see code across all levels that works something like this :

var hayStack = new List { 1, 2, 2 };
var needle = 3;

var foundValue = hayStack.FirstOrDefault(x => x == needle);
if(foundValue == 0)
{
    Console.WriteLine("We couldn't find the value");
}

This works of course, but what if needle actually is the number 0? You have to do a bit of a dance to work out was it truly not found, or is the value you are looking for actually the default value anyway. You have a couple of options :

  • Run a LINQ Any statement beforehand to ensure that your list does indeed contain the item
  • Cast the list to a nullable variant of the type if not already, so you can ensure you get null back if not found
  • Use First instead of FirstOrDefault and catch the exception

You might think this is only really an issue in edge cases where you are using primitives that typically aren’t nullable, but with the introduction of Nullable Reference types in C# 8, this is actually going to become a very common scenario.

.NET 6 introduces the concept of being able to pass in what the default value should be, should the item not be found. So for example, this code is now valid in .NET 6.

var hayStack = new List<int?> { 1, 2, 2 };
var needle = 3;

var foundValue = hayStack.FirstOrDefault(x => x == needle, -1);
if(foundValue == -1)
{
    Console.WriteLine("We couldn't find the value");
}

But… Hold on. All we are doing here is saying instead of returning 0, return -1. Oof!

As it turns out, the IEnumerable method still must return a valid integer. And because our type is not nullable, even with this extension method, we can’t force it to return null. This goes for FirstOrDefault, SingleOrDefault and LastOrDefault.

The reason for this article I guess is to first and foremost to introduce the new extension, but also secondly to say, it doesn’t quite solve the problem that I thought it would at first look. You still must return a valid type. It doesn’t make it as useful as I first thought, but at the very least, it may help in some very edge scenarios, for example upserting values.

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 post is part of a series on .NET 6 and C# 10 features. Use the following links to navigate to other articles in the series and build up your .NET 6/C# 10 knowledge! While the articles are seperated into .NET 6 and C# 10 changes, these days the lines are very blurred so don’t read too much into it.

.NET 6

Minimal API Framework
DateOnly and TimeOnly Types
LINQ OrDefault Enhancements
Implicit Using Statements
IEnumerable Chunk
SOCKS Proxy Support
Priority Queue
MaxBy/MinBy

C# 10

Global Using Statements
File Scoped Namespaces


In a previous post, we talked about the coming ability to use global using statements in C# 10. The main benefit being that you were now able to avoid the clutter of declaring namespaces over and over (Things like using System etc) in every single file. I personally think it’s a great feature!

So it only makes sense that when you create a new .NET 6 project, that global usings are implemented right off the bat. After all, if you create a new web project, there are many many files auto generated as part of the template that will call upon things like System or System.IO, and it makes sense to just use GlobalUsings straight away from the start right?

Well… .NET 6 have solved the problem in a different way. With Implicit Using statements, your code will have almost invisible using statements declared globally! Let’s take a look at this new feature, and how it works.

Getting Setup With .NET 6 Preview

At the time of writing, .NET 6 is in preview, and is not currently available in general release. That doesn’t mean it’s hard to set up, it just means that generally you’re not going to have it already installed on your machine if you haven’t already been playing with some of the latest fandangle features.

To get set up using .NET 6, you can go and read out guide here : https://dotnetcoretutorials.com/2021/03/13/getting-setup-with-net-6-preview/

Remember, this feature is *only* available in .NET 6. Not .NET 5, not .NET Core 3.1, or any other version you can think of. 6.

Additionally, there was a change to this feature between .NET 6 Preview and .NET 6 RC. This article has been updated as of 2021-10-07 to reflect what is currently in the very latest SDK version. If you are unsure what you have, go grab the latest SDK just to be sure.

Implicit Global Usings

Implicit Global Usings are an opt in feature (kinda), that is new to .NET 6/C# 10. For existing projects that you are upgrading to .NET 6, you will need to add the following to your csproj file :

<ImplicitUsings>enable</ImplicitUsings>

However if you create a new project inside Visual Studio 2022 or using the latest SDK from the command line, this flag has already been enabled for you! So again, it’s somewhat opt in, it’s just that you will be opted in by default when creating a new project.

When enabled, implicit usings are actually a hidden auto generated file, inside your obj folder, that declares global using statements behind the scenes. In my case, if I go to my project folder then go obj/Debug/net6.0, I will find a file titled “ProjectName.GlobalUsings.g.cs”.

Opening this file, I can see it contains the following :

global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;

Note the fact this is an auto generated file, and we can’t actually edit it here. But we can see that it declares a whole heap of global using statements for us.

The project I am demoing this from is actually a console application, but each main project SDK type has their own global imports.

Console/Library

System
System.Collections.Generic
System.IO
System.Linq
System.Net.Http
System.Threading
System.Threading.Tasks

Web

In addition to the console/library namespaces :

System.Net.Http.Json
Microsoft.AspNetCore.Builder
Microsoft.AspNetCore.Hosting
Microsoft.AspNetCore.Http
Microsoft.AspNetCore.Routing
Microsoft.Extensions.Configuration
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Hosting
Microsoft.Extensions.Logging

Worker

In addition to the console/library namespaces :

Microsoft.Extensions.Configuration
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Hosting
Microsoft.Extensions.Logging

Of course, if you are unsure, you can always quickly create a project of a certain type and check the obj folder for what’s inside.

If we try and import a namespace that previously appeared in our implicit global usings, we will get the usual warning.

Opting Out

As previously mentioned, if you are creating a brand new .NET 6 and C# 10 (Which in a years time, the majority will be), then this feature is turned on by default. I have my own thoughts on that, but what if you want to turn this off? This might be especially common when an automatically imported namespace has a type that conflicts with a type you yourself are wanting to declare. Or what if you just don’t like the hidden magic full stop?

Well of course we can either delete the flag all together, or set it to be disabled if we want to be a bit more explicit :

<ImplicitUsings>disable</ImplicitUsings>

Note that clearly, if we switch this flag to disabled on a live project that’s been going for some time, you’re likely to get 100’s of errors due to a project not importing the correct namespaces.

There is also another option to selectively remove (and add) implicit namespaces like so :

<ItemGroup>
  <Using Remove="System.Threading" />
  <Using Include="Microsoft.Extensions.Logging" />
</ItemGroup>

Here we are removing System.Threading and adding Microsoft.Extensions.Logging to the global implicit using imports.

This can also be used as an alternative to using something like a GlobalUsings.cs file in your project of course, but it is a somewhat “hidden” feature.

Is This A Good Feature? / My Thoughts

In the original version of this article, I was mostly down on this feature. And that’s saying something because I rarely comment on new features being good or bad. Mostly it’s because I presume that people much smarter than I know what they are doing, and I’ll get used to it. I’m sure when things like generics, lambdas, async/await got introduced, I would have been saying “I don’t get this”.

On the surface, I like the idea of project types having some sort of implicit namespace. Even imports that I thought were kinda dumb to be global such as “System.Threading.Tasks”, I soon realized are needed in every single file if you are using async/await since your methods must return a type of Task.

Originally, Implicit Usings were enabled by default *without* a flag in the csproj, and instead you had to add something like so to disable them :

<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>

The new version is better, in that we are opted in explicitly, but still the “hiddenness” of it all isn’t so great. I don’t like the idea of files being auto generated in the obj folder because for the most part, people do not go and look there. If you are doing a Ctrl + Shift + F inside your project to find a pesky namespace clash, you’re not going to find your auto generated implicit usings file.

I feel like a simpler idea would have been to edit the Visual Studio/Command Line templates that when you create a new web project, it automatically creates a GlobalUsings.cs file in the root of the project with the covered implicit namespaces already in there. To me, that would be a heck of a lot more visible, and wouldn’t lead to so much confusion over where these hidden imports were coming from.

That being said, maybe in a years time we just get used to it and it’s just “part of .NET” like so many other things. What’s your thoughts?

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.

For a long time now, I’ve been searching for a middle ground when it comes to Optical Character Recognition/OCR in .NET/C#. You might have heard of a little C++ library called “Tesseract” which many have tried to write wrappers around or interop in their C# code. I myself have followed tutorials and guides on how to do this and it’s always ended in pain. Most notably, when you are working with C++ libraries in C#, you have to be extremely careful about how memory is allocated otherwise there is a sure fire chance you’re going to end up with a memory leak somewhere along the way. Almost without fail when I’ve tried to use Tesseract in C++, I’ve ended up leaking memory all over the place and having my screen turn into a jigsaw requiring a PC restart.

The alternative has always been “enterprise” type OCR libraries with their hidden pricing that they then hoist on you at the last minute (I really have a distaste for these sorts of tactics if I’m being honest), and even then, they usually have some sort of limited feature set but you pay for it anyway just so you don’t end up losing sleep over memory issues.

Well, then in comes IronOCR. An OCR library that takes the headaches out of C++ interoperability, but with upfront (and very very reasonable) pricing. I’ve been playing around with this little OCR library for some time now and I’ve got to say, the ease in which this thing gets up and running is really a dream. Let’s get started!

What We Are Looking For In An OCR Library?

Before we jump to deep into the code, let me map out my thought process of what I wanted to get out of any OCR or computer vision library.

  • I know that there are API services out there that do this (For example for Azure OCR, there is Azure Cognitive Services which is essentially a computer vision API), but I wanted to make sure that I could run this without making API calls, and without having to pay more as I scale up. IronOCR is a one time fee and that’s it.
  • Support multiple languages, many libraries I looked at supported English only.
  • Is there some level of “cleanup” smarts there. If the scanned document or image is a bit scratchy, does the library come with a way to clean things up?
  • Does this work for both printed and handwritten text? This is more a nice to have, but it’s also a huge feature to have!
  • Can I use this in the cloud (Specifically, will this work in Azure)? Usually this means no “installs” that need to be made because I may not be using a VM at all and instead be entirely serverless.

IronOCR ticks all of these boxes, but let’s take a dive into how it might look in code.

Simple OCR Example

Let’s start off with something really easy. I took this screenshot from the Google Books page on Frankenstein by Mary Shelly.

I then took my C#/.NET Console Application, and ran the following in the nuget package manager to install IronOCR

Install-Package IronOcr

And then onto the code. I literally OCR’d this image to extract text, including line breaks and everything, using 4 lines of code.

var ocr = new IronTesseract();
using (var Input = new OcrInput("Frankenstein.PNG"))
{
    var result = ocr.Read(Input);
    Console.WriteLine(result.Text);
}

And the output?

Frankenstein
Annotated for Scientists, Engineers, and Creators of All Kinds

By Mary Wollstonecraft Shelley - 2017

Literally perfect character recognition in just a few lines of code! When I said that using Iron was like computer vision on “easy mode”, I wasn’t lying.

Running IronOCR In An Azure Function

I know this might seem like an obvious thing to say, but there has been countless times where I’ve used libraries that require some sort of dedicated VM, either through an installation on the machine or because of licensing “per machine”. In this day and age, you should not be using any library that can’t work in any sort of serverless environment.

Since in most of my recent projects, we are using Azure Functions in a microservices architecture, let’s create a really simple function that can take a parameter of an image, OCR it, and return the text.

public static class OCRFunction
{
    public static HttpClient _httpClient = new HttpClient();

    [FunctionName("OCRFunction")]
    public static async Task<IActionResult> Run([HttpTrigger] HttpRequest req, ExecutionContext context)
    {
        var imageUrl = req.Query["image"];
        var imageStream = await _httpClient.GetStreamAsync(imageUrl);

        var ocr = new IronTesseract();
        using (var input = new OcrInput(imageStream))
        {
            var result = ocr.Read(input);
            return new OkObjectResult(result.Text);
        }
    }
}

Nice and simple! We take the query parameter of image, download it and OCR it immediately. The great thing about doing this directly inside an Azure Function is that immediately it can service different parts of our application in a microservice architecture without us having to copy and paste the code everywhere.

If we run the above code on our Frankenstein image above :

Super easy!

Another thing I want to point out about this approach is that if you’re currently paying for some service that charges a per OCR fee. Things can appear cheap but at scale, the monthly fee can quickly spiral out of control. Compare this to a one time fee with IronOCR, and you’re getting what is essentially a callable API all hosted in the Azure Cloud, without the ongoing costs.

Non-English Support

One thing I noticed with even the “Enterprise” level OCR libraries is that they often supported English only. It would come with some caveat like “But you can train it yourself on any language you want”. But that’s not really good enough when you are paying through the nose already.

However, IronOCR supports 125 languages currently, and you can add as many or as few as you like by simply installing the applicable Nuget language pack.

Iron Azure OCR Language Support

I was going to write more on the language availability in IronOCR, but it just works, and it’s all right there in a nifty package!

Cleaning Up Skewed Scans For OCR

The thing is, most of the time when you need OCR, it’s because of scanned documents. It’s very rare that you’re going to be using OCR for some pixel perfect screenshot from a website. Some OCR libraries shy away from this and sort of “avoid” the topic. IronOCR jumps right in to the deep end and gives us some out of the box options for fixing up poor scans.

Let’s use this as an example. A scanned page from the book Harry Potter.

There’s a bit of noise here but more importantly the text is heavily skewed. Two issues that are very very common when scanning in paper. If I run this through the OCR with no “fixes” in play, the only things I get back are :

Chapter Eight

The Deathday Party

That’s because the page is just too skewed and noisy to make out smaller characters correctly. All we have to do is add the ability to correct the skew of the scan. We can do that with a single line of code :

var ocr = new IronTesseract();
using (var input = new OcrInput("HarryPotter.png"))
{
    input.Deskew(); //Deskew the image
    var result = ocr.Read(input);
    Console.WriteLine(result.Text);
}

And instantly, with no other changes, we actually get things working 100% :

Chapter Eight

The Deathday Party

October arrived, spreading a damp chill over the grounds and into the castie. Madam Pomfrey, the nurse,
was kept busy by a sudden spate of colds among the staff and students. Her Pepperup potion worked
instantly, though it left the drinker smoking at the ears for several hours afterward. Ginny Weasley, who had
been looking pale, was bullied into taking some by Percy. The steam pouring from under her vivid hair gave
the impression that her whole head was on fire.

There are actually a tonne of other options for cleaning up images/documents too including :

  • DeNoise
  • Rotating images a set amount of degrees
  • Manually controlling contrast, greyscale, or simply turning the image black and white
  • Enchancing the solution/image sharpening
  • Erode and Dilate images
  • And even more like color inversion and deep cleaning of background noise.

The thing is, if I’m being honest. I did play around with these but I just never really needed to. De-skewing my documents generally was enough to get everything coming out literally character perfect, but it’s great that IronOCR give you even more knobs to play with to really fine tune your OCR requirements.

Advanced Text Results

It might surprise you that other OCR libraries I tested simply output text and that was it. There was no structure to it, and you essentially had to work out based on counting line breaks or whitespace how each paragraph worked.  IronOCR however not only can read text from your documents, but can work out the structure too!

For example, let’s use our Harry Potter image and instead use the following code :

var ocr = new IronTesseract();
using (var input = new OcrInput("HarryPotter.png"))
{
    input.Deskew();
    var result = ocr.Read(input);
    foreach(var paragraph in result.Paragraphs)
    {
        Console.WriteLine($"Paragraph : {paragraph.ParagraphNumber}");
        Console.WriteLine(paragraph.Text);
    }
}

Notice how instead of simply spitting out the text, I want to go paragraph by paragraph, to really understand the blocks of text I’m working with. And the result?

Paragraph : 1
Chapter Eight
Paragraph : 2
The Deathday Party
Paragraph : 3
October arrived, spreading a damp chill over the grounds and into the castie. Madam Pomfrey, the nurse,
was kept busy by a sudden spate of colds among the staff and students. Her Pepperup potion worked
instantly, though it left the drinker smoking at the ears for several hours afterward. Ginny Weasley, who had
been looking pale, was bullied into taking some by Percy. The steam pouring from under her vivid hair gave
the impression that her whole head was on fire.

Again, character perfect recognition split into the correct blocks. There’s a tonne of options around this too including reading line by line, or even reading only certain sections of the text a time by drawing a rectangle over the document. The latter is extremely helpful when you only need to use computer vision on a particular section of the document, and don’t need to worry about the rest.

Who Is This Library For?

As always, when I look at these sorts of libraries I try and think about who is this actually aimed at. Is it a hobbyist library, is it for enterprises only. And honestly, I struggle to place this one. Computer vision and optical character recognition is on the rise, and in the past couple of years, I’ve been asked about libraries to extract text from images more than all previous years combined. Azure obviously has their own offering, but it’s on a per call basis and over time, that all adds up. Add to the fact that you really don’t have control over how it’s trained and it’s not an easy sell.

However, going with IronOCR you have all of the control, with a single one time price tag. Add to the fact that you can download this library today and test to your hearts content before buying, it really makes it a no brainer if you are looking for any sort of text extraction/OCR features.


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.

I recently came across a feature that was introduced in C# 8. It actually threw me through a loop because I first saw it used in some code I was reviewing. In a moment of “confidently incorrect”, I told the developer that they definitely had to change the code because clearly it wouldn’t work (If it would compile at all).

Of course the egg on my face ensued with a quick link to the documentation and a comment along the lines of “Shouldn’t you have written this on that blog?”.

Oof.

The feature I am talking about is “Using Declarations”. I think every time I’ve seen this feature mentioned, I’ve thought it referred to your standard usings at the top of your .cs file. Something like this :

using System;
using System.IO;

But in fact, it revolves around the use of using to automatically call dispose on objects. The code in question that I was reviewing looked something like this (And note, this is a really dumb example so don’t read into the code too much).

static int countLines()
{
    using var fileStream = File.OpenRead("myfile.txt");
    using var fileReader = new StreamReader(fileStream);
    var lineCount = 1;
    var line = string.Empty;
    while((line = fileReader.ReadLine()) != null)
    {
        lineCount++;
    }
    return lineCount;
}

I mentioned to the developer…. “Well how does that using statement work?” I had just assumed it functioned much like how an If statement works without braces. e.g. It will only affect the next line like so :

if(condition)
    DoThis();
ButThisIsNotAffectedByCondition();

But in fact this is a new way to do using statements without braces.

Now, placing a using statement like so :

using var fileStream = File.OpenRead("myfile.txt");

Actually means that the object will be disposed when control leaves the scope. The scope could be a method, a loop, a conditional block etc. In general, if it leaves an end brace } somewhere, the object will be disposed.

Why is this handy? Well without it, you would have to have large amounts of indenting, and generally that indentation is for the entire method body anyway. For example :

static int countLines()
{
    using (var fileStream = File.OpenRead("myfile.txt"))
    {
        using (var fileReader = new StreamReader(fileStream))
        {
            var lineCount = 1;
            var line = string.Empty;
            while ((line = fileReader.ReadLine()) != null)
            {
                lineCount++;
            }
            return lineCount;
        }
    }
}

Much less prettier, and it doesn’t afford us anything extra (In this case) than just doing the using declaration.

The one thing you may still want to use braces for is if you wish to really control when something is disposed, even without code leaving the current control scope. But otherwise, Using Declarations are a very nifty addition that I wish I knew about sooner.

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 post is part of a series on .NET 6 and C# 10 features. Use the following links to navigate to other articles in the series and build up your .NET 6/C# 10 knowledge! While the articles are seperated into .NET 6 and C# 10 changes, these days the lines are very blurred so don’t read too much into it.

.NET 6

Minimal API Framework
DateOnly and TimeOnly Types
LINQ OrDefault Enhancements
Implicit Using Statements
IEnumerable Chunk
SOCKS Proxy Support
Priority Queue
MaxBy/MinBy

C# 10

Global Using Statements
File Scoped Namespaces


I don’t often get hate comments/emails on this blog, but when I do, it’s about using statements not being available in my code snippets. For me, they just clutter everything up and rarely add much value or description to the code. What does several imports from system really add? Especially when everyone these days is using a fully featured IDE that has a one click “Add Using” option when you hover over anything.

Well with .NET 6 / C#10, I now have an excuse with the introduction of global using statements. Now you can place all of your common using statements (So mostly your System imports) into a single file that will automatically be available for use within that entire project. It’s a simple and nifty change!

Getting Setup With .NET 6 Preview

At the time of writing, .NET 6 is in preview, and is not currently available in general release. That doesn’t mean it’s hard to set up, it just means that generally you’re not going to have it already installed on your machine if you haven’t already been playing with some of the latest fandangle features.

To get set up using .NET 6, you can go and read out guide here : https://dotnetcoretutorials.com/2021/03/13/getting-setup-with-net-6-preview/

Remember, this feature is *only* available in .NET 6. Not .NET 5, not .NET Core 3.1, or any other version you can think of. 6.

Additionally, you may need to edit your .csproj file to allow for the preview LangVersion like so :

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

With all of that done, you should be ready to go!

Adding Global Usings

The syntax for adding global usings is actually fairly straight forward, simply add the keyword global before any using statement, anywhere, to make it global.

global using System;

Interestingly, there isn’t a well defined place to put these yet. You can put these in any file within your project and they are immediately global everywhere (As opposed to say the standard AssembleInfo.cs we used to have).

That being said, I’ve seen many people using a file in the root of your project called GlobalUsings.cs, with something akin to the following in there :

global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;

//Maybe even a global using of another projects folder folder for instance. 
// global using MyModelsProject.Models;

Again, there is no limit to how many usings you can place in here, nor where this file lives, but it’s generally a good idea to keep this list pretty concise only to what you need. That being said, the only downside to overloading these global usings is that your intellisense will be astronomical in every file, whether that’s actually a bad thing I don’t know.

And that’s it!

I’ll note that one of the reasons I love C# and .NET right now is that every single change has a pretty lively discussion on Github. Global Usings is no different and the discussion is out in the public here : https://github.com/dotnet/csharplang/issues/3428. But what’s your thoughts? 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.

A friend recently asked if I could help build a very simple image manipulation console app.

In short, he needed to take a folder full of RAW image files, and generate a smaller thumbnail in various formats (PNG, JPEG etc). Seemed like straight forward and (wrongly), I just assumed that .NET could handle RAW image files natively by now. As it turns out, I was very wrong.

What Image Types Can .NET Handle Natively?

From my research, .NET out of the box (Including Framework, Core and .NET 5+) could handle the following image types :

  • BMP (Bitmap)
  • EMF (Enhanced Metadata File)
  • EXIF (Exchangeable Image File)
  • GIF (Needs no explanation!)
  • ICON (Windows Icon Image Format)
  • JPEG (Again, no explanation necessary)
  • PNG
  • TIFF
  • WMF (Windows Metadata File)

Notice no “RAW” there. Raw itself actually has a few extensions including .CR2 which is Canon’s proprietary format, along with .NEF, .ORF, .ERF, .SRW and .SR2. The majority of these are just raw formats from a given camera manufacturer. The “Raw” format itself is almost just an overarching term for the images coming directly out of a camera without any processing.

Using ImageMagick

The only sensible option I found out there was to use the Magick.NET wrapper around ImageMagick. ImageMagick itself is a image processing library that is available in many languages (Especially common in PHP), and so it’s a pretty feature rich option.

Other options for .NET mostly included using command line applications, but just triggering them from .NET code using Process.Start. I want to avoid this sort of malarky (Even if at times, that’s what Magick.NET is actually doing behind the scenes).

To install Magick.NET, we first need to install the appropriate nuget package. In reality, there are packages for each CPU type (X86/X64) and different quality types (Q8, Q16, Q16HDRI). I was thinking I would try and go middle of the road and as it happens, that was also the most popular package on Nuget.

So from our Package Manager Console :

Install-Package Magick.NET-Q16-AnyCPU

From there, our code is actually extremely simple :

using (var image = new MagickImage("RAW_CANON_EOS_1DX.CR2"))
{
    var geometry = new MagickGeometry();
    geometry.IgnoreAspectRatio = false;
    geometry.Width = 500;
    image.Resize(geometry);
    image.Write("output.jpg");
}

This generates thumbnails (500px wide) from our images while keeping the same aspect ratio. Pretty nifty!

A quick note on testing all of this too. While building this, I didn’t have a camera myself that could generate raw images, so instead I used https://rawsamples.ch to check that various formats would work through ImageMagick (And they all seemed fine!). But if you aren’t sure which “raw” format you should be using, you can of course ask for the type of camera, and match it up to a couple of samples from the site. Worked a treat for me!

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 post is part of a series on .NET 6 and C# 10 features. Use the following links to navigate to other articles in the series and build up your .NET 6/C# 10 knowledge! While the articles are seperated into .NET 6 and C# 10 changes, these days the lines are very blurred so don’t read too much into it.

.NET 6

Minimal API Framework
DateOnly and TimeOnly Types
LINQ OrDefault Enhancements
Implicit Using Statements
IEnumerable Chunk
SOCKS Proxy Support
Priority Queue
MaxBy/MinBy

C# 10

Global Using Statements
File Scoped Namespaces


While looking through changes mentioned in .NET 6, I noticed that there was a new “Chunk” method on IEnumerable. This method was actually kindof simple, and yet powerful. Immediately I knew of a bunch of places in my code where I would love to use this, especially where I do parallel processing.

So of course, why not a quick write up to talk a little bit more about this utility!

Getting Setup With .NET 6 Preview

At the time of writing, .NET 6 is in preview, and is not currently available in general release. That doesn’t mean it’s hard to set up, it just means that generally you’re not going to have it already installed on your machine if you haven’t already been playing with some of the latest fandangle features.

To get set up using .NET 6, you can go and read out guide here : https://dotnetcoretutorials.com/2021/03/13/getting-setup-with-net-6-preview/

Remember, this feature is *only* available in .NET 6. Not .NET 5, not .NET Core 3.1, or any other version you can think of. 6.

IEnumerable.Chunk In A Nutshell

At it’s simplest, we can write code like so :

var list = Enumerable.Range(1, 100);
var chunkSize = 10;
foreach(var chunk in list.Chunk(chunkSize)) //Returns a chunk with the correct size. 
{
    foreach(var item in chunk)
    {
        Console.WriteLine(item);
    }
}

Allowing us to “chunk” data back. I’ve often done similar code when I want to “batch” things, Especially when running things in parallel like so :

var list = Enumerable.Range(1, 100);
var chunkSize = 10;
foreach(var chunk in list.Chunk(chunkSize)) //Returns a chunk with the correct size. 
{
    Parallel.ForEach(chunk, (item) =>
    {
        //Do something Parallel here. 
        Console.WriteLine(item);
    });
}

You’re probably thinking, well why not use Skip and Take? Which is true, I think this is just a bit more concise and makes things just that little bit more readable.

I was thinking that this would be a guide full of examples, and I actually had more here, but there’s nothing really to it. Chunk just does what it says on the tin, and is a welcome addition to the LINQ family.

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.