Skip to content

Commit a9a26bc

Browse files
authored
Merge pull request #2 from dotnet-presentations/master
Sync
2 parents 078f563 + 57e0577 commit a9a26bc

File tree

74 files changed

+669
-509
lines changed

Some content is hidden

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

74 files changed

+669
-509
lines changed

Directory.Build.props

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project>
22
<PropertyGroup>
3-
<AspNetCoreVersion>3.1.3</AspNetCoreVersion>
4-
<BlazorVersion>3.2.0-rc1.20223.4</BlazorVersion>
5-
<EntityFrameworkVersion>3.1.3</EntityFrameworkVersion>
6-
<SystemNetHttpJsonVersion>3.2.0-rc1.20217.1</SystemNetHttpJsonVersion>
3+
<AspNetCoreVersion>3.1.4</AspNetCoreVersion>
4+
<BlazorVersion>3.2.0</BlazorVersion>
5+
<EntityFrameworkVersion>3.1.4</EntityFrameworkVersion>
6+
<SystemNetHttpJsonVersion>3.2.0</SystemNetHttpJsonVersion>
77
</PropertyGroup>
88
</Project>

docs/01-components-and-layout.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ The solution already contains four projects:
1515

1616
- **BlazingPizza.Client**: This is the Blazor project. It contains the UI components for the app.
1717
- **BlazingPizza.Server**: This is the ASP.NET Core project hosting the Blazor app and also the backend services for the app.
18-
- **BlazingPizza.Shared**: Shared model types for the app.
19-
- **BlazingPizza.ComponentsLibrary**: A library of components and helper code to be used by the app in later sessions.
18+
- **BlazingPizza.Shared**: This project contains the shared model types for the app.
19+
- **BlazingPizza.ComponentsLibrary**: This is a library of components and helper code to be used by the app in later sessions.
2020

2121
The **BlazingPizza.Server** project should be set as the startup project.
2222

@@ -46,7 +46,7 @@ Add a `@code` block to *Index.razor* with a list field to keep track of the avai
4646
}
4747
```
4848

49-
The code in the `@code` block is added to the generated class for the component. The `PizzaSpecial` type is already defined for you in the Shared project.
49+
The code in the `@code` block is added to the generated class for the component. The `PizzaSpecial` type is already defined for you in the **BlazingPizza.Shared** project.
5050

5151
To get the available list of specials we need to call an API on the backend. Blazor provides a preconfigured `HttpClient` through dependency injection that is already setup with the correct base address. Use the `@inject` directive to inject an `HttpClient` into the `Index` component.
5252

@@ -70,7 +70,7 @@ Override the `OnInitializedAsync` method in the `@code` block to retrieve the li
7070
}
7171
```
7272

73-
The `/specials` API is defined by the `SpecialsController` in the Server project.
73+
The `/specials` API is defined by the `SpecialsController` in the **BlazingPizza.Server** project.
7474

7575
Once the component is initialized it will render its markup. Replace the markup in the `Index` component with the following to list the pizza specials:
7676

@@ -123,7 +123,9 @@ Update the `MainLayout` component to define a top bar with a branding logo and a
123123
@inherits LayoutComponentBase
124124

125125
<div class="top-bar">
126-
<img class="logo" src="img/logo.svg" />
126+
<a class="logo" href="">
127+
<img src="img/logo.svg" />
128+
</a>
127129

128130
<NavLink href="" class="nav-tab" Match="NavLinkMatch.All">
129131
<img src="img/pizza-slice.svg" />

docs/02-customize-a-pizza.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Now we need to implement the pizza customization dialog so we can display it whe
6565

6666
Add a *ConfigurePizzaDialog.razor* file under the *Shared* directory. Since this component is not a separate page, it does not need the `@page` directive.
6767

68-
> Note: In Visual Studio, you can right-click the *Shared* directory in Solution Explorer, then choose *Add* -> *New Item*, then use the *Razor Component* item template.
68+
> Note: In Visual Studio, you can right-click the *Shared* directory in Solution Explorer, then choose *Add* -> *New Item* to use the *Razor Component* item template to add a new Razor component.
6969
7070
The `ConfigurePizzaDialog` should have a `Pizza` parameter that specifies the pizza being configured. Component parameters are defined by adding a writable property to the component decorated with the `[Parameter]` attribute. Add a `@code` block to the `ConfigurePizzaDialog` with the following `Pizza` parameter:
7171

@@ -134,7 +134,7 @@ Now the dialog shows a slider that can be used to change the pizza size. However
134134

