Skip to content

Commit 68a3a58

Browse files
authored
Merge branch 'aspnet-ebook-net6' into ardalis/modernwebapps6
2 parents ad4cc48 + 265578d commit 68a3a58

File tree

108 files changed

+296
-232
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+296
-232
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"F#",
1414
"HashiCorp Configuration Language (HCL)",
1515
"HTML",
16+
"HTTP",
1617
"Ini",
1718
"JavaScript",
1819
"JSON",

docs/architecture/microservices/docker-application-development-process/docker-app-development-workflow.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ This section describes the *inner-loop* development workflow for Docker containe
2121

2222
An application is composed of your own services plus additional libraries (dependencies). The following are the basic steps you usually take when building a Docker application, as illustrated in Figure 5-1.
2323

24-
:::image type="complex" source="./media/docker-app-development-workflow/life-cycle-containerized-apps-docker-cli.png" alt-text="Diagram showing the 7 steps it takes to create a containerized app.":::
24+
:::image type="complex" source="./media/docker-app-development-workflow/life-cycle-containerized-apps-docker-cli.png" alt-text="Diagram showing the seven steps it takes to create a containerized app.":::
2525
The development process for Docker apps: 1 - Code your App, 2 - Write Dockerfile/s, 3 - Create images defined at Dockerfile/s, 4 - (optional) Compose services in the docker-compose.yml file, 5 - Run container or docker-compose app, 6 - Test your app or microservices, 7 - Push to repo and repeat.
2626
:::image-end:::
2727

@@ -407,7 +407,7 @@ Besides adding a Dockerfile to a project, as we mentioned before, Visual Studio
407407

408408
When you add container orchestrator support, as shown in Figure 5-7, for the first time, Visual Studio creates the Dockerfile for the project and creates a new (service section) project in your solution with several global `docker-compose*.yml` files, and then adds the project to those files. You can then open the docker-compose.yml files and update them with additional features.
409409

410-
You have to repeat this operation for every project you want to include in the docker-compose.yml file.
410+
Repeat this operation for every project you want to include in the docker-compose.yml file.
411411

412412
At the time of this writing, Visual Studio supports **Docker Compose** and **Kubernetes/Helm** orchestrators.
413413

@@ -508,7 +508,7 @@ This step will vary depending on what your application is doing. In a simple .NE
508508

509509
If localhost is not pointing to the Docker host IP (by default, when using Docker CE, it should), to navigate to your service, use the IP address of your machine's network card.
510510

511-
Note that this URL in the browser uses port 80 for the particular container example being discussed. However, internally the requests are being redirected to port 5000, because that was how it was deployed with the docker run command, as explained in a previous step.
511+
This URL in the browser uses port 80 for the particular container example being discussed. However, internally the requests are being redirected to port 5000, because that was how it was deployed with the docker run command, as explained in a previous step.
512512

513513
You can also test the application using curl from the terminal, as shown in Figure 5-14. In a Docker installation on Windows, the default Docker Host IP is always 10.0.75.1 in addition to your machine's actual IP address.
514514

docs/architecture/microservices/microservice-ddd-cqrs-patterns/implement-value-objects.md

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Implementing value objects
33
description: .NET Microservices Architecture for Containerized .NET Applications | Get into the details and options to implement value objects using new Entity Framework features.
4-
ms.date: 08/21/2020
4+
ms.date: 11/11/2021
55
---
66

77
# Implement value objects
@@ -16,7 +16,7 @@ Figure 7-13 shows the Address value object within the Order aggregate.
1616

1717
**Figure 7-13**. Address value object within the Order aggregate
1818

19-
As shown in Figure 7-13, an entity is usually composed of multiple attributes. For example, the `Order` entity can be modeled as an entity with an identity and composed internally of a set of attributes such as OrderId, OrderDate, OrderItems, etc. But the address, which is simply a complex-value composed of country/region, street, city, etc. and has no identity in this domain, must be modeled and treated as a value object.
19+
As shown in Figure 7-13, an entity is usually composed of multiple attributes. For example, the `Order` entity can be modeled as an entity with an identity and composed internally of a set of attributes such as OrderId, OrderDate, OrderItems, etc. But the address, which is simply a complex-value composed of country/region, street, city, etc., and has no identity in this domain, must be modeled and treated as a value object.
2020

2121
## Important characteristics of value objects
2222

@@ -75,7 +75,23 @@ public abstract class ValueObject
7575
}
7676
```
7777

78-
You can use this class when implementing your actual value object, as with the Address value object shown in the following example:
78+
<a id="equal-op-overload"></a>
79+
80+
The `ValueObject` is an `abstract class` type, but in this example, it doesn't overload the `==` and `!=` operators. You could choose to do so, making comparisons delegate to the `Equals` override. For example, consider the following operator overloads to the `ValueObject` type:
81+
82+
```csharp
83+
public static bool operator ==(ValueObject one, ValueObject two)
84+
{
85+
return one?.Equals(two) ?? false;
86+
}
87+
88+
public static bool operator !=(ValueObject one, ValueObject two)
89+
{
90+
return !(one?.Equals(two) ?? false);
91+
}
92+
```
93+
94+
You can use this class when implementing your actual value object, as with the `Address` value object shown in the following example:
7995

8096
```csharp
8197
public class Address : ValueObject
@@ -109,12 +125,28 @@ public class Address : ValueObject
109125
}
110126
```
111127

112-
You can see how this value object implementation of Address has no identity and therefore, no ID field, neither at the Address class not even at the ValueObject class.
128+
This value object implementation of `Address` has no identity, and therefore no ID field is defined for it, either in the `Address` class definition or the `ValueObject` class definition.
113129

114130
Having no ID field in a class to be used by Entity Framework (EF) was not possible until EF Core 2.0, which greatly helps to implement better value objects with no ID. That is precisely the explanation of the next section.
115131

116132
It could be argued that value objects, being immutable, should be read-only (that is, have get-only properties), and that's indeed true. However, value objects are usually serialized and deserialized to go through message queues, and being read-only stops the deserializer from assigning values, so you just leave them as `private set`, which is read-only enough to be practical.
117133

134+
### Value object comparison semantics
135+
136+
Two instances of the `Address` type can be compared using all the following methods:
137+
138+
```csharp
139+
var one = new Address("1 Microsoft Way", "Redmond", "WA", "US", "98052");
140+
var two = new Address("1 Microsoft Way", "Redmond", "WA", "US", "98052");
141+
142+
Console.WriteLine(EqualityComparer<Address>.Default.Equals(one, two)); // True
143+
Console.WriteLine(object.Equals(one, two)); // True
144+
Console.WriteLine(one.Equals(two)); // True
145+
Console.WriteLine(one == two); // True
146+
```
147+
148+
When all the values are the same, the comparisons are correctly evaluated as `true`. If you didn't choose to overload the `==` and `!=` operators, then the last comparison of `one == two` would evaluate as `false`. For more information, see [Overload ValueObject equality operators](#equal-op-overload).
149+
118150
## How to persist value objects in the database with EF Core 2.0 and later
119151

120152
You just saw how to define a value object in your domain model. But how can you actually persist it into the database using Entity Framework Core since it usually targets entities with identity?

docs/architecture/microservices/multi-container-microservice-net-applications/rabbitmq-event-bus-development-test-environment.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Each event type has a related channel to get events from RabbitMQ. You can then
102102

103103
The Subscribe method accepts an IIntegrationEventHandler object, which is like a callback method in the current microservice, plus its related IntegrationEvent object. The code then adds that event handler to the list of event handlers that each integration event type can have per client microservice. If the client code has not already been subscribed to the event, the code creates a channel for the event type so it can receive events in a push style from RabbitMQ when that event is published from any other service.
104104

105-
As mentioned above, the event bus implemented in eShopOnContainers has only and educational purpose, since it only handles the main scenarios, so it's not ready for production.
105+
As mentioned above, the event bus implemented in eShopOnContainers has only an educational purpose, since it only handles the main scenarios, so it's not ready for production.
106106

107107
For production scenarios check the additional resources below, specific for RabbitMQ, and the [Implementing event-based communication between microservices](./integration-event-based-microservice-communications.md#additional-resources) section.
108108

docs/architecture/modern-web-apps-azure/work-with-data-in-asp-net-core-apps.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ no-loc: [Blazor, WebAssembly]
1212
>
1313
> Tim Berners-Lee
1414
15-
Data access is an important part of almost any software application. ASP.NET Core supports a variety of data access options, including Entity Framework Core (and Entity Framework 6 as well), and can work with any .NET data access framework. The choice of which data access framework to use depends on the application's needs. Abstracting these choices from the ApplicationCore and UI projects, and encapsulating implementation details in Infrastructure, helps to produce loosely coupled, testable software.
15+
Data access is an important part of almost any software application. ASP.NET Core supports various data access options, including Entity Framework Core (and Entity Framework 6 as well), and can work with any .NET data access framework. The choice of which data access framework to use depends on the application's needs. Abstracting these choices from the ApplicationCore and UI projects, and encapsulating implementation details in Infrastructure, helps to produce loosely coupled, testable software.
1616

1717
## Entity Framework Core (for relational databases)
1818

@@ -184,7 +184,7 @@ private void ConfigureBasket(EntityTypeBuilder<Basket> builder)
184184
}
185185
```
186186

