# RazorSlices: Razor templates for ASP.NET Core without MVC, Razor Pages or Blazor

> RazorSlices is a Razor-based templating library for ASP.NET Core that renders HTML from Minimal APIs and middleware using unbuffered streaming, with a source generator that produces strongly-typed proxies for each .cshtml file. It is MIT licensed, targets .NET 8 and later, and its API surface is still moving.

**DamianEdwards/RazorSlices** — Lightweight Razor-based templates for ASP.NET Core without MVC, Razor Pages, or Blazor.

- Repository: https://github.com/DamianEdwards/RazorSlices
- Stars: 590 · Forks: 30
- Language: HTML
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/damianedwards-razorslices

## It is Razor without the framework that usually comes with it

RazorSlices is described as lightweight Razor-based templates for ASP.NET Core without MVC, Razor Pages or Blazor, optimized for high-performance, unbuffered rendering with low allocations. The README states it is compatible with trimming and native AOT, and that it is good for returning dynamically rendered HTML from Minimal APIs, middleware and similar places. That framing tells you what the library is not doing, and that matters more than the feature list. Razor syntax is a way to write HTML with C# expressions in it, and ASP.NET Core has historically shipped it as part of MVC, where the controller, the model binding and the view lookup convention all come along for the ride. RazorSlices keeps the syntax and drops the convention, so a template is a file you name, a source generator gives you a typed wrapper for it, and you return that wrapper from a handler. The repository layout supports the reading. There is a src/ directory for the library, samples/ with PagesAndSlices, RazorClassLibrary and WebApp subdirectories, a tests/ directory, and the usual build infrastructure including a Directory.Build.props, a Directory.Packages.props for central package versioning, a RazorSlices.slnx solution file, a global.json and a nuget.config. The primary language recorded for the repository is HTML, which is a fair description of a project whose substance is template files.

## A source generator turns each .cshtml file into a typed Create method

The mechanism that makes this usable rather than a novelty is the source generator, and the README describes its contract precisely. Each .cshtml file has a proxy type generated for it, and that proxy can be used as the generic argument to the rendering APIs. The generator detects the model type from the @inherits directive, so a template that says @inherits RazorSlice<DateTime> produces a Create method taking a DateTime, while a template with no model produces a parameterless Create. The README gives the two forms, MyApp.Slices.Hello.Create(DateTime.Now) and MyApp.Slices.Home.Create(). The stated payoff is compile-time validation that you are passing the correct model type, which is the thing a hand-rolled HTML string builder can never offer. The construction mechanism is also documented, and the detail matters for anyone debugging startup. Proxies construct the compiled Razor template directly with new, including setting its model in an object initializer, and the README notes this requires a Razor compiler that emits template types accessible to application code. Property injection is initialised lazily before rendering, and reflective construction is used only for replacement types coming from Hot Reload. If your build does not emit accessible template types, that requirement is the first thing to check.

## The setup is a package reference, a Slices folder and one line of C#

The getting started steps are short enough to follow exactly. You add the NuGet package into an ASP.NET Core project on .NET 8 or later:

```shell
> dotnet add package RazorSlices
```

Then you create a directory called Slices and put a _ViewImports.cshtml in it, which is the file that sets the base type and the namespaces:

```cshtml
    @inherits RazorSlice

    @using System.Globalization;
    @using Microsoft.AspNetCore.Razor;
    @using Microsoft.AspNetCore.Http.HttpResults;
    @using RazorSlices;
    
    @tagHelperPrefix __disable_tagHelpers__:
    @removeTagHelper *, Microsoft.AspNetCore.Mvc.Razor
```

The tag helper lines are doing real work rather than being boilerplate. The prefix directive disables tag helpers for the file, and the removeTagHelper line removes the MVC Razor tag helpers specifically, which is what keeps a Razor Pages or MVC project from injecting its own conventions into a file that is supposed to be a plain slice. A template file then lives alongside it, and the whole file is a normal HTML document with a model expression:

```cshtml
    @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>
```

And the handler that returns it is a single line in Program.cs:

```csharp
    app.MapGet("/hello", () => MyApp.Slices.Hello.Create(DateTime.Now));
```

No controller, no view lookup, no model binder. The template is a class, so the return type is the generated proxy, and the compiler checks the model type for you.

## Taking over which files count as slices is one project file property

By default every .cshtml file in your project is treated as a Razor Slice, with _ViewImports.cshtml and _ViewStart.cshtml excluded. That default is convenient in a small project and wrong in a larger one, since a Razor Pages application will have view files that are not slices at all. The fix is documented, and it starts with the EnableDefaultRazorSlices property set to false, followed by an explicit item group listing the RazorSlice items to include and exclude:

```xml
    <PropertyGroup>
      <EnableDefaultRazorSlices>false</EnableDefaultRazorSlices>
    </PropertyGroup>
```

