Loading Razor views programmtically in netcore

Hey guys,

I am migrating some existing .Net427 projects to .NetCore3.1, and trying to have a multi-targetted project that works for both: net472 and netcoreapp3.1.

For netcoreapp3.1 I am referencing ServiceStack.Mvc instead of ServiceStack.Razor, and using the RazorFormat plugin, but cannot translate this code to netcore3.1 code, because theses methods no longer exist.

What would be the equivalent netcoreapp3.1 version of this code:

That’s only for .NET Framework where we have control over the Razor implementation.

For .NET Core Razor all features are built on top of MVC’s Razor implementation and custom page rendering hasn’t been implemented yet, can be something I can look into although #Script is far more flexible for rendering custom views where you have complete control over the the behavior and features of each page render.

Thanks @mythz,

I need to do something equivalent in ASPNetCore.
I am using Razor Views (in a Views folder) to generate HTML views called by an API, as part of an OAuth2 Server implementation.

Id appreciate any pointers you have to how to do this in a similar way.

p.s. I guess one option is to add Mvc to my API host and generate the pages using Controllers?

You’d need to add Mvc anyway since ServiceStack’s Razor support relies on MVC, here’s the Startup.cs for the razor template:

But yeah if MVC exposes a way to do embedable rendering I’d use that.

I’ve added support for stand-alone Razor Views in the latest v5.8.1 Release on MyGet.

New APIs include the familiar GetViewPage() for retrieving View Pages (e.g. under ~/Views) and GetContentPage() for retrieving Content Pages (e.g. under wwwroot/) then you can use RenderToHtmlAsync() to render the HTML output in a UTF-8 ReadOnlyMemory<char> which you can return directly (for optimal efficiency) or if needed you can convert it to a string with .ToString()

public async Task<object> Any(MyRequest request)
{
    var razor = GetPlugin<RazorFormat>();
    var view = razor.GetViewPage("MyView");
    if (view == null)
        throw HttpError.NotFound("Razor view not found: " + "MyView");

    var ret = await razor.RenderToHtmlAsync(view, new MyModel { Name = "World" },
        layout:"_MyLayout"); //if Layout specified in `.cshtml` page it uses that
    return ret;
}

Although for maximum efficiency you can write it to a Stream with WriteHtmlAsync() where you can write the UTF-8 bytes directly to the OutputStream instead of above where it converts it into a UTF-8 string before converting it back to UTF-8 bytes when it writes it out again, e.g:

public async Task Any(MyRequest request)
{
    var razor = GetPlugin<RazorFormat>();
    var view = razor.GetViewPage("MyView");
    if (view == null)
        throw HttpError.NotFound("Razor view not found: " + "MyView");

    await razor.WriteHtmlAsync(Response.OutputStream, view, 
        new MyModel { Name = "World" }, 
        layout:"_MyLayout"); //if Layout specified in `.cshtml` page it uses that
}

If needed it also supports anonymous Types, e.g:

await razor.RenderToHtmlAsync(view, new { Name = "World" });

and in your Razor view you’ll need to specify you’re using a dynamic model, e.g:

@model dynamic

Wow. Great work! Thanks for doing that.