Razor.Templating.Core
Razor.Templating.Core copied to clipboard
Razor View as an input string
Hi, This library looks great. However, I see that it might be a great to have a feature where in, instead of just reading the views from a folder, one should be able to pass it to the function. Use case: In case one would want to allow the user to edit the template, they same would not necessarily be save at the same place. It might be pulled from a blob, DB or any other location.
Thanks.
Hi @gr8tushar, that sounds like an interesting use case. However, as far as I know, I doubt this can be achieved as this library is just an abstraction of ASP.NET Core Razor engine which expects the razor view file path as input. Anyhow, I'll still check the possibilities & let you know. Thanks :)
Hi @soundaranbu, yup. This would be great if one would want to send out emails using console / background services via the templates customized in the web app / other places. More over, if the user customized a template, it would probably not be available in the compiled file / views folder. I would come either from the user directory / DB / BLOB.
Let me know in case you need more info. Would be happy to help in anyway.
I think this should be possible with a custom IFileProvider and Razor runtime compilation.
- Razor runtime compilation: https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-compilation?view=aspnetcore-5.0
- Custom IFileProvider example: https://github.com/mikebrind/RazorEngineViewOptionsFileProviders
I tried configuring services as follows:
var services = new ServiceCollection();
services.AddRazorPages().AddRazorRuntimeCompilation();
services.Configure<Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.MvcRazorRuntimeCompilationOptions>(opts =>
opts.FileProviders.Add(new MyCustomFileProvider()));
// Add RazorTemplating after registering all dependencies
// this is important for the razor template engine to find the injected services
services.AddRazorTemplating();
and when calling RazorTemplateEngine.RenderAsync, my custom file provider is correctly used by the razor engine, but I then get a CompilationFailedException.
I have found similar errors on the web:
- https://stackoverflow.com/questions/61526883/compilationfailedexception-during-runtime-compilation-of-razor-from-aspnetcore-t
- https://github.com/aspnet/Razor/issues/1212
But I couldn't get it to compile without errors.
Looks promising :) will give it a try. Thanks!
Hi @gr8tushar, that sounds like an interesting use case. However, as far as I know, I doubt this can be achieved as this library is just an abstraction of ASP.NET Core Razor engine which expects the razor view file path as input. Anyhow, I'll still check the possibilities & let you know. Thanks :)
Like @gr8tushar mentioned, our use case is that we have several user/customer-specific templates and as such they are stored either on the cloud or in the database for editing purposes. This library makes the email generation process so easy especially since we can use dependency injection to ensure we're only retrieving the data and services needed for any given template. Based on your comment here, I wondered if saving the file at runtime after pulling it from the db would help but it appears there's no runtime support at all. I found older libraries which support this capability and was wondering if this is something worth pursuing in the future or if it was ruled out due to relying on older/unsupported technologies.
@ins0mniaque I tried this approach. This is working in v1.7.0
. I'll be adding samples for this in the coming days. Also, I'm adding some helper classes. so that, it's easier to implement.
cc: @sjd2021 @gr8tushar
This is a great new feature. Thanks!
Hello, any idea when this will be available to use?
Hi @NichlasNielsen, this feature is already possible. Please refer to the above commit for sample implementation. I'll need to add documentation for this. I'll do that once I get some free time. Thanks.
Does this work for azure functions, I can't get it to work?
Hi @Joffreyvl, technically it should work. But I need to try once to confirm. In the meantime, please upload a sample project if possible. I'll take a look. Thanks.
@soundaranbu I create a sample project, but both the in-process and the isolated function don't work for me. When I run the in-process function I get a DI issue and when I run the isolated function the custom file provider isn't used.
Ok, I can the see the problem already. Make sure, you've followed the steps here for creating the razor class library https://soundaranbu.medium.com/render-razor-view-cshtml-to-string-in-net-core-7d125f32c79
@soundaranbu do you need a razor class library when you are doing runtime compilation? I am trying to read cshtml files from a blob storage account.
That's a valid point. It's not necessary. However, you'll need to make these changes to make it to work.
@soundaranbu thanks for the information! I got it to work, I can now dynamically render string templates! For others wanting to solve this problem, you can find a code sample in this repo.
~With my recent PR, the function public static void AddRazorTemplating(this IServiceCollection services)
could be extended to allow customizing the MvcRazorRuntimeCompilationOptions, such as public static void AddRazorTemplating(this IServiceCollection services, Action<MvcRazorRuntimeCompilationOptions>? setupOptions)
and if setupOptions
is not null, then services.Configure<MvcRazorRuntimeCompilationOptions>(setupOptions);
can be called. This approach will work for the manually registered instance instead of the static RazorTemplateEngine methods.~
My previous comment is not required. Callers can customize MvcRazorRuntimeCompilationOptions themselves during service collection setup.
Hi, I have a pull request #48 that should hopefully address your concerns. Can you take a look and provide any feedback to changes for your use case. In this case, you will need to use the following approach to initialize
var services = new ServiceCollection();
services.Configure<Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.MvcRazorRuntimeCompilationOptions>(opts =>
opts.FileProviders.Add(new MyCustomFileProvider()));
services.AddRazorTemplating();
and either use the static method RazorTemplateEngine.RenderAsync(...)
or you can inject in an instance of IRazorTemplateEngine
into your defendant service. Hopefully we can have a prerelease with these changes deployed to nuget soon.
any solution on this, rendering razor string as input instead of path ?
any solution on this, rendering razor string as input instead of path ?
The PR mention here was merged. You should be able save your template as an embedded resource and add a ManifestEmbeddedFileProvider.
Say you want to store your template in a database, you would need to create a file provider that could query the database for the given template.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.fileproviders.ifileprovider?view=dotnet-plat-ext-8.0