With .NET 8 on the horizon, Minimal APIs continues to grow its offerings, slowly providing a similar feature set to the frameworks before, including ASP.NET Core MVC and Razor Pages. I was surprised when someone in the community (👋 Hi Johnathan Channon) pointed me to a fascinating RazorSlices project. RazorSlices is written by Damian Edwards, an ASP.NET Core team member with a history of working with the Razor view engine. His goal is to bring Razor functionality to Minimal API adopters in a similar way that ASP.NET Core MVC, Razor Pages, and Blazor users enjoy today.

In this post, we’ll see how to set up RazorSlices in your ASP.NET Core applications and think about the pros and cons of its usage.

Getting Started with RazorSlices

In a Minimal API project, start by installing the RazorSlices package. You can do this by using the dotnet add package RazorSlices command or by adding the appropriate PackageReference in your .csproj file.

<PackageReference Include="RazorSlices" Version="0.7.0" />

Next, create a folder at the root of your ASP.NET Core application. It can be named anything you like. I chose Slices as it was what the documentation recommended. This directory is where you’ll place all your Razor views to be used in your Minimal API endpoints.

Within the Slices folder, create a new file named _ViewImports.cshtml. The view imports file allows you to create a shared context for all views within the folder, including namespaces, base classes, and tag helpers. Here’s the contents of my file.

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

You’ll notice two strange things when looking at this file:

  1. The @inherits value is of RazorSliceHttpResult to work with the IResult type used my Minimal APIs.
  2. Tag helpers are removed and obfuscated. That’s because they’re not supported in this model. Only expect to port a Razor Pages implementation over to RazorSlices by making some modifications or concessions.

Next, you’ll want to create a new Hello.cshtml view in the Slices folder.

@inherits RazorSliceHttpResult<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>

Note that the view also uses the @inherit attribute, but this time uses a generic type definition. The generic type argument is the type of the @Model instance.

Finally, you’ll want to use the view in your Minimal API endpoint.

var builder = WebApplication.CreateBuilder(args);  
var app = builder.Build();  
  
app.MapGet("/", () =>  
    Results.Extensions.RazorSlice("/Slices/Hello.cshtml", DateTime.Now));  
  
app.Run();

And that’s it! You are now rendering Razor views through your Minimal API endpoint.

For folks using JetBrains tooling, go a little extra and install JetBrains.Annotations.

dotnet add package JetBrains.Annotations

Then, modify your code to look like the following.

using JetBrains.Annotations;  
  
var builder = WebApplication.CreateBuilder(args);  
var app = builder.Build();  
  
app.MapGet("/", () =>  
    Slice("/Slices/Hello.cshtml", DateTime.Now));  
  
app.Run();  
  
IResult Slice<T>([AspMvcView]string viewPath, T model)  
    => Results.Extensions.RazorSlice(viewPath, model);

The benefit here is you can now Ctrl + Click through to your view right from the C# code. That should help your productivity. This works because you need to reference RazorSlice views by the absolute path, and JetBrains Rider and ReSharper undertand that behavior. Pretty awesome, right?

The Pros of RazorSlices

The most obvious benefit here is that you can now use Razor to generate HTML results in your Minimal API endpoints. I might be biased, but I love the Razor syntax and its benefits to the web development experience.

Another significant benefit is your Razor views can also use the @inject attribute, giving you access to dependencies in the HTML rendering process.

If performance is a concern of yours, there is a SliceFactory, that can help reduce the cost associated with looking up views. This can be an easy win for folks looking to eek out more performance. Speaking of performance, there are plans to add Ahead of Time (AOT) support.

The Cons of RazorSlices

Let’s talk about the drawbacks of using RazorSlices, because there are a few.

As mentioned, if you’re looking for a one-to-one replacement for MVC or Razor Pages, you will be disappointed. It’s meant to be something other than a drop-in replacement for either approach. This is evident when using features like TagHelpers or View Components.

The library has no current support for partial views, making view composition and componentization impossible. It may find its way into the package but is currently unavailable. This includes the view infrastructure associated with MVC, like layouts and layout sections. As I said previously, this is not a drop-in replacement.

A new paradigm means leaving behind the past paradigm. If you depend on third-party Razor libraries, they may not work in this current iteration.

Conclusion

RazorSlices is worth checking out if you’re looking for a way to render HTML one step above string interpolation in your API endpoints. It provides the basics of what you love about Razor syntax, including expressions, control structures, looping, and code blocks. For most, that’s going to be enough to accomplish any goal. That said, if you’re looking for an ASP.NET Core MVC replacement, this library is far from being that, but that’s OK.

Check out the library at RazorSlices and let me know your thoughts. As always, thanks for reading and sharing my blog posts.