MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Visual Basic Blazor服务器端渲染

2023-10-223.3k 阅读

Visual Basic Blazor服务器端渲染基础

Blazor简介

Blazor是一个使用.NET编写交互式客户端Web UI的框架。它允许开发者使用C#或Visual Basic等.NET语言来构建单页应用(SPA),而无需JavaScript。Blazor应用可以在客户端(WebAssembly)或服务器端运行,为开发者提供了灵活的选择。

Blazor有两种主要的托管模型:客户端WebAssembly和服务器端渲染(Server - Side Rendering,SSR)。在客户端WebAssembly模式下,应用代码被编译成WebAssembly并在浏览器中运行,与JavaScript交互。而服务器端渲染模式下,应用在服务器上运行,处理用户交互并将更新后的UI发送回客户端。

Visual Basic在Blazor中的角色

Visual Basic作为.NET生态系统的一部分,完全可以用于Blazor开发。使用Visual Basic编写Blazor应用,开发者可以利用其简洁的语法和熟悉的编程结构。与C#相比,Visual Basic具有更易读的语法,对于一些习惯Visual Basic的开发者来说,这使得Blazor开发更加顺手。

Visual Basic Blazor服务器端渲染环境搭建

安装.NET SDK

要开始使用Visual Basic进行Blazor服务器端渲染开发,首先需要安装最新版本的.NET SDK。可以从微软官方网站下载适合你操作系统的.NET SDK安装包,并按照安装向导进行安装。安装完成后,通过在命令行中输入 dotnet --version 来验证安装是否成功。如果显示出正确的版本号,则说明安装成功。

创建Blazor服务器端项目

  1. 使用命令行:打开命令行工具,导航到你想要创建项目的目录。然后运行以下命令:
dotnet new blazorserver -lang VB -o MyBlazorServerApp

这里,blazorserver 是项目模板,表示创建一个Blazor服务器端项目;-lang VB 表示使用Visual Basic作为编程语言;-o MyBlazorServerApp 用于指定项目的名称和目录,你可以将 MyBlazorServerApp 替换为你想要的项目名称。

  1. 使用Visual Studio:如果你使用Visual Studio,打开Visual Studio后,选择 “创建新项目”。在项目模板搜索框中输入 “Blazor Server App”,选择该模板,然后在 “语言” 下拉菜单中选择 “Visual Basic”。点击 “下一步”,设置项目名称和位置,最后点击 “创建”。

项目结构解析

创建好项目后,让我们来了解一下Blazor服务器端项目的基本结构。

  1. Pages文件夹:存放应用的页面组件。每个页面组件通常是一个以 .razor 为后缀的文件,同时可能有一个对应的Visual Basic代码隐藏文件(.razor.vb)。例如,Index.razor 是应用的首页组件。
  2. Shared文件夹:包含可以在多个页面中共享的组件,如布局组件(MainLayout.razor)。布局组件定义了应用的整体结构,包括导航栏、侧边栏等公共部分。
  3. App.razor:这是应用的入口点,负责配置应用的路由和布局。
  4. Program.vb:在Visual Basic项目中,Program.vb 是应用的启动程序。它配置了应用的主机构建器,包括添加服务器端Blazor服务等。以下是 Program.vb 的基本代码结构:
Imports Microsoft.AspNetCore.Components.Web
Imports Microsoft.AspNetCore.Components.WebAssembly.Hosting

Module Program
    Sub Main()
        Dim builder = WebAssemblyHostBuilder.CreateDefault(args)
        builder.RootComponents.Add(Of App)("#app")
        builder.RootComponents.Add(Of HeadOutlet)("head::after")

        builder.Services.AddScoped(Function(sp) New HttpClient With {.BaseAddress = New Uri(builder.HostEnvironment.BaseAddress)})

        builder.Services.AddServerSideBlazor()

        Dim host = builder.Build()
        host.RunAsync().Wait()
    End Sub
