您当前的位置: 首页 >  服务器

寒冰屋

暂无认证

  • 0浏览

    0关注

    2286博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

从Web/Razor模板构建Blazor服务器应用程序

寒冰屋 发布时间:2022-07-06 19:15:00 ,浏览量:0

本文的目的是探讨Blazor和Razor应用程序之间的区别。我们将从开箱即用的Razor ASPNetCore Web应用程序模板开始,逐步构建运行Blazor Server SPA所需的基础结构。

在本文中,我们将从标准AspNetCore Razor Web应用程序模板逐块构建Blazor Server应用程序。

本文的目的是探讨Blazor和Razor应用程序之间的区别。我们将从开箱即用的Razor ASPNetCore Web应用程序模板开始,逐步构建运行Blazor Server SPA所需的基础架构。它应该可以帮助您更快地了解Blazor,而不是简单地部署模板并使用它。

虽然我是Visual Studio的坚定拥护者,但我们在本练习中使用Visual Studio代码来更接近煤层。

先决条件
  • Visual Studio Code
  • NET 6.0 SDK

为简单起见,所有代码和组件都在一个命名空间Blazr中。

代码库

您可以在BlazrServer Github存储库中找到所有代码。

构建项目
  1. 在Documents中创建一个Repos文件夹(如果您还没有)。
  2. 创建一个Repos/BlazorServer文件夹。
  3. 在文件夹上打开Visual Studio Code。
  4. Ctl + '打开终端。

我们现在准备将模板项目部署到当前文件夹中。但是哪一个?

S C:\Users\shaun\source\repos\BlazrServer > dotnet new --list

获取所有已安装模板的列表。

我们追求:

ASP.NET Core Web App                    webapp,razor         [C#]        Web/MVC/Razor Pages

要使用它:

PS > dotnet new razor

我们得到:

The template "ASP.NET Core Web App" was created successfully.
This template contains technologies from parties other than Microsoft, 
see https://aka.ms/aspnetcore/6.0-third-party-notices for details.

Processing post-creation actions...
Running 'dotnet restore' on C:\Users\shaun\source\repos\BlazorServer\BlazorServer.csproj...
  Determining projects to restore...
  Restored C:\Users\shaun\source\repos\BlazorServer\BlazorServer.csproj (in 90 ms).
Restore succeeded.

以及部署到目录中的一组文件夹和文件。

至此,我们可以运行项目了:

PS > dotnet watch run debug

得到这个:

PS C:\Users\shaun\source\repos\BlazorServer> dotnet watch run debug
watch : Started
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7280
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5280
info: Microsoft.Hostingetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\Users\shaun\source\repos\BlazorServer\

和我们的网站。

要检查热重载,请更改Index.cshtml:

Welcome To my Nascient Blazor App

并保存它。我们得到:

watch : Exited
watch : File changed: C:\Users\shaun\source\repos\BlazorServer\Pages\Index.cshtml
watch : Started
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7280
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5280
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\Users\shaun\source\repos\BlazorServer\

并查看页面上的更改:

热重载正在工作。我们有一个正在运行的Razor Web应用程序。

为了结束本节,让我们快速浏览一下Program。

// Initialize the WebApplication Builder
var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddRazorPages();

// Build the App from the builder
var app = builder.Build();

// Configure the HTTP request pipeline
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();

// Run the Application
app.Run();

这:

  1. 创建WebApplicationBuilder类的一个实例。
  2. 将一组服务添加到builder的ServiceCollection。这些定义了WebApplication实例的依赖注入容器可以使用的服务。
  3. 构建WebApplication实例。
  4. 添加一组中间件来处理WebApplication实例服务的Web请求管道。
  5. 运行配置的WebApplication实例。
将Blazor组件添加到Razor页面

添加一个Components文件夹和一个/Component/HelloBlazor.razor组件文件。

它显示一条消息和时间:时间很有用,因为我们可以很容易地看到渲染事件何时发生。

@inherits ComponentBase
@namespace Blazr

Hello Blazor at @(time.ToLongTimeString())
Todays Message is : @Message
Set Time
@code { [Parameter] public string Message {get; set;} = string.Empty; private DateTime time = DateTime.Now; protected override void OnInitialized() => time = DateTime.Now; private void GetTime() => time = DateTime.Now; }

将Component.cshtml添加到Pages。它使用服务器端`Html.RenderComponentAsync`来呈现组件并加载Blazor服务器JavaScript代码:

@page
@{
    ViewData["Title"] = "Component page";
}

Welcome To my Component Page @(await Html.RenderComponentAsync (RenderMode.ServerPrerendered, new { Message = "Hello there!" }))

在_layout.cshtml中,添加一个新的顶部菜单项,以便我们可以导航到新页面。

  • Component
  • 您现在应该能够导航到Component并查看页面渲染。单击按钮,然后……没有任何反应。

    组件已在服务器上呈现,但未配置Blazor服务。打开开发者工具,你会看到一个JS错误。

    没有_framework/blazor.server.js可供下载。

    配置服务器以运行Blazor服务

    首先,我们添加Blazor服务器端服务。更新Program。`AddServerSideBlazor` 添加所有Blazor特定服务。

    // Add services to the container.
    builder.Services.AddRazorPages();
    builder.Services.AddServerSideBlazor();

    现在检查浏览器,您将看到两个错误。blazor.server.js现在可以下载,但它无法运行,因为服务器上没有运行Blazor Hub中间件来为SignalR请求提供服务。

    这需要Blazor中间件。要在Program中配置:

    app.MapRazorPages();
    app.MapBlazorHub();

    现在一切都运行没有错误。但是按钮点击不起作用:时间没有更新!

    转到HelloBlazor.razor。请注意,VS Code无法识别@onclick。

    我们需要Microsoft.AspNetCore.Components.Web。

    @inherits ComponentBase
    @namespace Components
    @using Microsoft.AspNetCore.Components.Web  // New

    该按钮现在可以工作并更新时间。

    我们有一个Blazor组件运行我们的Razor服务器端页面。老手的似曾相识!

    构建Blazor SPA

    在Razor页面中运行的组件不是单页应用程序。或者是吗?

    在我们构建完整版本之前——如在Blazor模板中——让我们构建一个非常简单的SPA。

    将_Imports.razor文件添加到项目根目录并添加以下代码。这将为所有razor组件设置全局程序集。

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.AspNetCore.Components.Web.Virtualization
    @using Microsoft.JSInterop

    将Routes文件夹添加到项目并添加以下razor组件:

    @namespace Blazr
    
    Index
    
    Hello, world!
    
    Welcome to your new app.

    /Routes/Counter.razor

    @namespace Blazr
    
    Counter
    
    Counter
    
    

    Current count: @currentCount

    Click me @code { private int currentCount = 0; private void IncrementCount() => currentCount++; }

    /Routes/Hello.razor

    @namespace Blazr
    
    

    添加一个Apps文件夹并添加:

    /Apps/BaseApp.razor

    @using Microsoft.AspNetCore.Components;
    @using Microsoft.AspNetCore.Components.Rendering;
    @using Microsoft.AspNetCore.Components.Web;
    
    @namespace Blazr
    
    
        
    Blazor Simple App
    • this.ChangeRootComponent("Index")'>Index
    • this.ChangeRootComponent("Counter")'>Counter
    • this.ChangeRootComponent("Hello")'>Hello
    • Server Home
    @body
    @code {
        [Inject] private NavigationManager? NavManager { get; set; }
    
        private Dictionary Routes => new Dictionary {
            {"Index", typeof(Blazr.Index)},
            {"Counter", typeof(Blazr.Counter)},
            {"Hello", typeof(Blazr.Hello)}
        };
    
        private Type rootComponent = typeof(Blazr.Index);
    
        private RenderFragment body => (RenderTreeBuilder builder) =>
        {
            builder.OpenComponent(0, rootComponent);
            builder.CloseComponent();
        };
    
        public void ChangeRootComponent(string route)
        {
            if (Routes.ContainsKey(route))
            {
                rootComponent = Routes[route];
                StateHasChanged();
            }
        }
    
        public void GoServerIndex()
        => this.NavManager?.NavigateTo("/Index", true);
    }

    rootComponent是要渲染的组件Type:默认是Index.razor。NavBar调用ChangeRootComponent更改rootComponent并通过调用StateHasChanged请求组件重新渲染。

    body是一个RenderFragment简单地添加rootComponent到渲染树并渲染它。在实践中,我们会检查实现IComponent的rootComponent:所有组件都必须实现IComponent。我还没有实现代码来保持简单易读。

    GoHome使用NavigationManager触发完整的浏览器重新加载,从而加载默认服务器页面。

    添加指向_Layout.cshtml的链接:

  • Blazor Simple App
  • 添加/Pages/SimpleBlazor.cshtml:

    @page
    @{
        Layout = null;
    }
    
    
    
        
        
        @ViewData["Title"] - BlazorServer
        
        
        
    
    
            @(await Html.RenderComponentAsync(RenderMode.ServerPrerendered))
    
        
    
    

    您现在应该能够导航到Simple App,并在顶部菜单栏链接之间导航。

    部分摘要

    我们创建了一个服务器端razor页面,该页面将Blazor组件加载为其主要内容。该组件由导航栏和子组件组成。单击导航栏中的链接只需更改子组件。在渲染器的StateHasChanged队列中排队重新渲染页面。Renderer运行渲染(实际上是代表页面的RenderFragment)并计算出旧DOM和新DOM之间的任何差异。它将差异传递给浏览器端Blazor JS代码,该代码更新浏览器显示的DOM。不涉及页面导航,只是DOM更改。

    构建完整的Blazor服务器应用程序 从Repo添加文件

    我们需要从Blazor应用程序中添加一些文件。

    添加/Routes/Shared文件夹并从Repo添加以下文件:

    • MainLayout.razor
    • MainLayout.razor.css
    • NavMenu.razor
    • NavMenu.razor.css

    这些是带有命名空间集和调整了NavLink的Blazor模板文件。

    将以下文件添加到wwwroot/css:

    • blazor-site.css

    这是重命名的Blazor模板CSS文件:我们已经有一个site.css。

    应用组件

    添加/Apps/App.razor并添加以下代码:这是标准代码。

    @namespace Blazr
    
        
            
            
        
        
            Not found
            
                

    Sorry, there's nothing at this address.

    路由

    为了使路由工作,我们需要将router `page`属性添加到我们希望将Router其视为路由的组件。

    更新以下组件,添加页面路由。一个组件可以有多个路由。

    Routes/Index.razor

    @page "/"
    @page "/App"
    ......

    Routes /Counter.razor

    @page "/Counter"
    ......

    Routes /Hello.razor

    @page "/Hello"
    ......

    Razor服务器端页面

    添加/Pages/Shared/_AppLayout.cshtml。

    这是Blazor Server启动页面,带有经过调整的样式表设置。

    @using Microsoft.AspNetCore.Components.Web
    @namespace Layouts
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    
    
    
        
        
        
        
        
        
        
    
    
        @RenderBody()
    
        
    An error has occurred. This application may no longer respond until reloaded. An unhandled exception has occurred. See browser dev tools for details. Reload 🗙

    添加/Pages/App.cshtml。

    这是Blazor应用程序启动页面。Blazor.App被指定为启动类,即App.razor。

    @page 
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @{
        Layout = "_AppLayout";
    }
    
    

    导航更改

    更新/Routes/Shared/NavMenu.razor。

    添加一个新的NavLink。

    Server Home

    并添加GoServerIndex“硬”导航到服务器端主页的方法。

    public void GoServerIndex()
        => this.NavManager?.NavigateTo("/Index", true);

    网页更改

    在/Pages/Shared/_Layout.cshtml中添加指向主页导航的新链接。

  • Blazor App
  • 将后备端点添加到Program。所有回退都指向Blazor应用程序。

    //.....
    app.MapBlazorHub();
    app.MapFallbackToPage("/App");
    
    app.Run();

    您现在应该能够导航到应用程序并按F5重新加载它。

    部分摘要

    我们现在拥有一个使用路由运行的成熟Blazor Server应用程序。区分Blazor路由和浏览器导航非常重要。物理检测差异的一种方法是查看工具栏中的“刷新”按钮——前进按钮旁边的圆圈。当浏览器导航事件发生时,您可以看到它激活。

    当您单击Blazor应用程序中的左侧导航菜单时,会发生路由。您可能正在单击anchor,但浏览器事件被Blazor Javascript代码拦截,并由Router组件接收。它有一个Routes/Component字典——通过在当前程序集中查找所有具有@page属性的组件来构建。它根据路由查找组件,并加载新组件。我们在Simple Blazor组件中创建了一个非常简单的版本。

    将Blazor应用程序设置为默认值

    当前设置有一个没有@page设置的Index.cshtml页面。这被视为站点https://localhost:nnnnn/的默认页面。

    如果设置了Blazor路由组件@page "/",为什么不使用它?这就是使用路由属性“Pages”调用Blazor组件会引起混淆的地方。将它们称为除页面之外的任何内容Routes:RouteComponents或RouteViews。Web服务器对这些路由一无所知。请求通过配置的中间件管道运行Program。在我们的设置中,将Pages app.MapRazorPages()中的Razor页面映射到web路由。如果它找到一个索引或默认Web文件,它就会使用它。

    要了解发生了什么,请查看Program中的端点映射:

    app.MapRazorPages();
    app.MapBlazorHub();
    app.MapFallbackToPage("/App");
    
    app.Run();

    当前的Index.cshtml被视为默认页面并MapRazorPages()返回它。

    要更改我们的设置,请在Index.cshtml上设置页面属性。

    @page "/index"
    @model IndexModel

    MapRazorPages现在将Index.cshtml映射到https://localhost:nnnnn/Index并且不再将其视为默认页面。

    该请求app.MapFallbackToPage("/App")会返回App.cshtml我们的Blazor应用程序启动页面。

    Blazor应用程序中的导航

    那么如果我们在Blazor应用程序中有一个导航到Web服务器索引的链接会发生什么?我们可以看到这一点NavMenu。

    如果我们要这样编码GoServerIndex:

    public void GoServerIndex()
        => this.NavManager?.NavigateTo("/Index");

    Blazor将请求视为本地请求,而不是导航。路由器找不到路由匹配,因此显示“抱歉,此地址没有任何内容”。信息。尝试一下!

    要“硬”导航,我们需要这样做:

    public void GoServerIndex()
        => this.NavManager?.NavigateTo("/Index", true);

    这会强制NavigationManager导航、重新加载页面并点击“程序”中间件管道。

    概括

    我做了一些调整,使我的实现与开箱即用的模板不同。这些都是:

    1. 我已经删除FetchData了,它只会使事情复杂化。
    2. App NavMenu将Index指向/App而不是/。
    3. Index.razor添加了一个@page "/App"。
    4. 所有Blazor页面组件现在都在Routes中。

    2和3修复了“默认页面问题”,即默认页面是服务器Razor文件,而不是Blazor应用程序。

    https://www.codeproject.com/Articles/5321697/Building-a-Blazor-Server-Application-from-the-Web

    关注
    打赏
    1665926880
    查看更多评论
    立即登录/注册

    微信扫码登录

    0.0641s