ASP.NET Core Blazor 3:使用 Blazor Server (2)

Blazor Server 的登录与退出(一) 如果自学Blazor ,因为增加了许多知识点,有许多问题会是一头雾水,难以理清。Blazor Server 的登录与退出就是一个非常难以理清的问题,因为我有强迫症,既然用了Blazor,我难道又要退回去用Razor Page?新建立的Blazor Server程序,使用Identity的个人标识账户,它的登录与退出默认使用的是Razor Page,因为它能非常清晰地得到ClaimsPrincipal 的User,和不支持Razor组件,特别是所以想抛开Razor Page,它的登录与退出只能另想办法,好像一 阅读详情

1 准备工作

  继续使用上一章项目。
  本章展示如何组合Razor组件来创建更复杂的特性。展示如何创建组件之间的父子关系,如何利用属性配置组件,以及如何创建自定义事件,以在发生重要更改时发出信号。还展示了组件如何从父组件接收内容,以及如何使用模板组件一致地生成内容,模板组件可以用一个或多个泛型类型参数定义。在本章结束时,演示了 Blazor应用程序如何对连接和应用程序错误做出反应。

2 结合组件

  Blazor 组件可以组合起来创建更复杂的功能。Blazor 文件夹中添加 SelectFilter.razor:

<div class="form-group">
    <label for="select-@Title">@Title</label>
    <select name="select-@Title" class="form-control" @bind="SelectedValue">
        <option disabled selected>Select @Title</option>
        @foreach (string val in Values)
        {
            <option value="@val" selected="@(val == SelectedValue)">
                @val
            </option>
        }
    </select>
</div>

@code
{
    public IEnumerable<string> Values { get; set; } = Enumerable.Empty<string>();
    public string SelectedValue { get; set; }
    public string Title { get; set; } = "Placeholder";
}

  该组件呈现现一个 selcect 元素,该元素允许用户选择城市。在 Blazor 文件夹的 PeopleList.razor 中应用此组件替换现有的 select:

<SelectFilter />

  当组件添加到控制器视图或 Razor Pages 所呈现的内容中时,就会使用组件元素,当一个组件添加到另一个组件所呈现的内容中时,该组件的名称将用作一个元素。本例向 PeopleList 组件所呈现的内容添加了 SelectFilter 组件,使用 SelectFilter 元素来实现,大小写必须匹配。
  组合组件时,效果是一个组件将其部分布局的职责委托给另一个组件。本例各组成部分构成父/子关系:PcopleList 组件是父组件,SelectFilter 组件是子组件。
  请求http:/localhost:5000/controllers查看效果。

2.1 利用属性配置组件

  使用 SelectList 组件的目标是创建一个可在整个应用程序中使用的通用特性,配置每次使用它时显示的值。Razor 组件是用属性配置的,这些属性添加到应用它们的 HTML 元素中。分配给 HTML 元素属性的值被分配给组件的 C# 属性。Parameter 属性应用于组件允许配置的 C# 属性, 在 Blazor 文件夹的 SelectFilter.razor 文件中声明可配置属性如下:

@code
{
    [Parameter]
    public IEnumerable<string> Values { get; set; } = Enumerable.Empty<string>();
    public string SelectedValue { get; set; }
    [Parameter]
    public string Title { get; set; } = "Placeholder";
}

  组件可以选择它们允许配置的属性。在本例中,Parameter属性已应用于 SelectFilter 组件定义的两个属性。在 Blazor 文件夹的 PeopleList.razor ,修改了组件用于应用 SelectFilter 组件以添加配置属性的元素,如下:

<SelectFilter values="@Cities" title="city" />

  对于每个应该配置的属性,将一个同名属性添加到父元素的 HTML 元素中。属性值可以是固定的值,比如分配给 title 属性的 City 字符串,也可以是 Razor 表达式,如 @Cities (它将 City 属性中的对象序列分配给 values 属性)。

1.设置和接收批量配置设置

  如果存在许多配置设置,可以指定一个属性来接收没有被其他属性匹配的任何属性值,然后可将其作为一个集合应用。如下在 Blazor 文件夹的 SelectFiter.razor 文件中接收未匹配属性:

<select name="select-@Title" class="form-control" @bind="SelectedValue"
    @attributes="Attrs">
......
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object> Attrs { get; set; }

  将 Parameter 属性的 CaptureUnmatchedValues 参数设置为 true,将标识一个属性作为未以其他方式匹配的属性的集合。属性的类型必须是 Dictionary<string,object>,这表示属性名称和值,可以使用@attribute 表达式应用于元素。它允许一次性应用一组属性,上面更改的效果意味着 SelectFilter 组件接收 Values 和 Title 属性值,其他任何属性都分配给 Attrs 属性并传递给 select 元素。
在 Blazor 文件夹的 PeopleList.razor 文件中添加元素属性:

<SelectFilter values="@Cities" title="city" autofocus="true" name="city" 
    required ="true"/>

  请求 http://localhost:5000/controllers。传递给 select 元素的属性不影响显示,右击选择元素,并从弹出菜单中选择检查,就将看到属性添加到 PeopleList 组件的 SelectFilter 元素中,SelectFilter 元素已添加到 SelectFilter 组件呈现的元素中。
2.在控制器视图或 Razor Pages 中配置组件
  当使用组件元素应用组件时,属性还用于配置组件。在 Blazor 文件夹的 PeopleList.razor,向 PeopleList 组件添加了属性,该属性指定应该显示来自数据库的多少项,以及将传递给 SelectFilter 组件的字符串值,如下:

<SelectFilter values="@Cities" title="@SelectTitle" />
@code
{
    [Inject]
    public DataContext Context { get; set; }
    public IEnumerable<Person> People => Context.People
        .Include(p => p.Department).Include(p => p.Location)
        .Take(ItemCount);
    public IEnumerable<string> Cities => Context.Locations.Select(l => l.City);
    public string SelectedCity { get; set; }
    public string GetClass(string city) =>
        SelectedCity == city ? "bg-info text-white" : "";
    [Parameter]
    public int ItemCount { get; set; } = 4;
    [Parameter]
    public string SelectTitle { get; set; }
}

  C#属性的值是通过将名称以param-开头、后跟属性名称的属性添加到组件元素来提供的,在 Views/Home 文件夹的 Index.cshtm 文件中添加配置属性如下:

<component type="typeof(MyAdvanced.Blazor.PeopleList)" render-mode="Server"
           param-itemcount="5" param-selecttitle="@("Location")" />

  param-itemcount 属性为 ItemCount 属性提供一个值,param-selecttitle 属性为 SelectTitle 属性提供一个值。
  在使用组件元素时,可以解析为数值或 bool值的属性值。其他值假定为 Razor 表达式而不是文字值,因为它们没有以@作为前缀,那么,为将 SelectTitle 属性的值指定为文字字符串,就需要一个 Razor 表达式。

2.2 创建自定义事件和绑定

  SelectFilter 组件从父组件接收数据值,但它无法指示用户何时进行选择。为此,需要创建一个自定义事件,父组件可为其注册一个处理程序方法,就像它为常规 HTML 元素中的事件所做的那样。向 SelectFilter 组件添加了一个自定义事件:

<select name="select-@Title" class="form-control" @onchange="HandleSelect" 
    value="@SelectedValue">
[Parameter]
public EventCallback<string> CustomEvent { get; set; }
public async Task HandleSelect(ChangeEventArgs e)
{
    SelectedValue = e.Value as string;
    await CustomEvent.InvokeAsync(SelectedValue);
}

  自定义事件是通过添加一个类型为 EventCalback的属性来定义的。泛型类型参数是父类的事件处理程序接收的类型,在本例中为sting。前面更改了 select 元素,所以当 select 元素触发其 onchange 事件时,@onchange 属性会注册 HandleSelect 方法。通过调用 EventCallback.InvokeAsync 方法,HandleSelect 方法会更新 SelectedValue 属性。
  InvokeAsync方法的参数使用从 ChangeEventArgs 对象接收到的值(从select元素接收到的值)触发事件。更改了 PeopleList 组件,以便它接收由 SelectList 组件发出的定制事件:

<SelectFilter values="@Cities" title="@SelectTitle" CustomEvent="@HandleCustom"/>
public void HandleCustom(string newValue)
{
    SelectedCity = newValue;
}

  要设置事件处理程序,需要向使用 EventCallback属性名称应用子组件的元素添加一个属性。属性的值是一个 Razor 表达式,它选择接收类型为 T 的参数的方法。
  请求 http://localhost:5000/controllers,并从城市列表中选择一个值。自定义事件完成父组件和子组件之间的关系。父元素通过其属性配置子元素,以指定呈现给用户的标题和数据值列表。子组件使用自定义事件来告诉父组件,当用户选择一个值时,允许父对象在其HTML 表中突出显示相应的行。创建自定义绑定
  父组件可以在子组件上创建绑定,前提是它定义了一对属性,其中一个属性被分配一个数据值,另一个属性是自定义事件。属性的名称很重要:事件属性的名称必须与数据属性的名称加 Changed 相同。
  在 Blazor 文件夹的 SelectFiter.razor 文件中准备自定义绑定,更新了 SelectFiter 组件,以便它显示绑定所需的属性,如下:

[Parameter]
public string SelectedValue { get; set; }
......
[Parameter]
public EventCallback<string> SelectedValueChanged { get; set; }
public async Task HandleSelect(ChangeEventArgs e)
{
    SelectedValue = e.Value as string;
    await SelectedValueChanged.InvokeAsync(SelectedValue);
}

  注意,Parameter 属性必须同时应用于 SelectedValue 和 SelectedValueChanged 属性。如果省略其中任何一个属性,数据绑定将无法按预期工作。
  父组件通过@bind-属性绑定到子组件,其中对应于子组件定义的属性。在本例中,子组件的属性名是 SelectedValue,父组件可以使用@bind-SelectedValue 创建绑定。在 Blazor 文件夹 PeopleList.razor 文件中使用自定义绑定:

<SelectFilter values="@Cities" title="@SelectTitle" @bind-SelectedValue = "SelectedCity"/>
<button class="btn btn-primary" @onclick="@(()=> SelectedCity = "San Jose")">
    Change
</button>

  请求 http://localhost:5000/controllers,并从城市列表中选择 New York,自定义绑定将使select 元素中选择的值通过表中的高亮显示反映出来。单击 Change 按钮以在另一个方向测试绑定,城市的更改将高亮显示。

3 在组件中显示子内容

  显示子内容的组件充当父元素提供的元素的包装器。要查看子内容是如何管理的,请给 Blazor文件夹添加名为 ThemeWrapper.razor 的 Razor 组件,如下:

<div class="p-2 bg-@Theme border text-white">
    <h5 class="text-center">@Title</h5>
    @ChildContent
</div>

@code
{
    [Parameter]
    public string Theme { get; set; }
    [Parameter]
    public string Title { get; set; }
    [Parameter]
    public RenderFragment ChildContent { get; set; }
}

  为接收子内容,组件定义了一个名为 ChildContent 的属性。@ChildContent 表达式在组件的 html 输出中包含子内容。div 元素使用引导主题颜色进行样式化,并显示标题。
  子内容是通过在应用组件时在开始和结束标记之间添加HTML元素来定义的。在 Blazor 文件夹的 PeopleList.razor 文件中定义子内容:

<ThemeWrapper Theme="info" Title="Location Selector">
    <SelectFilter values="@Cities" title="@SelectTitle" 
        @bind-SelectedValue="SelectedCity" />
    <button class="btn btn-primary" @onclick="@(()=> SelectedCity = "San Jose")">
        Change
    </button>
</ThemeWrapper>

  配置子内容不需要附加属性,子内容将被自动处理并分配给ChidContcent属性。请求 http://localhost:5000/controllers,将看到选择主题的配置属性和用于生成响应的标题文本。

3.1 创建模板组件

  模板组件为子内容的表示带来了更多的结构,允许显示内容的多个部分。模板组件可以很好地整合应用程序中使用的特性,以防止代码和内容的重复。
要了解其工作原理,请给 Blazor 文件夹添加一个名为 TableTemplate.razor 的 Razor 组件:

<table class="table table-sm table-bordered table-striped">
    @if (Header != null)
    {
        <thead>@Header</thead>
    }
    <tbody>@Body</tbody>
</table>

@code
{
    [Parameter]
    public RenderFragment Header { get; set; }
    [Parameter]
    public RenderFragment Body { get; set; }
}

  组件为它支持的每个子内容区域定义一个 RenderFragment 属性。TableTemplate 组件定义了两个Renderfragment 属性,命名为 Header 和 Body,它们代表了表格的内容部分,子内容的每个区域都是使用 Razor 表达式 @Header 和 @Body 呈现的,可以通过检查属性值是否为空来检查是否为特定部分提供了内容,该组件为 Header 部分执行此操作。
  当使用模板组件时,每个区域的内容都包含在一个 HTML 元素中,该元素的标记与对应的Renderfragment 属性的名称相匹配。 在 Blazor 文件夹的 PeopleList.razor 文件中应用模板组件:

<TableTemplate>
    <Header>
        <tr><th>ID</th><th>Name</th><th>Dept</th><th>Location</th></tr>
    </Header>
    <Body>
        @foreach (Person p in People)
        {
        <tr class="@GetClass(p.Location.City)">
            <td>@p.PersonId</td>
            <td>@p.Surname, @p.Firstname</td>
            <td>@p.Department.Name</td>
            <td>@p.Location.City, @p.Location.State</td>
        </tr>
        }
    </Body>
</TableTemplate>

  子内容构成与模版组件的属性、标题和主体对应的部分,这使得 TableTemplate 组件负责表结构,而 PeopleList 组件负责提供详情。请求 http://localhost:5000/controllers,将看到模版组件爱你生成的输出。

3.2 在模板组件中使用泛型类型参数

  模板组件可通过使用泛型类型参数来感知数据,泛型类型参数允许父组件提供一系列数据对象和用于表示这些对象的模板。模板组件负责为每个数据对象生成内容,因此可以提供更有用的功能。
  下面将向模板组件添加对选择显示多少表行和选择表行的支持。第一步是向组件添加一个泛型类型参数,并使用它呈现表主体的内容。在 Blazor 文件夹的 TableTemplate.razor 文件中添加泛型类型参数:

@typeparam RowType

<table class="table table-sm table-bordered table-striped">
    @if (Header != null)
    {
        <thead>@Header</thead>
    }
    <tbody>
        @foreach(RowType item in RowData)
        {
            <tr>@RowTemplate(item)</tr>
        }
    </tbody>
</table>

@code
{
    [Parameter]
    public RenderFragment Header { get; set; }
    [Parameter]
    public RenderFragment<RowType> RowTemplate { get; set; }
    [Parameter]
    public IEnumerable<RowType> RowData { get; set; }
}

  泛型类型参数是使用 @typeparam 属性指定的,本例为参数指定了名称 RowType,因为引用组件将为其生成表行的数据类型。
  组件处理的数据是通过添加一个属性来接收的,该属性的类型是泛型类型的对象序列。将属性命名为 RowData,其类型为 IEnumerable<RowType>。组件为每个对象显示的内容是使用RenderFragment<T> 属性接收的。将这个属性命名为 RowTemplate,它的类型是RenderFragment<RowType>,反映了为泛型类型参数选择的名称。
  当组件通过 RenderFragment<T>属性接收到一个内容区段时,可通过调用该区段作为方法并使用该对象作为参数,来为单个对象呈现它@RowTemplate(item)。
这段代码枚举 RowData 序列中的 RowType 对象,并为每个对象呈现通过 RowTemplate 属性接收到的内容部分。1.使用通用模板组件
  前面简化了 PeopleList 组件,使其仅使用模板组件生成 Person 对象表,并且删除了以前的特性。在 Blazor 文件夹的 PeopleList.razor 文件中使用通用模板组件:

<TableTemplate RowType="Person" RowData="People">
    <Header>
    <tr><th>ID</th><th>Name</th><th>Dept</th><th>Location</th></tr>
    </Header>
    <RowTemplate Context="p">
        <td>@p.PersonId</td>
        <td>@p.Surname, @p.Firstname</td>
        <td>@p.Department.Name</td>
        <td>@p.Location.City, @p.Location.State</td>
    </RowTemplate>
</TableTemplate>

@code
{
    [Inject]
    public DataContext Context { get; set; }

    public IEnumerable<Person> People => Context.People
            .Include(p => p.Department)
            .Include(p => p.Location);
}

  RowIype 属性用于指定泛型类型参数的值。RowData 属性指定模板组件要处理的数据。RowTempaie 元素表示为每个数据对象生成的元素。当为 Renderragment属性定义一个内容区段时,conrext属性用于为当前处理的对象分配一个名称。
  在本例中,使用 Context 属性们名称 p 分配给当前对象,然后在用于填充内容部分元素的 Razor 表达式中引用该对象。
总体效果是将模板组件配置为显示 Person 对象。该组件为每个 Person 生成一个表行,其中包含 td 元素,其内容是使用当前 Person 对象的属性设置的。
删除了用 Parameter 属性装饰的属性,所以需要从应用 PepleList 组件的元素中删除相应的属性,在 Views/Home 文件夹的 Index.cshtml 文件中删除属性:

<component type="typeof(MyAdvanced.Blazor.PeopleList)" render-mode="Server"/>

  要查看通用模板组件,请求 http://localhost:5000/controllers。PeopleList 组件提供的数据和内容部分已被 TableTemplate 组件用于生成列表。2.向通用模板组件添加特性
  在 Blazor 文件夹的 TableTemplate.razor 文件中添加特性:

@typeparam RowType

<div class="container-fluid">
    <div class="row">
        <div class="col">
            <SelectFilter Title="@("Sort")" Values="@SortDirectionChoices"
            @bind-SelectedValue="SortDirectionSelection" />
        </div>
        <div class="col">
            <SelectFilter Title="@("Highlight")" Values="@HighlightChoices()"
            @bind-SelectedValue="HighlightSelection" />
        </div>
    </div>
</div>

<table class="table table-sm table-bordered table-striped">
    @if (Header != null)
    {
        <thead>@Header</thead>
    }
    <tbody>
        @foreach (RowType item in SortedData())
        {
            <tr class="@IsHighlighted(item)">@RowTemplate(item)</tr>
        }
    </tbody>
</table>

@code {
    [Parameter]
    public RenderFragment Header { get; set; }

    [Parameter]
    public RenderFragment<RowType> RowTemplate { get; set; }

    [Parameter]
    public IEnumerable<RowType> RowData { get; set; }

    [Parameter]
    public Func<RowType, string> Highlight { get; set; }

    public IEnumerable<string> HighlightChoices() =>
        RowData.Select(item => Highlight(item)).Distinct();

    public string HighlightSelection { get; set; }

    public string IsHighlighted(RowType item) =>
        Highlight(item) == HighlightSelection ? "bg-dark text-white" : "";

    [Parameter]
    public Func<RowType, string> SortDirection { get; set; }

    public string[] SortDirectionChoices =
        new string[] { "Ascending", "Descending" };

    public string SortDirectionSelection { get; set; } = "Ascending";

    public IEnumerable<RowType> SortedData() =>
        SortDirectionSelection == "Ascending"
            ? RowData.OrderBy(SortDirection)
            : RowData.OrderByDescending(SortDirection);
}

  这些更改为用户提供了两个选择元素,这两个元素是使用本章前面创建的 SelectFilter 组件显示的。这些新元素允许用户按升序和降序对数据排序,并选择用于突出显示表行的值。父组件提供了额外参数,为模板组件函数提供功能,来选择用于排序和突出显示的属性,在 Blazor 文件夹的 PeopleList.razor 文件中配置模板组件特性:

<TableTemplate RowType="Person" RowData="People"
    Highlight="@(p=>p.Location.City)" SortDirection="@(p=>p.Surname)">
    ......
</TableTemplate>

  Highlight 属性为模板组件提供一个函数,该函数选择用于突出显示表行的属性,SortDirection 属性提供一个函数,该函数选择用于排序的属性。要查看效果,请求 http://localhost:5000/controllers。响应将包含新的 select 元素,这些元素可用于重改排序顺定或选择要过滤的城市。3.重用通用模板组件
  添加到模板组件的特性都依赖于泛型类型参数,允许组件修改它呈现的内容,而不绑定到特定的类。结果是一个组件,可用于在需要表的地方显示、排序和突出显示任何数据类型。给 Blazor文件夹添加一个名为 DepartmmentList.razor 的 Razor 组件:

<TableTemplate RowType="Department" RowData="Departments"
               Highlight="@(d => d.Name)" SortDirection="@(d => d.Name)">
    <Header>
    <tr><th>ID</th><th>Name</th><th>People</th><th>Locations</th></tr>
    </Header>
    <RowTemplate Context="d">
        <td>@d.Departmentid</td>
        <td>@d.Name</td>
        <td>@(String.Join(", ", d.People.Select(p => p.Surname)))</td>
        <td>
            @(String.Join(", ",
                d.People.Select(p => p.Location.City).Distinct()))
        </td>
    </RowTemplate>
</TableTemplate>

@code
{
    [Inject]
    public DataContext Context { get; set; }

    public IEnumerable<Department> Departments =>
        Context.Departments.Include(d => d.People).ThenInclude(p => p.Location);
}

  TableTemplate 组件用于向用户展示数据库中的 Department 对象列表,以及相关的 Person 和Location 对象的详细信息,这些信息通过 Entity Framework Core Include 和 Thenlnclude 方法进行查询。更改在 Pages 文件夹的 Blazor.cshtml 文件中组件:

@page "/pages/blazor"
<h4 class="bg-primary text-white text-center p-2">Departmments</h4>
<component type="typeof(MyAdvanced.Blazor.DepartmmentList)" render-mode="Server" />

  请求 http://localhost:5000/pages/blazor。使用模板化组件显示响应。

3.3 级联参数

  Blazor 通过支持级联参数,组件提供的数据值可直接用于它的任何后代,而不由中间组件传递。级联参数是使用 CascadingValue 组件定义的,该组件用于包装部分内容。在 Blazor 文件夹的 DepartmentList.razor 文件中创建级联参数:

<CascadingValue Name="BgTheme" Value="Theme" IsFixed="false">
    ......
</CascadingValue>

<SelectFilter Title="@("Theme")" Values="Themes" @bind-SelectedValue="Theme" />

@code 
{
    [Inject]
    public DataContext Context { get; set; }
    public IEnumerable<Department> Departments => Context.Departments
            .Include(d => d.People).ThenInclude(p => p.Location);
    public string Theme { get; set; } = "info";
    public string[] Themes = new string[] { "primary", "info", "success" };
}

  CascadingValue 元素为它所包含的组件及其后代提供一个可用的值。Name 属性指定参数的名称,Value 属性指定值,isFixed 属性用于指定值是否会更改。代码清单中使用了 CascadingValue 元素来创建名为BgTheme 的级联参数,它的值由 SelectFilter 组件的一个实例设置该组件向用户提供了一组引导 CSS 主题名。
  在 Blazor 文件夹的 SelectFilter.razor 文件中使用 CascadingParameter 属性的组件直接接收级联参数:

<div class="form-group p-2 bg-@Theme @TextColor()">
......
......
[CascadingParameter(Name = "BgTheme")]
public string Theme { get; set; }
public string TextColor() => Theme == null ? "" : "text-white";

  CascadingParameter 属性的 Name 参数用于指定级联参数的名称。代码清单 DepartmentList.razor 中定义的 BgTheme 参数由代码清单 SelectFilter.razor 中的Theme属性接收,并用于设置组件的背景。请求 http://localhost:5000/pages/blazor。
  本例中使用了三个 SelectFilter 组件实例,但其中只有两个在 Cascadingvalue 元素所包含的层次结构中。另一个实例在 Cascadingvalue 元素之外定义,不接收级联值。

4 处理错误

4.1 处理连接错误

  Blazor 依赖于它在浏览器和 ASP.NETCore 服务器之间的持久 HTTP连接。当连接中断时,应用程序无法正常工作,并显示一个模态错误消息,阻止用户与组件交互。Blazor 允许通过定义具有特定 id 的元素来定制连接错误,如代码清单所示。在 Pages 文件夹的 Blazor.cshtml 文件中定义连接错误元素:

<link href="~/lib/connectionerrors.css" rel="stylesheet" />
    
<div id="components-reconnect-modal" 
    class="h4 bg-dark text-white text-center my-2 p-2 components-reconnect-hide">
    Blazor Connection Lost
    <div class="reconnect">
        Trying to reconnect...
    </div>
    <div class="failed">
        Reconnection Failed.
        <button class="btn btn-light" onclick="window.Blazor.reconnect()">
            Reconnect
        </button>
    </div>
    <div class="rejected">
        Reconnection Rejected.
        <button class="btn btn-light" onclick="location.reload()">
            Reload
        </button>
    </div>
</div>

  自定义错误元素的id 属性必须是 componentes-reconnect-modal。当出现连接错误时,Blazor将查找此元素并将其添加到表中描述的四个类中的一个。

名称描述
components-reconnect-show当连接已经丢失且 Blazor 正在尝试重连接时,将元素添加到这个类中。错误消息应该显示
给用户,并且应该防止与 Blazor 内容的交互
components-reconnect-hide如果重新建立连接,则将元素添加到该类中。错误消息应该隐藏,并且应该允许交互
components-reconnect-failed如果 Blazor 重连接失败,则将该元素添加到该类中。用户可以看到一个按钮,该按钮调用
window.Blazor.reconnect()来再次尝试重新连接
components-reconnect-rejected如果 Blazor 能够到达服务器,但用户的连接状态已经丢失,则将元素添加到这个类中,这
通常发生在服务器重新启动时。用户可以看到一个按钮,该按钮调用 location.reload()来重
新加载应用程序并重试

  元素最初没有添加到这些类中的任何一个,因此将其显式添加到 components-reconnect-hide 类中,以便在出现问题之前隐藏它。
  希望针对重连接期间可能出现的每个条件向用户显示特定的消息。为此,添加了为每个条件显示消息的元素。为了管理它们的可见性,将一个名为connectionError.css 的 CSS 样式表添加到wwwroot 文件夹中,并用它定义如代码清单所示的样式。
  wwwroot 文件夹中 connectionError.css 文件的内容:

#components-reconnect-modal {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1000;
    overflow: hidden;
    opacity: 0.9;
}

.components-reconnect-hide {
    display: none;
}

.components-reconnect-show {
    display: block;
}

    .components-reconnect-show > .reconnect {
        display: block;
    }

    .components-reconnect-show > .failed,
    .components-reconnect-show > .rejected {
        display: none;
    }

.components-reconnect-failed > .failed {
    display: block;
}

.components-reconnect-failed > .reconnect,
.components-reconnect-failed > .rejected {
    display: none;
}

.components-reconnect-rejected > .rejected {
    display: block;
}