End Module

在这段代码中,builder.Services.AddServerSideBlazor() 方法用于添加服务器端Blazor服务,使得应用能够在服务器端进行渲染。

编写Visual Basic Blazor服务器端组件

基本组件创建

  1. 创建组件文件:在 Pages 文件夹中,创建一个新的Blazor组件。例如,创建一个名为 Counter.razor 的文件,用于显示一个计数器。同时,创建对应的代码隐藏文件 Counter.razor.vb
  2. 编写组件UI(Counter.razor)
@page "/counter"
@using Microsoft.AspNetCore.Components

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

在这段代码中,@page "/counter" 定义了该组件的路由为 /counter@currentCount 是一个绑定到组件代码中的变量,显示当前计数器的值。@onclick="IncrementCount" 绑定了按钮的点击事件到 IncrementCount 方法。

  1. 编写组件逻辑(Counter.razor.vb)
Partial Public Class Counter
    Private currentCount As Integer = 0

    Private Sub IncrementCount()
        currentCount = currentCount + 1
    End Sub
End Class

这里,Counter 类继承自 ComponentBase(虽然没有显式声明)。currentCount 变量用于存储当前计数器的值,IncrementCount 方法在按钮点击时增加计数器的值。

组件之间的通信

  1. 父子组件通信:假设我们有一个父组件 Parent.razor 和一个子组件 Child.razor。在父组件中,我们可以通过属性将数据传递给子组件。
    • 定义子组件(Child.razor)
@using Microsoft.AspNetCore.Components

<p>Received value: @Value</p>

@code {
    [Parameter]
    Public Property Value As String
}

这里,[Parameter] 特性标记了 Value 属性,使其可以从父组件接收数据。 - 使用子组件(Parent.razor)

@page "/parent"
@using Microsoft.AspNetCore.Components

<h1>Parent Component</h1>

<Child Value="Hello from Parent"/>

在父组件中,通过 Value="Hello from Parent" 将字符串传递给子组件的 Value 属性。

  1. 事件回调:子组件也可以通过事件回调通知父组件发生的事件。
    • 修改子组件(Child.razor)
@using Microsoft.AspNetCore.Components

<button @onclick="NotifyParent">Notify Parent</button>

@code {
    [Parameter]
    Public Event OnChildEvent As Action

    Private Sub NotifyParent()
        If OnChildEvent IsNot Nothing Then
            OnChildEvent.Invoke()
        End If
    End Sub
}

这里,定义了一个 OnChildEvent 事件,当按钮点击时,调用该事件。 - 修改父组件(Parent.razor)

@page "/parent"
@using Microsoft.AspNetCore.Components

<h1>Parent Component</h1>

<Child OnChildEvent="HandleChildEvent"/>

@code {
    Private Sub HandleChildEvent()
        Console.WriteLine("Child component notified parent.")
    End Sub
}

在父组件中,将 HandleChildEvent 方法绑定到子组件的 OnChildEvent 事件。

数据绑定与状态管理

数据绑定基础

  1. 单向数据绑定:在Blazor中,单向数据绑定是将组件中的数据显示在UI上。例如,在前面的 Counter 组件中,@currentCount 就是单向数据绑定,将 currentCount 变量的值显示在页面上。
  2. 双向数据绑定:双向数据绑定允许在UI和组件数据之间进行双向同步。假设我们有一个输入框和一个变量,当输入框的值改变时,变量的值也随之改变,反之亦然。
    • 创建一个包含双向绑定的组件(DataBinding.razor)
@page "/databind"
@using Microsoft.AspNetCore.Components

<input type="text" @bind="userInput"/>
<p>You entered: @userInput</p>

@code {
    Private userInput As String
}

这里,@bind="userInput" 实现了双向数据绑定,将输入框的值与 userInput 变量进行同步。