187-
Another way in which you can improve your domain model is through the use of value objects for types that lack identity and are only distinguished by their properties. Using such types as properties of your entities can help keep logic specific to the value object where it belongs, and can avoid duplicate logic between multiple entities that use the same concept. In Entity Framework Core, you can persist value objects in the same table as their owning entity by configuring the type as an owned entity, like so:
187+
Another way in which you can improve your domain model is by using value objects for types that lack identity and are only distinguished by their properties. Using such types as properties of your entities can help keep logic specific to the value object where it belongs, and can avoid duplicate logic between multiple entities that use the same concept. In Entity Framework Core, you can persist value objects in the same table as their owning entity by configuring the type as an owned entity, like so:
188188

189189
```csharp
190190
private void ConfigureOrder(EntityTypeBuilder<Order> builder)
@@ -298,7 +298,7 @@ public async Task<IEnumerable<CatalogType>> GetCatalogTypesWithDapper()
298298
}
299299
```
300300

301-
If you need to build more complex object graphs with Dapper, you need to write the associated queries yourself (as opposed to adding an Include as you would in EF Core). This functionality is supported through a variety of syntaxes, including a feature called Multi Mapping that lets you map individual rows to multiple mapped objects. For example, given a class Post with a property Owner of type User, the following SQL would return all of the necessary data:
301+
If you need to build more complex object graphs with Dapper, you need to write the associated queries yourself (as opposed to adding an Include as you would in EF Core). This functionality is supported through various syntaxes, including a feature called Multi Mapping that lets you map individual rows to multiple mapped objects. For example, given a class Post with a property Owner of type User, the following SQL would return all of the necessary data:
302302

303303
```sql
304304
select * from #Posts p
@@ -355,7 +355,7 @@ The Azure Cosmos DB query language is a simple yet powerful interface for queryi
355355

356356
## Other persistence options
357357

358-
In addition to relational and NoSQL storage options, ASP.NET Core applications can use Azure Storage to store a variety of data formats and files in a cloud-based, scalable fashion. Azure Storage is massively scalable, so you can start out storing small amounts of data and scale up to storing hundreds or terabytes if your application requires it. Azure Storage supports four kinds of data:
358+
In addition to relational and NoSQL storage options, ASP.NET Core applications can use Azure Storage to store various data formats and files in a cloud-based, scalable fashion. Azure Storage is massively scalable, so you can start out storing small amounts of data and scale up to storing hundreds or terabytes if your application requires it. Azure Storage supports four kinds of data:
359359

360360
- Blob Storage for unstructured text or binary storage, also referred to as object storage.
361361

docs/architecture/modernize-desktop/whats-new-dotnet.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ Starting with .NET Core 3.0, besides the existing support for web and cloud, the
5555
.NET 5 is the next step forward with .NET Core. .NET 5 aims to improve .NET in a few key ways:
5656

5757
- Produce a single .NET runtime and framework that can be used everywhere and that has uniform runtime behaviors and developer experiences.
58-
- Expand the capabilities of .NET by taking the best of .NET Core, .NET Framework, Xamarin and Mono.
58+
- Expand the capabilities of .NET by taking the best of .NET Core, .NET Framework, Xamarin, and Mono.
5959
- Build that product out of a single code-base that developers (Microsoft and the community) can work on and expand together and that improves all scenarios.
6060

61-
This new release and direction are a game-changer for .NET. With .NET 5, your code and project files will look and feel the same no matter which type of app you're building. You’ll have access to the same runtime, APIs, and language capabilities with each app. This includes new [performance improvements](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/) that get committed to the runtime, practically daily. For more details refer [What's new in .NET 5](../../core/whats-new/dotnet-5.md).
61+
This new release and direction are a game-changer for .NET. With .NET 5, your code and project files will look and feel the same no matter which type of app you're building. You’ll have access to the same runtime, APIs, and language capabilities with each app. This includes new [performance improvements](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/) that get committed to the runtime, practically daily. For more details, see [What's new in .NET 5](../../core/whats-new/dotnet-5.md).
6262

6363
![All domains of .NET 5](./media/whats-new-dotnet-core/all-domains-of-dotnet5.png)
6464

@@ -125,7 +125,7 @@ To make it easier to create XAML Islands for Windows Forms and WPF developers, t
125125

126126
### Access to all Windows 10 APIs
127127

128-
Windows 10 has a great amount of API available for developers to work with. These APIs give access to a wide variety of functionality like Authentication, Bluetooth, Appointments, and Contacts. Now these APIs are exposed through .NET Core and give Windows developers the chance to create powerful desktops apps leveraging the capabilities present on Windows 10.
128+
Windows 10 has a great amount of API available for developers to work with. These APIs give access to a wide variety of functionality like Authentication, Bluetooth, Appointments, and Contacts. Now these APIs are exposed through .NET Core and give Windows developers the chance to create powerful desktops apps using the capabilities present on Windows 10.
129129

130130
### Side-by-side support and self-contained EXEs
131131

docs/architecture/porting-existing-aspnet-apps/example-migration-eshop.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ That leaves the *Controllers* folder and its two `Controller` classes. After cop
168168

169169
> `Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'`
170170
171-
To resolve this error add a NuGet package reference to C#:
171+
To resolve this error, add a NuGet package reference to C#:
172172

173173
```xml
174174
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
@@ -493,7 +493,7 @@ For now, the setting for `useMockData` is set to `true`. This setting will be re
493493

494494
#### Migrate app settings
495495

496-
ASP.NET Core uses a new [configuration system](/aspnet/core/fundamentals/configuration/?preserve-view=true&view=aspnetcore-2.2), which by default leverages an *appsettings.json* file. By using `CreateDefaultBuilder` in *Program.cs*, the default configuration is already set up in the app. To access configuration, classes just need to request it in their constructor. The `Startup` class is no exception. To start accessing configuration in `Startup` and the rest of the app, request an instance of `IConfiguration` from its constructor:
496+
ASP.NET Core uses a new [configuration system](/aspnet/core/fundamentals/configuration/?preserve-view=true&view=aspnetcore-2.2), which by default uses an *appsettings.json* file. By using `CreateDefaultBuilder` in *Program.cs*, the default configuration is already set up in the app. To access configuration, classes just need to request it in their constructor. The `Startup` class is no exception. To start accessing configuration in `Startup` and the rest of the app, request an instance of `IConfiguration` from its constructor:
497497

498498
```csharp
499499
public Startup(IConfiguration configuration)
@@ -550,7 +550,7 @@ The app's migration is nearly complete. The only remaining task is data access c
550550

551551
## Data access considerations
552552

553-
ASP.NET Core apps running on .NET Framework can continue to leverage Entity Framework (EF). If performing an incremental migration, getting the app working with EF 6 before trying to port its data access to use EF Core may be worthwhile. In this way, any problems with the app's migration can be identified and addressed before another block of migration effort is begun.
553+
ASP.NET Core apps running on .NET Framework can continue to use Entity Framework (EF). If performing an incremental migration, getting the app working with EF 6 before trying to port its data access to use EF Core may be worthwhile. In this way, any problems with the app's migration can be identified and addressed before another block of migration effort is begun.
554554

555555
As it happens, configuring EF 6 in the eShop sample migration doesn't require any special work, since this work was performed in the Autofac `ApplicationModule`. The only problem is that currently the `CatalogDBContext` class tries to read its connection string from *web.config*. To address this, the connection details need to be added to *appsettings.json*. Then the connection string must be passed into `CatalogDBContext` when it's created.
556556

0 commit comments

Comments
 (0)