The result, as the README puts it, is that the source generator only generates proxy types for .cshtml files in the Slices directory. The RazorSlice item that follows uses a glob to include the cshtml files under the Slices directory and an exclude list naming the layout and the view imports files, so a project can have several slice folders and still leave particular files out of the generator. This is the part of the design that lets RazorSlices coexist with an existing Razor Pages application rather than requiring you to pick one, and it is worth setting up deliberately from the start rather than discovering the conflict when a stray view file fails to compile.

## Streaming is the feature the sample project is built to show

The streaming sample is the clearest statement of what unbuffered rendering buys you. You run the sample with dotnet run --project samples/WebApp --framework net10.0 and open the /streaming route, which is also linked as Streaming in the sample's footer. The page immediately flushes Counting down... 10, then flushes a plain JavaScript script block every second to update the number through zero, and after showing zero for one second it replaces the message with Countdown complete!. The README is careful about the mechanism, and the detail is the point. The sample uses FlushAsync() in the Razor slice together with cancellation-aware server-side delays, with no JavaScript libraries and no additional requests, so the browser gets its updates over the same response rather than through polling. The endpoint also opts out of the sample's development response buffering with DisableResponseBuffering(), so updates stream even under the default launch profiles, and the README notes this helper works on individual endpoints and route groups. It adds DisableResponseBufferingAttribute metadata implementing IDisableResponseBufferingMetadata, and the attribute can also be applied directly to a handler method. The buffering middleware runs after routing and checks the selected endpoint's metadata, leaving all other endpoints buffered, which is the detail that makes the approach safe to adopt partially.

## The API has already had a breaking removal in it

The README contains a migration note that anyone adopting this should read before upgrading. The generator-facing SliceDefinition and SliceDefinition<TModel> APIs have been removed, and the instruction is to rebuild applications and Razor Class Libraries with the matching source generator and runtime when upgrading. The reassurance in the same paragraph is that the generated proxy Create methods and the IRazorSliceProxy interfaces are unchanged, so the code that calls the library survives, but the code that generated or configured slices does not. The README also says the library is still new and that features are being actively added, and the feature list begins with ASP.NET Core 8.0 and above and strongly-typed models with compile-time model validation. The current version numbers reflect that state. The listed releases are v0.12.2 on 2026-10-20, v0.12.1 on 2026-09-28 and v0.12.0 on 2026-09-23, and the last push to the repository was on 2026-10-22. A 0.x version with removals inside a minor version is the normal pattern for a young library, and it means the upgrade path is a coordinated rebuild of source generator and runtime rather than a version bump. The MIT licence and the ThirdPartyNotices.txt file at the root are the other two facts worth checking before you depend on it.

## Conclusion

RazorSlices suits a team serving HTML from Minimal APIs, middleware or a static file handler that wants Razor syntax without adopting MVC, Razor Pages or Blazor, and who cares about streaming responses and trimming. It is the wrong choice if your application is already a Razor Pages or Blazor application, where the framework already provides what this library offers, and it is the wrong choice if you cannot accept an API that is still being reshaped, since the SliceDefinition APIs have already been removed in a recent version. Verify first that your project targets .NET 8 or later, that the Razor compiler in your build emits template types visible to application code, and that you read the changelog before upgrading, because the generator and runtime must be rebuilt in step.

## FAQ

### What is RazorSlices and what does it replace?

It is a library of lightweight Razor-based templates for ASP.NET Core that works without MVC, Razor Pages or Blazor, rendering HTML from Minimal APIs and middleware with unbuffered streaming, low allocations, and compatibility with trimming and native AOT.

### How do I add RazorSlices to an ASP.NET Core project?

Run dotnet add package RazorSlices into a project targeting .NET 8 or later, create a Slices directory with a _ViewImports.cshtml that inherits RazorSlice and removes the MVC Razor tag helpers, add your .cshtml templates, then return a generated proxy from a handler with app.MapGet.

### How do I control which .cshtml files are treated as Razor Slices?

By default all .cshtml files are slices apart from _ViewImports.cshtml and _ViewStart.cshtml. Set the EnableDefaultRazorSlices property to false and add an explicit RazorSlice item group in the project file that includes the cshtml files under Slices while excluding _Layout.cshtml and _ViewImports.cshtml.

### What changed in the RazorSlices API that I need to know about before upgrading?

The generator-facing SliceDefinition and SliceDefinition<TModel> APIs have been removed, so applications and Razor Class Libraries must be rebuilt with the matching source generator and runtime. The generated proxy Create methods and the IRazorSliceProxy interfaces are unchanged.

## Sources

- [DamianEdwards/RazorSlices on GitHub](https://github.com/DamianEdwards/RazorSlices)
- [Issues](https://github.com/DamianEdwards/RazorSlices/issues)
- [License: MIT](https://github.com/DamianEdwards/RazorSlices/blob/main/LICENSE)
- [README](https://github.com/DamianEdwards/RazorSlices/blob/main/README.md)
- [Releases](https://github.com/DamianEdwards/RazorSlices/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/damianedwards-razorslices