状态管理

  1. 简单状态管理:对于小型应用,可以在组件内部管理状态。例如,Counter 组件通过在组件类中定义 currentCount 变量来管理计数器的状态。
  2. 使用共享状态服务:对于大型应用,可能需要在多个组件之间共享状态。可以创建一个状态服务类,并在需要的组件中注入该服务。
    • 创建状态服务(CounterStateService.vb)
Public Class CounterStateService
    Private _count As Integer = 0

    Public Property Count As Integer
        Get
            Return _count
        End Get
        Set(value As Integer)
            _count = value
        End Set
    End Property

    Public Sub Increment()
        _count = _count + 1
    End Sub
End Class
- **注册状态服务(Program.vb)**:
Imports Microsoft.AspNetCore.Components.Web
Imports Microsoft.AspNetCore.Components.WebAssembly.Hosting

Module Program
    Sub Main()
        Dim builder = WebAssemblyHostBuilder.CreateDefault(args)
        builder.RootComponents.Add(Of App)("#app")
        builder.RootComponents.Add(Of HeadOutlet)("head::after")

        builder.Services.AddScoped(Function(sp) New HttpClient With {.BaseAddress = New Uri(builder.HostEnvironment.BaseAddress)})

        builder.Services.AddServerSideBlazor()

        builder.Services.AddScoped(Of CounterStateService)

        Dim host = builder.Build()
        host.RunAsync().Wait()
    End Sub
End Module
- **使用状态服务的组件(SharedCounter.razor)**:
@page "/sharedcounter"
@using Microsoft.AspNetCore.Components
@inject CounterStateService CounterService

<h1>Shared Counter</h1>

<p>Current count: @CounterService.Count</p>

<button class="btn btn-primary" @onclick="IncrementCounter">Click me</button>

@code {
    Private Sub IncrementCounter()
        CounterService.Increment()
    End Sub
}

在这个组件中,通过 @inject CounterStateService CounterService 注入了 CounterStateService,并使用该服务的 Count 属性和 Increment 方法来管理和更新共享状态。

Blazor服务器端渲染原理与性能优化

服务器端渲染原理

  1. 初始渲染:当用户首次请求Blazor服务器端应用的页面时,服务器接收到请求。服务器会创建一个新的Blazor应用实例,然后调用页面组件的渲染方法。组件的状态被初始化,渲染出的HTML被发送回客户端。这个初始渲染过程与传统的服务器端渲染(如ASP.NET MVC)类似,不同的是Blazor使用了组件化的编程模型。
  2. 后续交互:当客户端与页面进行交互(如点击按钮、输入文本等)时,这些事件会通过SignalR连接发送回服务器。服务器接收到事件后,再次调用相关组件的事件处理方法,更新组件的状态,然后重新渲染组件。只有发生变化的部分(通常是一个或几个组件)会被重新渲染,而不是整个页面。服务器将更新后的HTML片段发送回客户端,客户端使用这些片段来更新页面的相应部分。

性能优化

  1. 减少不必要的渲染:在组件设计时,尽量避免不必要的状态变化和渲染。可以使用 @key 指令来帮助Blazor更有效地跟踪组件的变化。例如,在一个列表组件中,如果列表项的数据发生变化,但项的数量不变,可以使用 @key 来确保只有真正发生变化的项被重新渲染。
@foreach (Dim item In items)
{
    <div @key=item.Id>
        @item.Name
    </div>
}

这里,@key=item.Id 使得Blazor可以根据 Id 来判断哪些项发生了变化,从而只重新渲染变化的项。

  1. 优化SignalR连接:由于Blazor服务器端渲染依赖SignalR进行客户端与服务器之间的通信,优化SignalR连接可以提升性能。可以通过合理配置SignalR的传输协议(如使用WebSocket协议,因为它具有较低的延迟和开销),以及调整SignalR的连接超时时间等参数来优化连接。在 Startup.vb 文件中,可以进行如下配置:
Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.AspNetCore.Http
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Hosting