.components-reconnect-rejected > .reconnect,
.components-reconnect-rejected > .failed {
    display: none;
}

  这些样式将 componentes-reconnect-modal 元素显示为一个模态项,其可见性由 componentesrecomnecthide 和 componentes-reconnect-show 类决定。
  要查看效果,请求http://localhost:5000/pages/blazor。等到显示组件,就停止服务器。当 Blazor 尝试重新连接时,将看到一个初始错误消息。几秒钟后,将看到指示重连接失败的消息。

4.2 处理未捕获的应用程序错误

  Blazor 不能很好地响应未捕获的应用程序错误,这些错误几乎总是被视为终端。要查看默认的错误行为,请将代码清单中所示的元素添加到 DepartmentList 组件。
  在 Blazor 文件夹的 DepartmentList.razor 文件中添加元素:

<button class="btn btn-danger" @onclick="@(()=> throw new Exception())">Error</button>

  重启 ASP.NET Core,请求 http://localhost:5000/pages/blazor,然后单击 Error 按钮。在浏览器中并无明显变化,但当单击按钮时在服务器上抛出的异常被证明是致命的;用户仍然可以使用 select 元素选择值,因为这些是由浏览器显示的,但响应选择的事件处理程序不再有效,应用程序本质上是停止了。
  当出现未处理的应用程序错误时,Blazor会查找 id 为 Blazor-error-ui 的元素,并设置其 CSS显示属性以阻止。代码清单将具有此 id 的元素添加到 Blazorcshtml 文件,该文件样式化为显示有用的消息。

<div id="blazor-error-ui"
     class="text-center bg-danger h6 text-white p-2 fixed-top w-100"
     style="display:none">
    An error has occurred. This application will not respond until reloaded.
    <button class="btn btn-sm btn-primary" onclick="location.reload()">
        Reload
    </button>
</div>

  单击 Error 按钮,当显示元素时,用户将看到一个警告和一个重新加载浏览器的按钮。

Blazor Service 实现身份验证 之前用 Blazor 做了几个小应用,但是一直没有去做身份验证系统,之前也没有ASP.NET的基础,C#也是最近学的,而且重要的是,网上居然几乎没有相关的资料,于是咱就结合网上的一些信息和微软的官方文档(微软的文档是我见过最好的文档了)做了一个身份鉴权的小Demo。在 Provider 下写自定义的基础认证服务,这里使用的session的形式做鉴权认证。Blazor 是微软的新型的web开发方案,用来做全栈开发真是太爽了。然后在项目的目录下创建Auth目录存放鉴权的基础设施。一个简单的登录页面示例; 阅读详情

相关推荐

Blazor —— 教你从零搭建 Blazor for Server-Side 项目

这篇文章不会介绍什么是 Blazor,若想理解基本概念,请自行百度或查看微软官方文档。这篇文章是偏向技术的,也就是说它不是概念,而是教你从零开始搭建一个 Blazor 项目,前提是你必须先掌握 ASP.NET CORE 的基本知识。

不忘初心 9081

Blazor Server开发技术总结

C# Blazor Server

shine_leo的专栏 3043

ASP.NET Core防伪令牌实战:从CSRF防御到Blazor SSR配置

跨站请求伪造(CSRF)是一种常见的Web安全威胁,攻击者利用用户已登录的会话,诱导其执行非预期的操作。其防御核心在于验证请求的合法性,确保操作来自可信来源。防伪令牌技术通过生成一次性随机令牌,结合会话凭证进行双重验证,有效阻断恶意请求。在ASP.NET Core中,该机制通过中间件和属性验证实现,为表单提交和状态修改操作提供基础防护。随着.NET版本更新,自动CSRF保护功能引入,基于浏览器安全头进行智能拦截,但防伪令牌仍是敏感操作的核心保障。在Blazor SSR场景中,最新版本要求显式启用中间件验证,

weixin_33798152的博客 372

ASP.NET Core Blazor 2:使用 Blazor Server (1)

  Blazor 是 ASP.NET Core 新添加的一个功能,它向 Web 应用程序添加客户端交互性。Blazor 有两个变种,本章将重点介绍 Blazor Server,另一种是 Blazor WebAssembly。解释它解决的问题和它是如何工作的。展示如何配置 ASP.NET Core应用程序来使用 Blazor Server,并描述使用 Razor 组件时可用的基本特性,这是 Bla...

噢~ 1474

asp .net core blazor 是什么?

我想显从网页的显示历史变化来了解什么是asp .net core blazor 1、第一阶段:静态网页全部下载并显示阶段 在服务器端,程序员写好一个完整的.html网页。浏览一篇网页时,浏览器首先将整个网页下载下来,并显示出来。这个阶段有个很明显的缺点,当网页的部分内容变化比较频繁时,每次在浏览器和服务器之间都要传输一整个.html文件。而这个文件的大部分内容是重复的,只有少部分内容是不同的。...

freewzx2005的专栏 1409

创建 ASP.NET Core 应用与 Blazor Server 入门指南

本文通过构建一个示例应用程序,深入介绍ASP.NET Core中的控制器和视图创建,以及如何使用Blazor Server为Web应用增加客户端交互性。文中详细说明了如何配置和运行ASP.NET Core项目,展示了控制器和Razor页面的使用,以及Blazor Server组件的创建和事件处理。

weixin_42509888的博客 959

使用VS 2019,.NET Core 3和Web API创建ASP.NET Core Blazor CRUD应用程序

