Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Razor View as an input string #26

Open
gr8tushar opened this issue Jul 20, 2021 · 20 comments
Open

Razor View as an input string #26

gr8tushar opened this issue Jul 20, 2021 · 20 comments

Comments

@gr8tushar
Copy link

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.

@soundaranbu
Copy link
Owner

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 :)

@gr8tushar
Copy link
Author

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.

@ins0mniaque
Copy link

I think this should be possible with a custom IFileProvider and Razor runtime compilation.

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:

But I couldn't get it to compile without errors.

@soundaranbu
Copy link
Owner

Looks promising :) will give it a try. Thanks!

@sjd2021
Copy link

sjd2021 commented Dec 1, 2021

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.

@soundaranbu
Copy link
Owner

soundaranbu commented Mar 2, 2022

@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

@ins0mniaque
Copy link

This is a great new feature. Thanks!

@NichlasNielsen
Copy link

Hello, any idea when this will be available to use?

@soundaranbu
Copy link
Owner

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.

@Joffreyvl
Copy link

Does this work for azure functions, I can't get it to work?

@soundaranbu
Copy link
Owner

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.

@Joffreyvl
Copy link

@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.

@soundaranbu
Copy link
Owner

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

@Joffreyvl
Copy link

@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.

@soundaranbu
Copy link
Owner

That's a valid point. It's not necessary. However, you'll need to make these changes to make it to work.

@Joffreyvl
Copy link

@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.

soundaranbu added a commit that referenced this issue Jul 2, 2022
@pbolduc
Copy link
Contributor

pbolduc commented Sep 9, 2022

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.

@pbolduc
Copy link
Contributor

pbolduc commented Sep 13, 2022

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.

@vaskolekoski
Copy link

any solution on this, rendering razor string as input instead of path ?

@pbolduc
Copy link
Contributor

pbolduc commented Mar 19, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants