Razor Slices Documentation

repository·main·Indexed 20 days ago

https://github.com/damianedwards/razorslices

A lightweight, high-performance Razor-based templating engine for ASP.NET Core designed for Minimal APIs. It provides low allocations, native AOT support, and works without the overhead of MVC, Razor Pages, or Blazor. Features include source-generated proxy types for strongly-typed template creation, support for layouts via RazorLayoutSlice, and direct integration with IResult for returning HTML from route handlers.

Tokens
1.4K
Snippets
6
Records
7
Agent score
19%

What's inside Razor Slices

  1. How Razor Slice proxy types work

    main

    The Razor Slices source generator automatically creates a public sealed partial class proxy for every .cshtml file. This proxy provides a strongly-typed Create method based on the @inherits directive:

    • Slices with a model: If you use @inherits RazorSlice<T>, the proxy gets Create(T model).
    • Slices without a model: If you use @inherits RazorSlice, the proxy gets Create().

    This allows for compile-time validation of the models passed to your templates.

    Tip: To use record classes instead of class for these proxies, set <RazorSliceProxiesAsRecords>true</RazorSliceProxiesAsRecords> in your project file.

  2. Using Layouts with Razor Slices

    main

    Razor Slices support layouts through a specific inheritance and implementation pattern.

    1. Define the Layout

    Inherit from RazorLayoutSlice or RazorLayoutSlice<TModel> and use @await RenderBodyAsync() to define where the content goes. You can also use @await RenderSectionAsync("SectionName") to define sections.

    @inherits RazorLayoutSlice<LayoutModel>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>@Model.Title</title>
        @await RenderSectionAsync("head")
    </head>
    <body>
        @await RenderBodyAsync()
        <footer>
            @await RenderSectionAsync("footer")
        </footer>
    </body>
    </html>

    2. Implement the Slice using the Layout

    To use a layout, implement IUsesLayout<TLayout> or IUsesLayout<TLayout, TModel>. If the layout requires a model, you must implement the LayoutModel property in the slice's @functions block.

    @inherits RazorSlice<SomeModel>
    @implements IUsesLayout<LayoutSlice, LayoutModel>
    
    <div>
        @* Content here *@
    </div>
    
    @functions {
        public LayoutModel LayoutModel => new() { Title = "My Layout" };
    }

    3. Overriding Sections

    Slices can provide content for layout sections by overriding ExecuteSectionAsync:

    protected override Task ExecuteSectionAsync(string name)
    {
        if (name == "lorem-header")
        {
            <p>Custom section content.</p>
        }
        return Task.CompletedTask;
    }

    Note: The standard Razor @section directive is not supported.

    @inherits RazorSlice<SomeModel>
    @implements IUsesLayout<LayoutSlice, LayoutModel>
    
    @functions {
        public LayoutModel LayoutModel => new() { Title = "My Layout" };
    }
  3. Configure Razor Slices for your project

    main

    Follow these steps to set up a standard Razor Slices environment:

    1. Create a Slices directory: Create a folder named Slices in your project.
    2. Add _ViewImports.cshtml: Add this file to your Slices directory to configure the base type and imports:
      @inherits RazorSlice
      
      @using System.Globalization;
      @using Microsoft.AspNetCore.Razor;
      @using Microsoft.AspNetCore.Http.HttpResults;
      @using RazorSlices;
      
      @tagHelperPrefix __disable_tagHelpers__:
      @removeTagHelper *, Microsoft.AspNetCore.Mvc.Razor
    3. Create a Slice: Add a .cshtml file (e.g., Hello.cshtml) inheriting from RazorSlice<TModel> or RazorSlice:
      @inherits RazorSlice<DateTime>
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="utf-8">
          <title>Hello from Razor Slices!</title>
      </head>
      <body>
          <p>Hello from Razor Slices! The time is @Model</p>
      </body>
      </html>
    4. Use in Minimal APIs: The source generator creates a proxy type with a Create method. Use it in your Program.cs:
      app.MapGet("/hello", () => MyApp.Slices.Hello.Create(DateTime.Now));
    app.MapGet("/hello", () => MyApp.Slices.Hello.Create(DateTime.Now));
  4. Install CI builds from GitHub Packages

    main

    To use the latest builds from the main branch, you must add the GitHub package feed to your NuGet configuration.

    1. Create a GitHub Personal Access Token (PAT) with read:packages scope.
    2. Run the following command, replacing <GITHUB_USER_NAME> and <PERSONAL_ACCESS_TOKEN>:
    dotnet nuget add source -n GitHub -u <GITHUB_USER_NAME> -p <PERSONAL_ACCESS_TOKEN> https://nuget.pkg.github.com/DamianEdwards/index.json
  5. Restrict Razor Slices to specific directories

    main

    By default, all .cshtml files in your project are treated as Razor Slices. To restrict this behavior (e.g., only to a Slices directory), set EnableDefaultRazorSlices to false in your project file and explicitly include the files you want to be processed by the source generator.

    <PropertyGroup>
      <EnableDefaultRazorSlices>false</EnableDefaultRazorSlices>
    </PropertyGroup>
    <ItemGroup>
      <!-- Only treat .cshtml files in Slices directory as Razor Slices -->
      <RazorSlice Include="Slices\**\*.cshtml" Exclude="Slices\**\_Layout.cshtml;Slices\**\_ViewImports.cshtml" />
    </ItemGroup>
  6. Returning Razor Slices from Minimal APIs

    main

    Because RazorSlice implements IResult, you can return a slice instance directly from a Minimal API route handler.

    • Direct return: () => MySlice.Create(model)
    • Using extensions: In .NET 10+, you can use Results.RazorSlice<TSlice, TModel>(model). In earlier versions, use Results.Extensions.RazorSlice<TSlice, TModel>(model).
    // Direct return
    app.MapGet("/hello", () => MyApp.Slices.Hello.Create(DateTime.Now));