Book Image

C# 8 and .NET Core 3 Projects Using Azure - Second Edition

By : Paul Michaels, Dirk Strauss, Jas Rademeyer
Book Image

C# 8 and .NET Core 3 Projects Using Azure - Second Edition

By: Paul Michaels, Dirk Strauss, Jas Rademeyer

Overview of this book

.NET Core is a general-purpose, modular, cross-platform, and opensource implementation of .NET. The latest release of .NET Core 3 comes with improved performance and security features, along with support for desktop applications. .NET Core 3 is not only useful for new developers looking to start learning the framework, but also for legacy developers interested in migrating their apps. Updated with the latest features and enhancements, this updated second edition is a step-by-step, project-based guide. The book starts with a brief introduction to the key features of C# 8 and .NET Core 3. You'll learn to work with relational data using Entity Framework Core 3, before understanding how to use ASP.NET Core. As you progress, you’ll discover how you can use .NET Core to create cross-platform applications. Later, the book will show you how to upgrade your old WinForms apps to .NET Core 3. The concluding chapters will then help you use SignalR effectively to add real-time functionality to your applications, before demonstrating how to implement MongoDB in your apps. Finally, you'll delve into serverless computing and how to build microservices using Docker and Kubernetes. By the end of this book, you'll be proficient in developing applications using .NET Core 3.
Table of Contents (13 chapters)

Understanding nullable reference types

In .NET Core 2.1 (or any previous version of .NET), we could legitimately type the following code and run it:

string test = null;
Console.WriteLine(test.Length);

And, of course it would crash. Obviously, no-one familiar with the language would write this; however, they might write something as follows:

string test = FunctionCanReturnNull();
Console.WriteLine(test.Length);

Nullable reference types are an opt-in feature (that is, you have to explicitly turn it on) that simply gives a warning to say that you have a potential for a reference type to be null. Let's try turning this on for our Ebook Manager. It can be turned on a class-by-class basis by adding the following directive to the top of a file:

#nullable enable

However, you can also switch it on for the entire project by adding the following line to the .csproj file:

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

At the time of writing, this property will be automatically added to the .csproj file.
There are other options that the Nullable option can be configured for; for further information, see the following URL:

https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references

This is a granular feature, so it can be turned off or on for specific sections of code. There are a few warnings that pop up, so let's focus on StorageSpace.cs:

So, what exactly is this telling us?

To answer that, let's look first at ID. ID is a value type, and therefore cannot be null. If nothing is assigned to ID, it will have the default value: 0. Name, however is a string (which is a reference type), and therefore can be null and, in fact, will be null unless we set it otherwise. If we want one of these fields to be nullable, then we can certainly do that (and in the case of Description, we probably should):

But what about Name? We would probably not want that to be null. There's a couple of options here; one is to add a blank string as a default initializer as follows:

public string Name { get; set; } = string.Empty;

This isn't ideal. In fact, getting a null reference exception might actually be preferable to it being blank and bypassing that.


This is just my opinion, but it is much better to have software crash at runtime and alert you to an error in the logic than to soldier on and potentially corrupt data or, worse, request or update data in a third-party system!

Another option is to add a constructor. The following is an example:

[Serializable]
public class StorageSpace
{
    public StorageSpace(string name)
    {
        Name = name;
    }
    public int ID { get; set; }
    public string Name { get; set; }
    public string? Description { get; set; }
    public List<Document>? BookList { get; set; }
}

This clears up the warnings and ensures that anyone creating the class provides a name, which we are saying can never be null. This is instantiated in ImportBooks.cs, so now we'll have to provide that parameter:

private void btnSaveNewStorageSpace_Click(object sender, EventArgs e)
{
    try
    {
        if (txtNewStorageSpaceName.Text.Length != 0)
        {
            string newName = txtNewStorageSpaceName.Text;
 
 
            // null conditional operator: "spaces?.StorageSpaceExists(newName) ?? false"
            // throw expressions: bool spaceExists = (space exists = false) ? return false : throw exception                    
            // Out variables
            bool spaceExists = (!spaces.StorageSpaceExists(newName, out int nextID)) ? false : throw new Exception("The storage space you are trying to add already exists.");
                                
            if (!spaceExists)
            {
                StorageSpace newSpace = new StorageSpace(newName);                        
                newSpace.ID = nextID;
                newSpace.Description = txtStorageSpaceDescription.Text;
                spaces.Add(newSpace);

Now we know that the Name property can never be null, it's worth remembering that the warnings that you get here are just that, warnings; and, like all warnings, it is your prerogative to ignore them. However, C# 8 does have a feature (which I've heard referred to as the dammit operator) that allows you to insist that, despite what the compiler believes, you know the variable will not be null; it looks as follows:

string test = null;
 
Console.WriteLine(test!.Length);
Console.ReadLine();

Obviously, if you do this, the preceding code will crash, so if you do decide that you know better than the compiler, be sure!