Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nullable #365

Merged
merged 53 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
ee2273e
Shared lib updated with Nullable context. Partially fixes issue #105.
EdCharbeneau Sep 6, 2023
d2669b4
Server updated with Nullable context. Partially fixes issue #105.
EdCharbeneau Sep 6, 2023
c8e742f
Razor projects updated with Nullable context. Partially fixes issue #…
EdCharbeneau Sep 6, 2023
b320741
01 updated with Nullable context, including instructions (md). Partia…
EdCharbeneau Sep 12, 2023
560bd5c
Updated 02. Dependencies to use Nullable
EdCharbeneau Sep 15, 2023
1e558ac
Updated code to include nullable considerations.
EdCharbeneau Sep 15, 2023
f9b6aa8
Updated instructions to align with nullable.
EdCharbeneau Sep 15, 2023
c240c05
Updated dependencies to use nullable context
EdCharbeneau Sep 15, 2023
1e5e283
Fixes issue #358 and Fixes issue #238
EdCharbeneau Sep 15, 2023
ad569ae
Sync with previous lesson
EdCharbeneau Sep 15, 2023
c4a0b11
Removed guard on GetUserId to allow workshop to flow without authoriz…
EdCharbeneau Sep 15, 2023
ecc0012
Sync changes across lessons
EdCharbeneau Sep 15, 2023
d106944
Updated 03 with nullability context
EdCharbeneau Sep 15, 2023
36184a4
Updated instructions with nullable code
EdCharbeneau Sep 15, 2023
e72e41b
Cleanup whitespace
EdCharbeneau Sep 15, 2023
38d08c1
Sync dependencies 04 with previous steps
EdCharbeneau Sep 15, 2023
6c77e8b
Fixed: Starting point 04's server code was actually from a later step…
EdCharbeneau Sep 15, 2023
8c85b72
Sync 04 client changes with previous steps
EdCharbeneau Sep 15, 2023
a13e07a
Updated client with nullable context enabled
EdCharbeneau Sep 15, 2023
f9ade8f
Sync dependencies 05 with previous changes
EdCharbeneau Sep 15, 2023
6fda4d3
Fixed step 05 controller is from step 06
EdCharbeneau Sep 15, 2023
acce7ac
Sync with client with previous step
EdCharbeneau Sep 15, 2023
2157016
Updated 05 with nullable context enabled
EdCharbeneau Sep 15, 2023
70052e7
Sync with previous steps
EdCharbeneau Sep 15, 2023
c7d2d48
Updated 06 with nullable context enabled.
EdCharbeneau Sep 15, 2023
1279c3f
Synced dependencies with previous lesson
EdCharbeneau Sep 18, 2023
dcd325d
Sync client changes with previous step
EdCharbeneau Sep 18, 2023
2773808
Updated 07 with nullable context enabled
EdCharbeneau Sep 18, 2023
2c76f8b
Synced dependencies with previous step
EdCharbeneau Sep 18, 2023
09cda9f
Synced client with previous lesson
EdCharbeneau Sep 18, 2023
038e53c
Updated 08 with nullable conetext enabled
EdCharbeneau Sep 18, 2023
c3ea048
Sync with prevous lesson
EdCharbeneau Sep 18, 2023
f3539c4
Updated 09 with nullable context enabled
EdCharbeneau Sep 18, 2023
9ea1c99
Updated src with nullable context enabled
EdCharbeneau Sep 19, 2023
def0f14
Updated docs
EdCharbeneau Sep 20, 2023
7747b65
Notification interop doesn't work with required.
EdCharbeneau Sep 20, 2023
7195eb2
Extra sln file
EdCharbeneau Sep 20, 2023
a2e5a47
Fixed link that moved for getting started
EdCharbeneau Sep 21, 2023
175f438
Removed extra comments.
EdCharbeneau Sep 21, 2023
c26f1af
Clairified the message about EditorRequired.
EdCharbeneau Sep 21, 2023
e7fb767
Trimmed whitespace
EdCharbeneau Sep 21, 2023
59125da
Supressed nullable warning on change event
EdCharbeneau Sep 21, 2023
5c1c94a
Added EditorRequired to step
EdCharbeneau Sep 21, 2023
6fe4eef
Refactored GetUserId. This code was duplicated in multiple places.
EdCharbeneau Sep 21, 2023
51ea18c
Updated `!=` to `is not` null
EdCharbeneau Sep 21, 2023
63efdf4
Fixes: SignoutSessionStateManager obsolete warning. See: https://lear…
EdCharbeneau Sep 21, 2023
b11af38
Added Nullable to orderWithStatus
EdCharbeneau Sep 21, 2023
f0bfc87
Updated Razor Class Library verbage, it was reminicent of .NET Core 3…
EdCharbeneau Sep 21, 2023
d551aed
Changed `!=` to `is not null`
EdCharbeneau Sep 21, 2023
474c164
The app was updated to include a Minimal API implementation of Notifi…
EdCharbeneau Sep 21, 2023
6fbd4cd
Pulling up some missed changes from the final exercise
EdCharbeneau Sep 21, 2023
d6a3d9e
Removed unused NavigationManager references
EdCharbeneau Sep 21, 2023
4a7346a
Updated code on Map component
EdCharbeneau Sep 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,6 @@ ASALocalRun/