Public Class Startup
    Public Sub ConfigureServices(services As IServiceCollection)
        services.AddServerSideBlazor()
        services.AddSignalR().AddJsonProtocol(Function(options)
                                                  options.PayloadSerializerOptions.PropertyNamingPolicy = Nothing
                                              End Function)
    End Sub

    Public Sub Configure(app As IApplicationBuilder, env As IWebHostEnvironment)
        If env.IsDevelopment() Then
            app.UseDeveloperExceptionPage()
        End If

        app.UseStaticFiles()
        app.UseRouting()

        app.UseEndpoints(Sub(endpoints)
                             endpoints.MapBlazorHub()
                             endpoints.MapFallbackToPage("/_Host")
                         End Sub)
    End Sub
End Class

在上述代码中,AddJsonProtocol 方法可以对SignalR的JSON协议进行配置,优化数据传输。

  1. 缓存与预渲染:对于一些不经常变化的数据,可以使用缓存来减少服务器的计算开销。例如,可以在服务器端缓存数据库查询结果。另外,预渲染可以在服务器启动时提前渲染一些页面,这样当用户请求这些页面时,可以更快地响应。可以通过在 Program.vb 中配置预渲染选项来实现:
Imports Microsoft.AspNetCore.Components.Web
Imports Microsoft.AspNetCore.Components.WebAssembly.Hosting

Module Program
    Sub Main()
        Dim builder = WebAssemblyHostBuilder.CreateDefault(args)
        builder.RootComponents.Add(Of App)("#app")
        builder.RootComponents.Add(Of HeadOutlet)("head::after")

        builder.Services.AddScoped(Function(sp) New HttpClient With {.BaseAddress = New Uri(builder.HostEnvironment.BaseAddress)})

        builder.Services.AddServerSideBlazor().AddPrerenderMode(Function(context) context.Type = GetType(MyComponent) AndAlso context.Parameters.Count = 0)

        Dim host = builder.Build()
        host.RunAsync().Wait()
    End Sub
End Module

在上述代码中,AddPrerenderMode 方法配置了对 MyComponent 组件在特定条件下进行预渲染。

与后端服务集成

调用API

  1. 创建HttpClient实例:在Blazor服务器端应用中,可以通过依赖注入获取 HttpClient 实例来调用后端API。在 Program.vb 中,已经默认配置了 HttpClient
Imports Microsoft.AspNetCore.Components.Web
Imports Microsoft.AspNetCore.Components.WebAssembly.Hosting

Module Program
    Sub Main()
        Dim builder = WebAssemblyHostBuilder.CreateDefault(args)
        builder.RootComponents.Add(Of App)("#app")
        builder.RootComponents.Add(Of HeadOutlet)("head::after")

        builder.Services.AddScoped(Function(sp) New HttpClient With {.BaseAddress = New Uri(builder.HostEnvironment.BaseAddress)})

        builder.Services.AddServerSideBlazor()

        Dim host = builder.Build()
        host.RunAsync().Wait()
    End Sub
End Module
  1. 调用API的组件示例:假设我们有一个后端API用于获取用户列表,创建一个组件 UserList.razor 来调用该API。
@page "/userlist"
@using Microsoft.AspNetCore.Components
@inject HttpClient Http

<h1>User List</h1>

@If users IsNot Nothing Then
    <ul>
        @For Each user In users
            <li>@user.Name</li>
        Next
    </ul>
End If

@code {
    Private users As List(Of User)

    Protected Overrides Async Function OnInitializedAsync() As Task
        users = Await Http.GetFromJsonAsync(Of List(Of User))("api/users")
    End Function

    Public Class User
        Public Property Name As String
    End Class
}

在这个组件中,通过 @inject HttpClient Http 注入 HttpClient,在 OnInitializedAsync 方法中使用 Http.GetFromJsonAsync 方法来调用 api/users API,并将返回的JSON数据反序列化为 List(Of User)

