Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
vermeir_nico_introducing_net_6_getting_started_with_blazor_m.pdf
Скачиваний:
19
Добавлен:
26.06.2023
Размер:
11.64 Mб
Скачать

Chapter 8 Microsoft Azure

Figure 8-32.  Calling a Function from Postman

Wrapping Up

Microsoft Azure is a powerful, globally distributed, versatile platform. The vast majority of available resources is large enough to fill multiple books on its own, so we have only scratched the surface here. I do hope that it has triggered you enough to go explore further and dive into the wonderous world of cloud-native applications and hybrid applications. With .NET being a first-class citizen in the Microsoft world, and .NET 6 being an important major release, it comes as no surprise that Azure was day 1 ready for

.NET 6. Multiple services have supported it even back when .NET 6 was in preview. All of this is made complete with great Azure integration in Visual Studio 2022, allowing us to create resources and publish new code to them without leaving the IDE.

257

CHAPTER 9

Application Architecture

Together with .NET 6 came tooling to help developers build better architectures. Projects like Dapr and example project like eShop On Containers help tremendously with building well-designed and well-architected platforms.

So where can .NET 6 help in building great architectures? There are a few concepts in .NET that help simplify some things; but not to worry, .NET is not pushing you into any direction. We still have full flexibility to architect our applications however we see fit. What we do have is numerous syntax concepts that help keep our code small and readable.

Record Types

The quickest win is Data Transfer Objects, or DTOs. DTOs are a representation of an entity that will be passed over the wire over a data transfer protocol such as HTTP. DTOs are important because they prevent leaking nonpublic, internal information about entities to foreign systems. In most cases, they are a basic class containing auto-­ properties that map in a straightforward way onto the entity that they represent.

Listing 9-1 shows an example of an entity.

Listing 9-1. The entity

public class Event : Entity, IAggregateRoot

{

private readonly List<Attendee.Attendee> _attendees;

public string Title { get; private set; } public DateTime StartDate { get; private set; } public DateTime EndDate { get; private set; } public decimal Price { get; private set; }

259

© Nico Vermeir 2022

N. Vermeir, Introducing .NET 6, https://doi.org/10.1007/978-1-4842-7319-7_9

Chapter 9 Application Architecture

public int? AddressId { get; private set; } public Address Address { get; private set; }

public virtual IReadOnlyCollection<Attendee.Attendee> Attendees => _attendees;

public Event(string title, DateTime startDate, DateTime endDate, decimal price)

{

_attendees = new List<Attendee.Attendee>();

Title = title; StartDate = startDate; EndDate = endDate; Price = price;

}

public void SetAddress(Address address)

{

AddressId = address.Id; Address = address;

}

}

This is a very basic example of an entity from an application build using the Domain-­ Driven-­Design principles. It inherits from Entity, which has an Id property to give us a uniquely identifiable property, and it is an IAggregateRoot, which means that this object can be stored and retrieved on its own. Entities who are not an IAggregateRoot are not meant to exist by themselves; they depend on other objects to be a member of.

Let’s say we need to fetch a list of events to show in our frontend; not using DTOs would mean that we could possibly fetch hundreds of events with all Attendee and Address details, while maybe all we want to do is show a list of upcoming events. To simply, list all events that would be too much data. Instead, we use a DTO to simplify the object that goes over the wire according to the use case we need.

Listing 9-2 shows an example what a DTO could look like for when we want a list of events.

260

Chapter 9 Application Architecture

Listing 9-2.  DTO for listing events

public class EventForList

{

public int Id { get; set; }

public string Title { get; set; }

public DateTime StartDate { get; set; }

public DateTime EndDate { get; set; }

}

Way less data to send over the wire, and just enough. When needing to fetch the details for an Event, we of course need another DTO containing all the info an event detail page might need. You may realize that this can become tedious quite fast, writing DTO after DTO, mapping them to the entity, and so on. A neat compiler trick that came with .NET 5 can help speed this process up; that trick is called records. Listing 9-3 shows the DTO from Listing 9-2 again but written as a record.

Listing 9-3.  DTO as a record

public record ActivityForListRecord (int Id, string Title, DateTime StartDate, DateTime EndDate);

That is one line of code to replace all the auto-properties. A record is a shorthand for writing a class, but there is more to it. Equality, for example, in a normal class, two variables of the same reference type are equal when they point to the same reference. With a record, they are equal when they have the same value. In this case, a class that only contains properties. Another difference is that a record is immutable. The complete documentation on records can be found here https://docs.microsoft.com/en-us/ dotnet/csharp/language-reference/builtin-types/record.

The values between the brackets are not parameters; they are properties, hence the Pascal Casing. As for the output, records are nothing more than a clever compiler trick, a pinch of syntactic sugar. Listing 9-4 compares the intermediate language definition of the EventForList class with the EventForList record. I have renamed them EventForListClass and EventForListRecord for convenience.

261

Chapter 9 Application Architecture

Listing 9-4.  IL output for a record and a class

.class public auto ansi beforefieldinit ActivityForListRecord extends [System.Runtime]System.Object

.class public auto ansi beforefieldinit ActivityForListClass extends [System.Runtime]System.Object

As you can see, the outputs are identical, meaning records are known to the C# compiler but not to the runtime.

New to the C# language since C# 10 is value-type records. Up until now, records could only be reference types, classes. C# 10 introduces record structs which are value-­ type records. Listing 9-5 shows the earlier record example as a value type; notice the struct keyword.

Listing 9-5.  Value-type records

public record struct ActivityForListRecord (int Id, string Title, DateTime StartDate, DateTime EndDate);

Let’s have a look at the IL again. Listing 9-6 shows the generated IL code.

Listing 9-6.  IL output for a record struct and a class

.class public sequential ansi sealed beforefieldinit ActivityForListRecord extends [System.Runtime]System.ValueType

.class public auto ansi beforefieldinit ActivityForListClass extends [System.Runtime]System.Object

Struct records follow the same rules as normal structs. Structs are often used because they are cheaper and memory-wise because they are value-typed. This often results in better performance. They do have limitations when compared to classes, for example, structs don’t allow inheritance. A major difference between records and record structs is that record structs are not immutable by default; they can be if we mark them as readonly.

262