Skip to content

Commit

Permalink
Update to Preview5 (dotnet-presentations#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
danroth27 committed May 7, 2019
1 parent 1854cdf commit 243db52
Show file tree
Hide file tree
Showing 183 changed files with 985 additions and 941 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Welcome to the Blazor app building workshop!

Blazor is an experimental single-page app framework for building client-side web apps using .NET and WebAssembly. In this workshop we will build a complete Blazor app and learn about the various Blazor framework features along the way.
Blazor is an single-page app framework for building client-side web apps using .NET and WebAssembly. In this workshop we will build a complete Blazor app and learn about the various Blazor framework features along the way.

![Blazing Pizza](https://user-images.githubusercontent.com/1874516/51886593-5a5bc980-2388-11e9-9329-7e015901e45d.png)

Expand Down
44 changes: 3 additions & 41 deletions docs/00-get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,10 @@ In this session, you'll setup your machine for Blazor development and build your

## Setup

Install the following:
To get started with Blazor, follow the instructions on https://blazor.net/get-started.

1. [.NET Core 2.1 SDK](https://go.microsoft.com/fwlink/?linkid=873092) (2.1.500 or later).
1. [Visual Studio 2017](https://go.microsoft.com/fwlink/?linkid=873093) (15.9 or later) with the *ASP.NET and web development* workload selected.
1. The latest [Blazor Language Services extension](https://go.microsoft.com/fwlink/?linkid=870389) from the Visual Studio Marketplace.
1. The Blazor templates on the command-line:
## Build your first app

```console
dotnet new -i Microsoft.AspNetCore.Blazor.Templates
```

## Build and run your first Blazor app

To create a Blazor project in Visual Studio:

1. Select **File** > **New** > **Project**. Select **Web** > **ASP.NET Core Web Application**. Name the project "BlazorApp1" in the **Name** field. Select **OK**.

![New ASP.NET Core project](https://raw.githubusercontent.com/aspnet/Blazor.Docs/gh-pages/docs/tutorials/build-your-first-blazor-app/_static/new-aspnet-core-project.png)

1. The **New ASP.NET Core Web Application** dialog appears. Make sure **.NET Core** is selected at the top. Also select **ASP.NET Core 2.1**. Choose the **Blazor** template and select **OK**.

![New Blazor app dialog](https://raw.githubusercontent.com/aspnet/Blazor.Docs/gh-pages/docs/tutorials/build-your-first-blazor-app/_static/new-blazor-app-dialog.png)

1. Once the project is created, press **Ctrl-F5** to run the app *without the debugger*. Running with the debugger (**F5**) isn't supported at this time.

> [!NOTE]
> If not using Visual Studio, create the Blazor app at a command prompt on Windows, macOS, or Linux:
>
> ```console
> dotnet new blazor -o BlazorApp1
> cd BlazorApp1
> dotnet run
> ```
>
> Navigate to the app using the localhost address and port provided in the console window output after `dotnet run` is executed. Use **Ctrl-C** in the console window to shutdown the app.

The Blazor app runs in the browser:

![Blazor app Home page](https://user-images.githubusercontent.com/1874516/39509497-5515c3ea-4d9b-11e8-887f-019ea4fdb3ee.png)

Congrats! You just built and ran your first Blazor app!

If you have more time, try out the rest of the [introductory Blazor tutorial](https://docs.microsoft.com/en-us/aspnet/core/tutorials/build-your-first-razor-components-app)
Once you have your first Blazor app running, try [building your first Blazor app](https://docs.microsoft.com/aspnet/core/tutorials/build-your-first-blazor-app).

Next up - [Components and layout](01-components-and-layout.md)
21 changes: 11 additions & 10 deletions docs/01-components-and-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ We've setup the initial solution for you for the pizza store app in this repo. G

The solution already contains four projects:

![image](https://user-images.githubusercontent.com/1874516/51783836-f2418500-20f4-11e9-95d4-4e9b34e6b2ca.png)
![image](https://user-images.githubusercontent.com/1874516/57006654-3e3e1300-6b97-11e9-8053-b6ec9c31614d.png)

- **BlazingPizza.Client**: This is the Blazor project. It contains the UI components for the app.
- **BlazingPizza.Server**: This is the ASP.NET Core project hosting the Blazor app and also the backend services for the app.
Expand All @@ -19,7 +19,7 @@ Run the app by hitting `Ctrl-F5`. Currently the app only contains a simple home

![image](https://user-images.githubusercontent.com/1874516/51783774-afcb7880-20f3-11e9-9c22-2f330380ff1e.png)

Open *Pages/Index.cshtml* to see the code for the home page.
Open *Pages/Index.razor* to see the code for the home page.

```
@page "/"
Expand All @@ -33,7 +33,7 @@ The home page is implemented as a single component. The `@page` directive specif

First we'll update the home page to display the list of available pizza specials. The list of specials will be part of the state of the `Index` component.

Add a `@functions` block to *Index.cshtml* with a list field to keep track of the available specials:
Add a `@functions` block to *Index.razor* with a list field to keep track of the available specials:

```csharp
@functions {
Expand All @@ -60,7 +60,7 @@ Override the `OnInitAsync` method in the `@functions` block to retrieve the list

protected async override Task OnInitAsync()
{
specials = await HttpClient.GetJsonAsync<List<PizzaSpecial>>("/specials");
specials = await HttpClient.GetJsonAsync<List<PizzaSpecial>>("specials");
}
}
```
Expand Down Expand Up @@ -89,24 +89,24 @@ Once the component is initialized it will render its markup. Replace the markup
</div>
```

![Pizza specials list](https://user-images.githubusercontent.com/1874516/51797486-8b0ef800-21fc-11e9-9d2e-a703d6574537.png)
![image](https://user-images.githubusercontent.com/1874516/57006743-1602e400-6b98-11e9-96cb-ff4829cf459f.png)

## Create the layout

Next we'll setup the layout for app.

Layouts in Blazor are also components. They inherit from `BlazorLayoutComponent`, which defines a `Body` property that can be used to specify where the body of the layout should be rendered. The layout component for our pizza store app is defined in *Shared/MainLayout.cshtml*.
Layouts in Blazor are also components. They inherit from `LayoutComponentBase`, which defines a `Body` property that can be used to specify where the body of the layout should be rendered. The layout component for our pizza store app is defined in *Shared/MainLayout.razor*.

```html
@inherits BlazorLayoutComponent
@inherits LayoutComponentBase

<div class="content">
@Body
</div>

```

To apply a layout use the `@layout` directive. Typically this is done in a `_ViewImports.cshtml` file, which then gets inherited hierarchically. See *Pages/_ViewImports.cshtml*.
To apply a layout use the `@layout` directive. Typically this is done in a `_Imports.razor` file, which then gets inherited hierarchically. See *Pages/_Imports.razor*.

```
@layout MainLayout
Expand All @@ -115,7 +115,7 @@ To apply a layout use the `@layout` directive. Typically this is done in a `_Vie
Update the `MainLayout` component to define a top bar with a branding logo and a nav link for the home page:

```html
@inherits BlazorLayoutComponent
@inherits LayoutComponentBase

<div class="top-bar">
<img class="logo" src="img/logo.svg" />
Expand All @@ -137,6 +137,7 @@ The `NavLink` component is the same as an anchor tag, except that it adds an `ac

With our new layout our pizza store app now looks like this:

![Pizza store layout](https://user-images.githubusercontent.com/1874516/51797487-9feb8b80-21fc-11e9-8c91-52dfc86d057f.png)
![image](https://user-images.githubusercontent.com/1874516/57006730-e81d9f80-6b97-11e9-813d-9c35b62efa53.png)


Next up - [Customize a pizza](02-customize-a-pizza.md)
22 changes: 11 additions & 11 deletions docs/02-customize-a-pizza.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ In this session we'll update the pizza store app to enable users to customize th

When the user clicks a pizza special a pizza customization dialog should pop up to allow the user to customize their pizza and add it to their order. To handle DOM UI events in a Blazor app, you specify which event you want to handle using the corresponding HTML attribute and then specify the C# delegate you want called. The delegate may optionally take an event specific argument, but it's not required.

In *Pages/Index.cshtml* add the following `onclick` handler to the list item for each pizza special:
In *Pages/Index.razor* add the following `onclick` handler to the list item for each pizza special:

```html
@foreach (var special in specials)
Expand All @@ -27,7 +27,7 @@ Run the app and check that the pizza name is written to the browser console when

The `@` symbol is used in Razor files to indicate the start of C# code. Surround the C# code with parens if needed to clarify where the C# code begins and ends.

Update the `@functions` block in *Index.cshtml* to add some additional fields for tracking the pizza being customized and whether the pizza customization dialog is visible.
Update the `@functions` 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;
Expand Down Expand Up @@ -62,7 +62,7 @@ Update the `onclick` handler to call the `ShowConfigurePizzaDialog` method inste

Now we need to implement the pizza customization dialog so we can display it when the user selects a pizza. The pizza customization dialog will be a new component that lets you specify the size of your pizza and what toppings you want, shows the price, and lets you add the pizza to your order.

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

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 `@functions` block to the `ConfigurePizzaDialog` with the following `Pizza` parameter:

Expand Down Expand Up @@ -95,7 +95,7 @@ Add the following basic markup for the `ConfigurePizzaDialog`:
</div>
```

Update *Pages/Index.cshtml* 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.
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.

```html
@if (showingConfigureDialog)
Expand Down Expand Up @@ -174,7 +174,7 @@ The user should also be able to select additional toppings. Add a list property

protected async override Task OnInitAsync()
{
toppings = await HttpClient.GetJsonAsync<List<Topping>>("/toppings");
toppings = await HttpClient.GetJsonAsync<List<Topping>>("toppings");
}
}
```
Expand Down Expand Up @@ -250,13 +250,13 @@ You should now be able to add and remove toppings.

## Component events

The Cancel and Order buttons don't do anything yet. We need some way to communicate to the `Index` component when the user adds the pizza to their order or cancels. We can do that by defining component events. Component events are action parameters that parent components can subscribe to.
The Cancel and Order buttons don't do anything yet. We need some way to communicate to the `Index` component when the user adds the pizza to their order or cancels. We can do that by defining component events. Component events are callback parameters that parent components can subscribe to.

Add two parameters to the `ConfigurePizzaDialog` component: `OnCancel` and `OnConfirm`. Both parameters should be of type `Action`.
Add two parameters to the `ConfigurePizzaDialog` component: `OnCancel` and `OnConfirm`. Both parameters should be of type `EventCallback`.

```csharp
[Parameter] Action OnCancel { get; set; }
[Parameter] Action OnConfirm { get; set; }
[Parameter] EventCallback OnCancel { get; set; }
[Parameter] EventCallback OnConfirm { get; set; }
```

Add `onclick` event handlers to the `ConfigurePizzaDialog` that trigger the `OnCancel` and `OnConfirm` events.
Expand Down Expand Up @@ -344,7 +344,7 @@ Create a new `ConfiguredPizzaItem` component for displaying a configured pizza.

@functions {
[Parameter] Pizza Pizza { get; set; }
[Parameter] Action OnRemoved { get; set; }
[Parameter] EventCallback OnRemoved { get; set; }
}
```

Expand Down Expand Up @@ -389,7 +389,7 @@ void RemoveConfiguredPizza(Pizza pizza)

async Task PlaceOrder()
{
await HttpClient.PostJsonAsync("/orders", order);
await HttpClient.PostJsonAsync("orders", order);
order = new Order();
}
```
Expand Down
22 changes: 11 additions & 11 deletions docs/03-show-order-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Your customers can order pizzas, but so far have no way to see the status of the

## Adding a navigation link

Open `Shared/MainLayout.cshtml`. As an experiment, let's try adding a new link element *without* using `NavLink`. Add a plain HTML `<a>` tag pointing to `myorders`:
Open `Shared/MainLayout.razor`. As an experiment, let's try adding a new link element *without* using `NavLink`. Add a plain HTML `<a>` tag pointing to `myorders`:

```html
<div class="top-bar">
Expand All @@ -23,7 +23,7 @@ If you run the app now, you'll see the link, styled as expected:

![image](https://user-images.githubusercontent.com/1101362/51804403-60528d00-2258-11e9-8d2b-ab00d33c74cb.png)

This shows it's not strictly necessary to use `<NavLink>`. We'll see the reason to use it momentatily.
This shows it's not strictly necessary to use `<NavLink>`. We'll see the reason to use it momentarily.

## Adding a "My Orders" page

Expand All @@ -33,7 +33,7 @@ If you click "My Orders", nothing will seem to happen. Open your browser's dev t
Error: System.InvalidOperationException: 'Router' cannot find any component with a route for '/myorders'.
```

As you can guess, we will fix this by adding a component to match this route. Create a file in the `Pages` folder called `MyOrders.cshtml`, with the following content:
As you can guess, we will fix this by adding a component to match this route. Create a file in the `Pages` folder called `MyOrders.razor`, with the following content:

```html
@page "/myorders"
Expand Down Expand Up @@ -80,7 +80,7 @@ Then add a `@functions` block that makes an asynchronous request for the data we

protected override async Task OnParametersSetAsync()
{
ordersWithStatus = await HttpClient.GetJsonAsync<List<OrderWithStatus>>("/orders");
ordersWithStatus = await HttpClient.GetJsonAsync<List<OrderWithStatus>>("orders");
}
}
```
Expand Down Expand Up @@ -118,7 +118,7 @@ It's simple to express this using `@if/else` blocks in Razor code. Update your c

protected override async Task OnParametersSetAsync()
{
ordersWithStatus = await HttpClient.GetJsonAsync<List<OrderWithStatus>>("/orders");
ordersWithStatus = await HttpClient.GetJsonAsync<List<OrderWithStatus>>("orders");
}
}
```
Expand Down Expand Up @@ -184,7 +184,7 @@ It looks like a lot of code, but there's nothing special here. It simply uses a

If you click on the "Track" link buttons next to an order, the browser will attempt a client-side navigation to `myorders/<id>` (e.g., `http://example.com/myorders/37`). Currently this will just log an error because no component matches this route.

Once again we'll add a component to handle this. In the `Pages` directory, create a file called `OrderDetails.cshtml`, containing:
Once again we'll add a component to handle this. In the `Pages` directory, create a file called `OrderDetails.razor`, containing:

```html
@page "/myorders/{orderId:int}"
Expand All @@ -205,7 +205,7 @@ This code illustrates how components can receive parameters from the router by d
If you're wondering how routing actually works, let's go through it step-by-step.

1. When the app first starts up, code in `Startup.cs` tells the framework to render `App` as the root component.
2. The `App` component (in `App.cshtml`) contains a `<Router>`. `Router` is a built-in component that interacts with the browser's client-side navigation APIs. It registers a navigation event handler that gets notification whenever the user clicks on a link.
2. The `App` component (in `App.razor`) contains a `<Router>`. `Router` is a built-in component that interacts with the browser's client-side navigation APIs. It registers a navigation event handler that gets notification whenever the user clicks on a link.
3. Whenever the user clicks a link, code in `Router` checks whether the destination URL is within the same SPA (i.e., whether it's under the `<base href>` value). If it's not, traditional full-page navigation occurs as usual. But if the URL is within the SPA, `Router` will handle it.
4. `Router` handles it by looking for a component with a compatible `@page` URL pattern. Each `{parameter}` token needs to have a value, and the value has to be compatible with any constraints such as `:int`.
* If there's no matching component, it's an error. This will change in Blazor 0.8.0, which includes support for fallback routes (e.g., for custom "not found" pages).
Expand All @@ -220,7 +220,7 @@ What's more, we'll also account for the possibility of `OrderId` being invalid.
* No such order exists
* Or later, when we've implement authentication, if the order is for a different user and you're not allowed to see it

Before we can implement the polling, we'll need to add the following directives at the top of `OrderDetails.cshtml`, typically directly under the `@page` directive:
Before we can implement the polling, we'll need to add the following directives at the top of `OrderDetails.razor`, typically directly under the `@page` directive:

```html
@using System.Threading
Expand Down Expand Up @@ -382,7 +382,7 @@ This is wasteful of client-side memory and CPU time, network bandwidth, and serv

To fix this, we need to make `OrderDetails` stop the polling once it gets removed from the display. This is simply a matter of using the `IDisposable` interface.

In `OrderDetails.cshtml`, add the following directive at the top of the file, underneath the other directives:
In `OrderDetails.razor`, add the following directive at the top of the file, underneath the other directives:

```html
@implements IDisposable
Expand Down Expand Up @@ -426,13 +426,13 @@ To use this, update the `PlaceOrder` code so it calls `UriHelper.NavigateTo`:
```cs
async Task PlaceOrder()
{
await HttpClient.PostJsonAsync("/orders", order);
await HttpClient.PostJsonAsync("orders", order);
order = new Order();

UriHelper.NavigateTo("myorders");
}
```

Now as soon as the server accepts the order, the browser will switch to the "order details" display and being polling for updates.
Now as soon as the server accepts the order, the browser will switch to the "order details" display and begin polling for updates.

Next up - [Refactor state management](04-refactor-state-management.md)
2 changes: 1 addition & 1 deletion docs/04-refactor-state-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ To hook up the other side, we should subscribe to the change notifications on `I
protected async override Task OnInitAsync()
{
OrderState.StateChanged += OnOrderStateChanged;
specials = await HttpClient.GetJsonAsync<List<PizzaSpecial>>("/specials");
specials = await HttpClient.GetJsonAsync<List<PizzaSpecial>>("specials");
}
void IDisposable.Dispose()
Expand Down
Loading

0 comments on commit 243db52

Please sign in to comment.