与数据库交互

  1. 使用Entity Framework Core:Entity Framework Core是一个用于.NET的对象关系映射(ORM)框架,可以方便地与各种数据库进行交互。首先,安装 Microsoft.EntityFrameworkCore 和相应数据库提供程序的NuGet包,例如对于SQL Server,安装 Microsoft.EntityFrameworkCore.SqlServer
  2. 创建数据上下文:创建一个继承自 DbContext 的数据上下文类,例如 AppDbContext.vb
Imports Microsoft.EntityFrameworkCore

Public Class AppDbContext
    Inherits DbContext

    Public Sub New(options As DbContextOptions(Of AppDbContext))
        MyBase.New(options)
    End Sub

    Public Property Users As DbSet(Of User)
End Class

Public Class User
    Public Property Id As Integer
    Public Property Name As String
End Class
  1. 配置数据库连接:在 Startup.vb 中配置数据库连接:
Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.AspNetCore.Http
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Hosting

Public Class Startup
    Public Sub ConfigureServices(services As IServiceCollection)
        services.AddDbContext(Of AppDbContext)(Function(options) options.UseSqlServer("your_connection_string"))
        services.AddServerSideBlazor()
    End Sub

    Public Sub Configure(app As IApplicationBuilder, env As IWebHostEnvironment)
        If env.IsDevelopment() Then
            app.UseDeveloperExceptionPage()
        End If

        app.UseStaticFiles()
        app.UseRouting()

        app.UseEndpoints(Sub(endpoints)
                             endpoints.MapBlazorHub()
                             endpoints.MapFallbackToPage("/_Host")
                         End Sub)
    End Sub
End Class
  1. 在组件中使用数据库:例如,在 UserList.razor 组件中,可以通过依赖注入获取 AppDbContext 并查询用户列表:
@page "/userlist"
@using Microsoft.AspNetCore.Components
@inject AppDbContext DbContext

<h1>User List</h1>

@If users IsNot Nothing Then
    <ul>
        @For Each user In users
            <li>@user.Name</li>
        Next
    </ul>
End If

@code {
    Private users As List(Of User)

    Protected Overrides Async Function OnInitializedAsync() As Task
        users = Await DbContext.Users.ToListAsync()
    End Function
}

在这个组件中,通过 @inject AppDbContext DbContext 注入 AppDbContext,在 OnInitializedAsync 方法中使用 DbContext.Users.ToListAsync 方法从数据库中获取用户列表。

部署Visual Basic Blazor服务器端应用

部署到IIS

  1. 发布项目:在Visual Studio中,右键点击项目,选择 “发布”。在发布向导中,选择 “文件夹” 作为发布目标,并选择一个输出文件夹。点击 “发布” 按钮,项目将被发布到指定文件夹。
  2. 配置IIS:打开Internet信息服务(IIS)管理器。在左侧导航栏中,右键点击 “网站”,选择 “添加网站”。设置网站名称、物理路径(指向刚才发布的文件夹)和绑定信息(如端口号、主机名等)。确保在IIS中安装了.NET Core模块,以支持运行Blazor服务器端应用。

部署到Azure

  1. 创建Azure App Service:登录到Azure门户,点击 “创建资源”,搜索 “Web 应用”,然后选择 “Web 应用” 服务。按照创建向导填写相关信息,如订阅、资源组、应用名称、运行时栈(选择.NET Core)等。
  2. 部署应用:在Visual Studio中,右键点击项目,选择 “发布”。在发布目标中选择 “Azure”,然后选择刚才创建的Azure App Service。按照提示完成部署过程。Azure会自动检测项目类型并进行相应的部署配置,确保应用能够在Azure上正常运行。

通过以上步骤,你可以使用Visual Basic开发、优化并部署Blazor服务器端渲染应用,充分利用.NET生态系统的强大功能来构建高效、交互式的Web应用。