Components

All rendered Blazor views descend from the ComponentBase class, this includes Layouts, Pages, and also Components.

A Blazor page is essentially a component with a @page directive that specifies the URL the browser must navigate to in order for it to be rendered. In fact, if we compare the generated code for a component and a page there is very little difference. The following generated source code can be found in Counter.razor.g.cs in the folder obj\Debug\netcoreapp3.0\Razor\Pages.

namespace MyFirstBlazorApp.Client.Pages
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Components;
    using System.Net.Http;
    using Microsoft.AspNetCore.Components.Forms;
    using Microsoft.AspNetCore.Components.Routing;
    using Microsoft.AspNetCore.Components.Web;
    using Microsoft.JSInterop;
    using MyFirstBlazorApp.Client;
    using MyFirstBlazorApp.Client.Shared;

    [Microsoft.AspNetCore.Components.LayoutAttribute(typeof(MainLayout))]
    [Microsoft.AspNetCore.Components.RouteAttribute("/counter")]
    public class Counter : Microsoft.AspNetCore.Components.ComponentBase
    {
        protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder)
        {
            builder.AddMarkupContent(0, "<h1>Counter</h1>\r\n");
            builder.OpenElement(1, "p");
            builder.AddContent(2, "The counter value is ");
            builder.AddContent(3, counter);
            builder.CloseElement();
            builder.AddMarkupContent(4, "\r\n");
            builder.OpenElement(5, "button");
            builder.AddAttribute(6, "class", "btn btn-primary");
            builder.AddAttribute(7, "onclick", Microsoft.AspNetCore.Components.EventCallback.Factory.Create<Microsoft.AspNetCore.Components.UIMouseEventArgs>(this, IncrementCounter));
            builder.AddContent(8, "Increment counter");
            builder.CloseElement();
        }

    private int counter = 42;

    private void IncrementCounter()
    {
        counter++;
    }
  }
}

[Microsoft.AspNetCore.Components.RouteAttribute("/counter")] identifies the URL for the page.

[Microsoft.AspNetCore.Components.LayoutAttribute(typeof(MainLayout))] identifies which layout to use.

In fact, because pages are merely components decorated with additional attributes, if you alter the Pages/Index.razor file of a default Blazor app, it is possible to embed the Counter page as a component.

@page "/"

<h1>Hello, world!</h1>
Welcome to your new app.
<Counter/>

When embedding a page within another page, Blazor treats it as a component. The LayoutAttribute on the embedded page is ignored because Blazor already has an explicit container – the parent component that contains it.