# Visual Studio Code folder
.vscode/
*.db-shm
*.db-wal
/save-points/08-templated-components/BlazingPizza.Client/BlazingPizza.Client.sln
2 changes: 1 addition & 1 deletion docs/00-get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ In this session, you'll setup your machine for Blazor development and build your

## Setup

To get started with Blazor, follow the getting instructions on [blazor.net](https://blazor.net).
To get started with Blazor, follow the getting instructions on [blazor.net](https://dotnet.microsoft.com/en-us/learn/aspnet/blazor-tutorial/intro).

## Build your first app

Expand Down
6 changes: 3 additions & 3 deletions docs/01-components-and-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Add a `@code` block to *Index.razor* with a list field to keep track of the avai

```csharp
@code {
List<PizzaSpecial> specials;
List<PizzaSpecial>? specials;
}
```

Expand All @@ -61,7 +61,7 @@ Override the `OnInitializedAsync` method in the `@code` block to retrieve the li

```csharp
@code {
List<PizzaSpecial> specials;
List<PizzaSpecial>? specials;

protected override async Task OnInitializedAsync()
{
Expand All @@ -81,7 +81,7 @@ Once the component is initialized it will render its markup. Replace the markup
```html
<div class="main">
<ul class="pizza-cards">
@if (specials != null)
@if (specials is not null)
{
@foreach (var special in specials)
{
Expand Down
92 changes: 51 additions & 41 deletions docs/02-customize-a-pizza.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ The `@` symbol is used in Razor files to indicate the start of C# code. Surround
Update the `@code` block in *Index.razor* to add some additional fields for tracking the pizza being customized and whether the pizza customization dialog is visible.

```csharp
List<PizzaSpecial> specials;
Pizza configuringPizza;
List<PizzaSpecial>? specials;
Pizza? configuringPizza;
bool showingConfigureDialog;
```

Expand Down Expand Up @@ -67,11 +67,13 @@ Add a *ConfigurePizzaDialog.razor* file under the *Shared* directory. Since this

> 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.

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:
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. Because the `Pizza` parameter requires a value for the component to function, the `[EditorRequired]` attribute is also added. By adding the `[EditorRequired]` attribute, if a parameter value isn't provided, editors or build tools may display warnings to the user.

Add a `@code` block to the `ConfigurePizzaDialog` with the following `Pizza` parameter:

```csharp
@code {
[Parameter] public Pizza Pizza { get; set; }
[Parameter, EditorRequired] public Pizza Pizza { get; set; } = new();
}
```

Expand All @@ -80,22 +82,22 @@ The `ConfigurePizzaDialog` should have a `Pizza` parameter that specifies the pi
Add the following basic markup for the `ConfigurePizzaDialog`:

```html
<div class="dialog-container">
<div class="dialog">
<div class="dialog-title">
<h2>@Pizza.Special.Name</h2>
@Pizza.Special.Description
</div>
<form class="dialog-body"></form>
<div class="dialog-buttons">
<button class="btn btn-secondary mr-auto">Cancel</button>
<span class="mr-center">
Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
</span>
<button class="btn btn-success ml-auto">Order</button>
<div class="dialog-container">
<div class="dialog">
<div class="dialog-title">
<h2>@Pizza.Special?.Name</h2>
@Pizza.Special?.Description
</div>
<form class="dialog-body"></form>
<div class="dialog-buttons">
<button class="btn btn-secondary mr-auto">Cancel</button>
<span class="mr-center">
Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
</span>
<button class="btn btn-success ml-auto">Order</button>
</div>
</div>
</div>
</div>
```

Update *Pages/Index.razor* to show the `ConfigurePizzaDialog` when a pizza special has been selected. The `ConfigurePizzaDialog` is styled to overlay the current page, so it doesn't really matter where you put this code block.
Expand Down Expand Up @@ -145,7 +147,7 @@ If you wanted to implement two-way binding manually, you could do so by combinin
max="@Pizza.MaximumSize"
step="1"
value="@Pizza.Size"
@onchange="@((ChangeEventArgs e) => Pizza.Size = int.Parse((string) e.Value))" />
@onchange="@((ChangeEventArgs e) => Pizza.Size = int.Parse((string?) e.Value))" />
```

In Blazor you can use the `@bind` directive attribute to specify a two-way binding with this same behavior. The equivalent markup using `@bind` looks like this:
Expand Down Expand Up @@ -180,13 +182,14 @@ The user should also be able to select additional toppings on `ConfigurePizzaDia
</div>

@code {
List<Topping> toppings;
// toppings is only null while loading
List<Topping> toppings = null!;

[Parameter] public Pizza Pizza { get; set; }
[Parameter, EditorRequired] public Pizza Pizza { get; set; } = default!;

protected async override Task OnInitializedAsync()
{
toppings = await HttpClient.GetFromJsonAsync<List<Topping>>("toppings");
toppings = await HttpClient.GetFromJsonAsync<List<Topping>>("toppings") ?? new();
}
}
```
Expand All @@ -196,7 +199,7 @@ Add the following markup in the dialog body for displaying a drop down list with
```html
<div>
<label>Extra Toppings:</label>
@if (toppings == null)
@if (toppings is null)
{
<select class="custom-select" disabled>
<option>(loading...)</option>
Expand All @@ -221,11 +224,14 @@ Add the following markup in the dialog body for displaying a drop down list with
<div class="toppings">
@foreach (var topping in Pizza.Toppings)
{
<div class="topping">
@topping.Topping.Name
<span class="topping-price">@topping.Topping.GetFormattedPrice()</span>
<button type="button" class="delete-topping" @onclick="@(() => RemoveTopping(topping.Topping))">x</button>
</div>
if (topping?.Topping is not null)
{
<div class="topping">
@topping.Topping.Name
<span class="topping-price">@topping.Topping.GetFormattedPrice()</span>
<button type="button" class="delete-topping" @onclick="@(() => RemoveTopping(topping.Topping))">x</button>
</div>
}
}
</div>
```
Expand All @@ -235,15 +241,16 @@ Also add the following event handlers for topping selection and removal:
```csharp
void ToppingSelected(ChangeEventArgs e)
{
if (int.TryParse((string)e.Value, out var index) && index >= 0)
if (int.TryParse((string?)e.Value, out var index) && index >= 0)
{
AddTopping(toppings[index]);
}
}

void AddTopping(Topping topping)
{
if (Pizza.Toppings.Find(pt => pt.Topping == topping) == null)
if (toppings is null) return;
if (Pizza.Toppings.Find(pt => pt.Topping == topping) is null)
{
Pizza.Toppings.Add(new PizzaTopping() { Topping = topping });
}
Expand All @@ -267,8 +274,8 @@ The Cancel and Order buttons don't do anything yet. We need some way to communic
Add two parameters to the `ConfigurePizzaDialog` component: `OnCancel` and `OnConfirm`. Both parameters should be of type `EventCallback`.

```csharp
[Parameter] public EventCallback OnCancel { get; set; }
[Parameter] public EventCallback OnConfirm { get; set; }
[Parameter, EditorRequired] public EventCallback OnCancel { get; set; }
[Parameter, EditorRequired] public EventCallback OnConfirm { get; set; }
```

Add `@onclick` event handlers to the `ConfigurePizzaDialog` that trigger the `OnCancel` and `OnConfirm` events.
Expand Down Expand Up @@ -308,8 +315,8 @@ Run the app and verify that the dialog now disappears when the Cancel button is
When the `OnConfirm` event is fired, the customized pizza should be added to the user's order. Add an `Order` field to the `Index` component to track the user's order.

```csharp
List<PizzaSpecial> specials;
Pizza configuringPizza;
List<PizzaSpecial>? specials;
Pizza? configuringPizza;
bool showingConfigureDialog;
Order order = new Order();
```
Expand All @@ -326,9 +333,12 @@ In the `Index` component add an event handler for the `OnConfirm` event that add
```csharp
void ConfirmConfigurePizzaDialog()
{
order.Pizzas.Add(configuringPizza);
configuringPizza = null;

if (configuringPizza is not null)
{
order.Pizzas.Add(configuringPizza);
configuringPizza = null;
}

showingConfigureDialog = false;
}
```
Expand All @@ -344,11 +354,11 @@ Create a new `ConfiguredPizzaItem` component for displaying a configured pizza.
```html
<div class="cart-item">
<a @onclick="OnRemoved" class="delete-item">x</a>
<div class="title">@(Pizza.Size)" @Pizza.Special.Name</div>
<div class="title">@(Pizza.Size)" @Pizza.Special?.Name</div>
<ul>
@foreach (var topping in Pizza.Toppings)
{
<li>+ @topping.Topping.Name</li>
<li>+ @topping.Topping?.Name</li>
}
</ul>
<div class="item-price">
Expand All @@ -357,8 +367,8 @@ Create a new `ConfiguredPizzaItem` component for displaying a configured pizza.
</div>

@code {
[Parameter] public Pizza Pizza { get; set; }
[Parameter] public EventCallback OnRemoved { get; set; }
[Parameter, EditorRequired] public Pizza Pizza { get; set; } = new();
[Parameter, EditorRequired] public EventCallback OnRemoved { get; set; }
}
```

Expand Down
18 changes: 9 additions & 9 deletions docs/03-show-order-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Then add a `@code` block that makes an asynchronous request for the data we need

```csharp
@code {
IEnumerable<OrderWithStatus> ordersWithStatus;
IEnumerable<OrderWithStatus>? ordersWithStatus;

protected override async Task OnParametersSetAsync()
{
Expand All @@ -124,7 +124,7 @@ It's simple to express this using `@if/else` blocks in Razor code. Update the ma

```html
<div class="main">
@if (ordersWithStatus == null)
@if (ordersWithStatus is null)
{
<text>Loading...</text>
}
Expand Down Expand Up @@ -257,9 +257,9 @@ Now you can implement the polling. Update your `@code` block as follows:
@code {
[Parameter] public int OrderId { get; set; }

OrderWithStatus orderWithStatus;
OrderWithStatus? orderWithStatus;
bool invalidOrder;
CancellationTokenSource pollingCancellationToken;
CancellationTokenSource? pollingCancellationToken;

protected override void OnParametersSet()
{
Expand All @@ -278,7 +278,7 @@ Now you can implement the polling. Update your `@code` block as follows:
try
{
invalidOrder = false;
orderWithStatus = await HttpClient.GetFromJsonAsync<OrderWithStatus>($"orders/{OrderId}");
orderWithStatus = await HttpClient.GetFromJsonAsync<OrderWithStatus>($"orders/{OrderId}")?? throw new NullReferenceException();
StateHasChanged();

if (orderWithStatus.IsDelivered)
Expand Down Expand Up @@ -321,7 +321,7 @@ OK, so we're getting the order details, and we're even polling and updating that
<h2>Nope</h2>
<p>Sorry, this order could not be loaded.</p>
}
else if (orderWithStatus == null)
else if (orderWithStatus is null)
{
<text>Loading...</text>
}
Expand Down Expand Up @@ -363,15 +363,15 @@ Create a new file, `OrderReview.razor` inside the `Shared` directory, and have i
<p>
<strong>
@(pizza.Size)"
@pizza.Special.Name
@pizza.Special?.Name
(£@pizza.GetFormattedTotalPrice())
</strong>
</p>

<ul>
@foreach (var topping in pizza.Toppings)
{
<li>+ @topping.Topping.Name</li>
<li>+ @topping.Topping?.Name</li>
}
</ul>
}
Expand All @@ -384,7 +384,7 @@ Create a new file, `OrderReview.razor` inside the `Shared` directory, and have i
</p>

@code {
[Parameter] public Order Order { get; set; }
[Parameter, EditorRequired] public Order Order { get; set; } = new();
}
```

Expand Down
9 changes: 6 additions & 3 deletions docs/04-refactor-state-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class OrderState
{
public bool ShowingConfigureDialog { get; private set; }

public Pizza ConfiguringPizza { get; private set; }
public Pizza? ConfiguringPizza { get; private set; }

public Order Order { get; private set; } = new Order();
}
Expand Down Expand Up @@ -86,8 +86,11 @@ public void CancelConfigurePizzaDialog()

public void ConfirmConfigurePizzaDialog()
{
Order.Pizzas.Add(ConfiguringPizza);
ConfiguringPizza = null;
if (ConfiguringPizza is not null)
{
Order.Pizzas.Add(ConfiguringPizza);
ConfiguringPizza = null;
}

ShowingConfigureDialog = false;
}
Expand Down
Loading