Why are Blazor lifecycle methods getting executed twice?

前端 未结 2 486
执笔经年
执笔经年 2020-12-17 16:30

So with a release of asp.net core 3.0 and blazor 1.0 I started doing some actual work with blazor. When splitting Blazor component code into code behind I am using the follo

相关标签:
2条回答
  • 2020-12-17 17:11

    I did a test with a fresh new blazorserver project, logging when lifecycle methods are called, and got this output:

    info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]
          User profile is available. Using 'C:\Users\Alsein\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
    info: Microsoft.Hosting.Lifetime[0]
          Now listening on: https://localhost:5001
    info: Microsoft.Hosting.Lifetime[0]
          Now listening on: http://localhost:5000
    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: D:\repos\HelloWorld
    info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
          Request starting HTTP/2 GET https://localhost:5001/
    info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
          Executing endpoint '/_Host'
    info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
          Route matched with {page = "/_Host"}. Executing page /_Host
    info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[103]
          Executing an implicit handler method - ModelState is Valid
    info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[104]
          Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
    crit: HelloWorld.MyBase[0]
          OnInitializedAsync
    crit: HelloWorld.MyBase[0]
          OnParameterSetAsync
    info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
          Executed page /_Host in 122.3724ms
    info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
          Executed endpoint '/_Host'
    info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
          Request finished in 216.7341ms 200 text/html; charset=utf-8
    info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
          Request starting HTTP/2 GET https://localhost:5001/css/site.css
    info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
          Request starting HTTP/2 GET https://localhost:5001/_framework/blazor.server.js
    info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
          Request starting HTTP/2 GET https://localhost:5001/css/bootstrap/bootstrap.min.css
    info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
          Sending file. Request path: '/css/site.css'. Physical path: 'D:\repos\HelloWorld\wwwroot\css\site.css'
    info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
          Sending file. Request path: '/_framework/blazor.server.js'. Physical path: 'N/A'
    info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
          Request finished in 44.733000000000004ms 200 text/css
    info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
          Sending file. Request path: '/css/bootstrap/bootstrap.min.css'. Physical path: 'D:\repos\HelloWorld\wwwroot\css\bootstrap\bootstrap.min.css'
    info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
          Request finished in 55.3613ms 200 text/css
    info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
          Request finished in 55.569900000000004ms 200 application/javascript
    info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
          Request starting HTTP/2 GET https://localhost:5001/css/open-iconic/font/css/open-iconic-bootstrap.min.css
    info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
          Sending file. Request path: '/css/open-iconic/font/css/open-iconic-bootstrap.min.css'. Physical path: 'D:\repos\HelloWorld\wwwroot\css\open-iconic\font\css\open-iconic-bootstrap.min.css'
    info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
          Request finished in 4.5189ms 200 text/css
    info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
          Request starting HTTP/2 POST https://localhost:5001/_blazor/negotiate text/plain;charset=UTF-8 0
    info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
          Request starting HTTP/2 GET https://localhost:5001/css/open-iconic/font/fonts/open-iconic.woff
    info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
          Sending file. Request path: '/css/open-iconic/font/fonts/open-iconic.woff'. Physical path: 'D:\repos\HelloWorld\wwwroot\css\open-iconic\font\fonts\open-iconic.woff'
    info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
          Request finished in 4.3562ms 200 application/font-woff
    info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
          Executing endpoint '/_blazor/negotiate'
    info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
          Executed endpoint '/_blazor/negotiate'
    info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
          Request finished in 24.7409ms 200 application/json
    info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
          Request starting HTTP/1.1 GET https://localhost:5001/_blazor?id=7oyJvbydrUy9tqlsH_DHzQ
    info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
          Executing endpoint '/_blazor'
    crit: HelloWorld.MyBase[0]
          OnInitializedAsync
    crit: HelloWorld.MyBase[0]
          OnParameterSetAsync
    

    From the result we can see that, the component is loaded twice.

    • The first time it was loaded as a simple Mvc component directly when the page is requested and handled by /_Host which must be specified with the following code in _Host.cshtml, which calls the lifecycle methods for the first time:
    @(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
    
    • Then resources are loaded including blazor.server.js.

    • Then the blazor app starts rendering.

    • Then the component is loaded as a blazor component, where the lifecycle methods are called for the second time.

    Try replacing RenderMode.ServerPrerendered with RenderMode.Server, then it behaves as expected, which is that the lifecycle methods are only called for once (when the blazor app starts).

    Conclusion: The default RenderMode is ServerPrerendered which must mean that Mvc could render the components as static contents in order to display the page contents before the blazor app is downloaded and starts, then when the blazor app starts, it takes over the page content. This must be a workaround for user experience that the browser user could wait less time for seeing the contents.

    0 讨论(0)
  • 2020-12-17 17:19

    I had exactly the same issue with a holding page for a site where I had a little css animation which looked great in development, but when I put it live it ran twice. Changing the RenderMode to Server certainly fixes the issue, but it appears notably slower.

    Funny because I would never have picked this up until I did this, for the final site I'll be switching back to ServerPrerendered

    0 讨论(0)
提交回复
热议问题