目录 介绍 Blazor Blazor客户端应用程序 Blazor服务器应用程序 背景 先决条件 使用代码 第1步-创建数据库和表 第2步-创建ASP.NET Core Blazor服务器应用程序 运行以测试应用程序 调试组件 步骤3-使用实体框架 安装软件包 添加数据库连接字符串 创建模型类 创建dbConext类 在Startup中添加DbContext 创...

寒冰屋的专栏 5257

1.28寸圆屏LCD驱动开发:GC9A01与RT-Thread嵌入式实现

圆形TFT-LCD是一种面向可穿戴、IoT终端的紧凑型人机交互显示技术,其核心在于SPI/QSPI接口时序控制与GRAM内存映射原理。通过驱动芯片(如GC9A01)完成电源管理、伽马校正和MADCTL方向配置,可实现低功耗、高刷新率的图形渲染。该技术显著提升嵌入式设备的UI表现力与空间利用率,在智能手环、传感器节点、微型HMI等资源受限场景中具备突出工程价值。本文围绕1.28寸圆屏LCD模块,详解硬件接口规范、RT-Thread下QSPI驱动架构及Bresenham算法优化实践。

weixin_42599908的博客 155

[.NET学习笔记] - 在ASP.NET Core MVC中使用Blazor组件

场景 .NET5发布了,突然对Blazor有了点兴趣,想尝尝鲜。 Blazor有两种模式,server-side与client-side(WASM)。这里打算在已有的MVC项目中使用Blazor组件,所以用的server-side。 use blazor component in ASP.NET Core 3.1 MVC。 解决方案 step1 startup.cs配置。 // ConfigureServices services.AddServerSideBlazor(); services.AddAnt

kyw的专栏 2169

ADP在线自适应动态规划之持续激励条件

在线自适应动态规划之持续激励条件 在在线自适应动态规划算法中,需要通过满足持续激励条件(Persistent Excitation Condition)保证critic网络权值的收敛性,一般的做法都是在算法初期在输入端引入探测噪声(Probing Noises)来保证数据的丰富性,但是由于在输入端引入噪声会给系统带来一些不好的影响,甚至可能破坏系统的稳定性。因此,出现了一些其他的方法来避免引入探测噪声,受阅读所限,我目前了解两种: Concurrent Learning(CL) Experience Re

qq_43435956的博客 6161

第十篇|网络子系统 ②——无损以太网、PFC/ECN、DCQCN 与拥塞可视化

网络部分了解了解

qq_37535542的博客 1873

.NET 10 中的 ASP.NET Core:Blazor、API 和 OpenAPI 的重大更新

微软发布.NET 10版本中ASP.NET Core的全面更新,涵盖Blazor、Minimal API等多个方面。Blazor获得最显著改进,包括安全示例更新、客户端指纹识别等功能。Minimal API新增验证支持和服务器发送事件功能。OpenAPI支持升级至3.1版本,提高文档生成质量。此外还优化了身份验证、异常处理及性能表现,并新增测试支持和JSON解析增强功能。

csdn_aspnet的专栏,请点击博客主页右上角三个点中的私信联系 5931

pycharm一直选择不了conda正确路径弹框报错:latinit property envs_dirs has not been initialized...如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 2908

ASP.NET Core 和 Blazor 更新

.NET Core 3.0 preview 8现在已经可用,它包含了对 ASP.NET Core 和 Blazor 的一系列新更新。更新内容如下: 项目模板更新 清理 Visual Studio 中的顶级模板 Visual Studio 中“Create a new project”对话框中的顶级 ASP.NET Core 项目模板不再出现在“Create a new ASP.NET Cor...

寒冰屋的专栏 2237

游戏大厂技术护城河——为什么你抄不了原神?

│ │ │ │ ↓ 通过 │ │ │ │。│ │ │ │ ↓ 成功 │ │ │ │。│ │ │ │ ↓ 完成 │ │ │ │。│ │ │ │ ↓ 达标 │ │ │ │。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 70

【时空图神经网络 & 交通】相关模型3:STFGNN | 空间-时间依赖性 | 基于数据驱动的方法来生成“时间图” | 时空融合图模块,门控卷积模块 | 动态时间规整 | 顶会文章解析

STFGNN(时空融合图神经网络)在交通流量预测中的优势主要体现在以下几个方面:首先,它提出了一种数据驱动的方法生成“时间图”,弥补了传统空间图可能无法反映的某些相关性。其次,STFGNN通过并行处理不同时间段的空间图和时间图,有效地学习隐藏的时空依赖关系。此外,它将融合图模块与门控卷积模块整合到一个统一层中,通过层层堆叠处理长序列,进一步增强了模型的表达能力。实验结果表明,STFGNN在多个交通数据集上表现出色,优于其他基准方法,展示了其在实际应用中的强大潜力。

追光者♂:记录、分享、总结、提升,现象级专栏《Python从入门到人工智能》作者,无惧黑暗,坚信曙光 382

.NET开发技术推荐,如何使用ASP.NET Core和Blazor进行开发

当使用.NET开发MES(制造执行系统)时,前端和后端的开发方式可以根据项目需求、团队技能和项目规模进行选择。以下是一些常见的开发方式建议::ASP.NET Core 是一个跨平台的、高性能的、开源的 Web 框架,非常适合构建现代、可扩展的 Web 应用程序。它支持多种开发模式,包括 MVC(模型-视图-控制器)和 Web API,可以轻松地与数据库和其他服务进行交互。ASP.NET Core 还具有强大的依赖注入和中间件支持,使得应用程序的可扩展性和可维护性更高。

slty_123的博客 918

ARM Linux工控板+C# .NET Core:倍福ADS协议轻量化工业控制(附跨平台部署代码)

某自动化设备厂的倍福PLC控制系统曾依赖传统x86工控机:单台设备需配备1台Intel i5工控机(成本约8000元),功耗30W+,且Windows系统稳定性受工业环境干扰(如电磁辐射导致蓝屏)。更棘手的是,设备需部署在产线边缘(空间狭小),x86工控机的体积(4U机架)和散热需求(风扇噪音)难以适配;而多设备部署时,高硬件成本和高功耗导致年运维成本超20万元。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 954

您需要在Blazor应用程序上了解的所有知识,并使用VS 2019,.NET Core 3和Web API创建ASP.NET Core Blazor CRUD应用程序

Download shanuBlazorCRUD.zip - 435.9 KB 下载shanuBlazorCRUD.zip-435.9 KB 介绍 (Introduction) In this article, we will see how to create a simple CRUD application for ASP.NET Core Blazor using Visual Stud...

cunhan4654的博客 1926

目标检测YOLO实战应用案例100讲-跨模态、多级别融合的RGB-D显著目标检测方法研究(续)

在第二章介绍了本研究的跨模态特征融合方法,第二章对于多级别特征的融合, 使用的是与基线模型baseline相同的方法:相邻级别的特征中,高级特征进行上采 样到与低级特征相同的尺度,再将高级特征通过降维得到与低级特征相同的通道数 量,最后对二者进行特征叠加,如此自顶向下的进行多级别的特征融合。本章主要 介绍本研究在特征层面的另一发现,并基于此发现引出的本文的第二个创新点:多 级别特征的融合方法。另外,在网络最深层,本文设计了一个新的模块来获取大的 感受野,对于大尺度目标能够增加更多语义信息,提升检测效果。 骨

qq_36130719的博客 466

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

C# 与前端开发结合:利用 Blazor 和 ASP.NET Core 构建前后端分离的动态页面

前后端分离是一种将前端和后端功能解耦的架构模式。前端负责展示数据和与用户的交互,而后端负责处理业务逻辑和数据持久化。两者通过 API 进行通信,通常采用或GraphQL等标准协议。通过使用Blazor和,C# 开发者可以轻松地实现前后端分离的开发模式。Blazor 使得 C# 成为前端开发的强大工具,而 ASP.NET Core 提供了高效的 API 后端支持。前端可以通过 HTTP 请求与后端交互,使用 JavaScript 或 TypeScript 来处理动态页面,形成一个灵活的开发体系。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 3201

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

ASP.NET Core与Blazor性能对比:基于Benchmarks项目的实战分析

ASP.NET Core与Blazor作为.NET生态中重要的Web开发技术,它们的性能表现直接影响应用的用户体验和资源消耗。本文基于Benchmarks项目提供的权威测试数据,深入对比分析两者在不同场景下的性能差异,为开发者选择合适的技术栈提供实用参考。 ## 一、技术架构与性能特点解析 ASP.NET Core作为成熟的后端框架,采用传统的请求-响应模型,通过中间件管道处理HTTP请求,具

gitblog_00162的博客 708

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Blazor Server安全实践:ASP.NET Core Security Samples中的前端身份验证

ASP.NET Core Security Samples项目提供了丰富的Blazor Server安全实践示例,帮助开发者轻松实现前端身份验证功能。本文将详细介绍如何在Blazor Server应用中配置和使用身份验证与授权机制,保护应用安全。 ## 🌟 Blazor Server身份验证基础架构 Blazor Server应用的身份验证核心配置位于[Startup.cs](https:/

gitblog_00993的博客 144

ASP.NET Core Blazor 简介

作者:Daniel Roth和Luke Latham 欢迎使用 Blazor! Blazor 是一个使用.NET生成交互式客户端 Web UI 的框架: 使用C#代替JavaScript来创建信息丰富的交互式 UI。 共享使用 .NET 编写的服务器端和客户端应用逻辑。 将 UI 呈现为 HTML 和 CSS,以支持众多浏览器,其中包括移动浏览器。 与新式托管平台(如Docker)集成。 使用 .NET 进行客户端 Web 开发可提供以下优势: 使用 C# 代替 JavaSc...

cxzhq2002的杂记 1008

八、实现登录页面 :Blazor Server + MudBlazor + Asp.Net Core Web Api + MongoDB + Asp.Net Core Identity身份验证

在Pages文件夹中新增登录页面Login.razor:新增登录页面对应的cs文件,Login.razor.cs:stringstringobjectstringstring_Imports.razor中加入组件,但Login.razor.cs里的组件仍然显示错误:找不到该变量;!!!注意:以上代码需要加到app.UseRouting();后面。

Kevinxxxxx的博客 746

ASP。NET Core Blazor CRUD使用实体框架和Web API

下载source code - 1.7 MB 介绍 *请查看我的Youtube视频链接来学习ASP。NET Core Blazor CRUD使用实体框架和Web API。 在本文中,我们将了解如何为ASP创建一个简单的CRUD应用程序。NET Core Blazor使用实体框架和Web API。Blazor是微软引入的一个新框架。我喜欢使用Blazor,因为它使我们的SPA全栈应用程序开发更加简单,而且现在我们只能使用一种语言,比如c#。在Blazor之前,我们一直使用ASP。结合Angular和Reac

DiyAbc 788
上一篇: ASP.NET Core Blazor 2:使用 Blazor Server (1)
下一篇: ASP.NET Core Blazor 4:高级Blazor特性
似水明俊德
博客等级 码龄8年 247粉丝 276原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值