135135
![Slider](https://user-images.githubusercontent.com/1430011/57576985-eff40400-7421-11e9-9a1b-b22d96c06bcb.png)
136136

137-
We want the value of the `Pizza.Size` to reflect the value of the slider. When the dialog opens, the slider gets its value from `Pizza.Size`. Moving the slider should update the pizza size stored in `Pizza.Size` accordingly. This concept is called two-way binding.
137+
We want the value of `Pizza.Size` to reflect the value of the slider. When the dialog opens, the slider gets its value from `Pizza.Size`. Moving the slider should update the pizza size stored in `Pizza.Size` accordingly. This concept is called two-way binding.
138138

139139
If you wanted to implement two-way binding manually, you could do so by combining value and @onchange, as in the following code (which you don't actually need to put in your application, because there's an easier solution):
140140

docs/03-show-order-status.md

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Then add a `@code` block that makes an asynchronous request for the data we need
8585

8686
```csharp
8787
@code {
88-
List<OrderWithStatus> ordersWithStatus;
88+
IEnumerable<OrderWithStatus> ordersWithStatus;
8989

9090
protected override async Task OnParametersSetAsync()
9191
{
@@ -108,7 +108,7 @@ It's simple to express this using `@if/else` blocks in Razor code. Update the ma
108108
{
109109
<text>Loading...</text>
110110
}
111-
else if (ordersWithStatus.Count == 0)
111+
else if (!ordersWithStatus.Any())
112112
{
113113
<h2>No orders placed</h2>
114114
<a class="btn btn-success" href="">Order some pizza</a>
@@ -142,7 +142,7 @@ Asynchronous work when applying parameters and property values must occur during
142142

143143
### 5. How can I reset the database?
144144

145-
If you want to reset your database to see the "no orders" case, simply delete `pizza.db` from the Server project and reload the page in your browser.
145+
If you want to reset your database to see the "no orders" case, simply delete `pizza.db` from the **BlazingPizza.Server** project and reload the page in your browser.
146146

147147
![My orders empty list](https://user-images.githubusercontent.com/1874516/77241390-a4b49100-6bae-11ea-8dd4-e59afdd8f710.png)
148148

@@ -199,7 +199,7 @@ Once again we'll add a component to handle this. In the `Pages` directory, creat
199199
}
200200
```
201201

202-
This code illustrates how components can receive parameters from the router by declaring them as tokens in the `@page` directive. If you want to receive a `string`, the syntax is simply `{parameterName}`, which matches a `[Parameter]` name case-insensitively. If you want to receive a numeric value, the syntax is `{parameterName:int}`, as in the example above. The `:int` is an example of a *route constraint*. Other route constraints are supported too.
202+
This code illustrates how components can receive parameters from the router by declaring them as tokens in the `@page` directive. If you want to receive a `string`, the syntax is simply `{parameterName}`, which matches a `[Parameter]` name case-insensitively. If you want to receive a numeric value, the syntax is `{parameterName:int}`, as in the example above. The `:int` is an example of a *route constraint*. Other route constraints, such as bool, datetime and guid, are also supported.
203203

204204
![Order details empty](https://user-images.githubusercontent.com/1874516/77241434-391ef380-6baf-11ea-9803-9e7e65a4ea2b.png)
205205

@@ -259,17 +259,24 @@ Now you can implement the polling. Update your `@code` block as follows:
259259
{
260260
invalidOrder = false;
261261
orderWithStatus = await HttpClient.GetFromJsonAsync<OrderWithStatus>($"orders/{OrderId}");
262+
StateHasChanged();
263+
264+
if (orderWithStatus.IsDelivered)
265+
{
266+
pollingCancellationToken.Cancel();
267+
}
268+
else
269+
{
270+
await Task.Delay(4000);
271+
}
262272
}
263273
catch (Exception ex)
264274
{
265275
invalidOrder = true;
266276
pollingCancellationToken.Cancel();
267277
Console.Error.WriteLine(ex);
278+
StateHasChanged();
268279
}
269-
270-
StateHasChanged();
271-
272-
await Task.Delay(4000);
273280
}
274281
}
275282
}
@@ -280,7 +287,7 @@ The code is a bit intricate, so be sure to go through it carefully to understand
280287
* This uses `OnParametersSet` instead of `OnInitialized` or `OnInitializedAsync`. `OnParametersSet` is another component lifecycle method, and it fires when the component is first instantiated *and* any time its parameters change value. If the user clicks a link directly from `myorders/2` to `myorders/3`, the framework will retain the `OrderDetails` instance and simply update its `OrderId` parameter in place.
281288
* As it happens, we haven't provided any links from one "my orders" screen to another, so the scenario never occurs in this application, but it's still the right lifecycle method to use in case we change the navigation rules in the future.
282289
* We're using an `async void` method to represent the polling. This method runs for arbitrarily long, even while other methods run. `async void` methods have no way to report exceptions upstream to callers (because typically the callers have already finished), so it's important to use `try/catch` and do something meaningful with any exceptions that may occur.
283-
* We're using `CancellationTokenSource` as a way of signalling when the polling should stop. Currently it only stops if there's an exception, but we'll add another stopping condition later.
290+
* We're using `CancellationTokenSource` as a way of signalling when the polling should stop. Currently it stops if there's an exception, or once the order is delivered.
284291
* We need to call `StateHasChanged` to tell Blazor that the component's data has (possibly) changed. The framework will then re-render the component. There's no way that the framework could know when to re-render your component otherwise, because it doesn't know about your polling logic.
285292

286293
## Rendering the order details

docs/04-refactor-state-management.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static async Task Main(string[] args)
2020
var builder = WebAssemblyHostBuilder.CreateDefault(args);
2121
builder.RootComponents.Add<App>("app");
2222

23-
builder.Services.AddBaseAddressHttpClient();
23+
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
2424
builder.Services.AddScoped<OrderState>();
2525

2626
await builder.Build().RunAsync();

0 commit comments

Comments
 (0)