Closed RedX2501 closed 4 years ago
@RedX2501 What is a self-contained template? Do you mean passing in a Stream object that resolves to a cshtml file? What is the interface contract you want?
@jzabroski You used to be able to write:
var engine = new RazorLightEngineBuilder() .UseMemoryCachingProvider() .Build();
.. but this now throws an exception, saying the _razorLightProject cannot be null.
Which release was that behavior available in? I'm newer to RazorLight than others, but trying to help make it great.
I imagine the reason for the change is so that it more explicitly wires dependencies.
Did the old behavior just assume embedded resources, file system, or some other approach I'm not thinking of, like not using a key at all and instead passing in a whole cshtml file as a string?
I'm not sure to be honest. In the version I currently use (just trying to upgrade now) - we did:
var razorEngine = new RazorLightEngineBuilder().UseMemoryCachingProvider().Build();
... and then specified the entire template contents as a string:
var template = File.ReadAllText(razorTemplatePath);
var emailBody = razorEngine.CompileRenderAsync(razorTemplateCacheKey, template, viewModel).Result;
Looking at it, I think to get it working now I think instead of reading the file myself, I think I need to specifiy the directory containing the template via the .UseFileSystemProject(<template dir>)
method and then just pass the template file name in to the .CompileRenderStringAsync()
method...
I think?
Correct. I would recommend using embedded resources, though. The main reason to use file system is to allow hot swapping templates, but you lose control over your deployment artifacts when you do that. I don't trust engineers to not sneak on servers and change things. At companies I've been at, sometimes it's business analysts who are friends with the executives who get access and change things and then bring down a whole sub-section of your app.
tl;dr: Use EmbeddedResource Project instead of UseFileSystemProject
Thanks for the clarification. Much appreciated!
Sorry, just following up again here. I think there's a bit of design flaw here. In 2.0.0-beta1, you MUST specify a project type when creating the engine:
var razorEngine = new RazorLightEngineBuilder()
.UseEmbeddedResourcesProject(typeof(EmailService)) // exception without this (or another project type)
.UseMemoryCachingProvider()
.Build();
But you then you can call razorEngine.CompileRenderStringAsync() and just pass a string in as your template, not using the resources provider at all.
I think just rendering a template from a string is a pretty common use-case, and seems confusing that you need to specify a project type (e.g. resources) that ultimately you'll never use.
Is there any scope to reintroduct the ability create a RazorEngine instance without a project type?
I mean, if you want to write test cases and the feature to support it, you are welcome to. But I suspect it's a lot of work to make sure there are no regressions, because everywhere you have a _razorProjectSystem you have a chance for a regression.
W.r.t using UseEmbeddedResourcesProject, the pattern Ivan uses in his tests is he creates a dummy class called Root that is in the Root namespace for your project. Not a great solution, but it's what I copied in my own projects.
Yeah, I was looking at the source earlier and I agree!
You're right though you can get around it by just specifying .UseEmbeddedResourcesProject(typeof(
Hopefully this solves @RedX2501 original question.
Thanks again
I'm quite glad this issue received so much attention :)
I'd really like to know WHAT a project is. Why I need it for and what are the implications of setting one? Is this in some documentation that I've missed? I don't have an ASP.Net background and the documentation about Razor that I've found never talk about projects.
allow hot swapping templates, but you lose control over your deployment artifacts when you do that
This is exactly my use-case. I have a model which the users can access with their own templates to generate C++ code for their application.
By self-contained I mean that the template has no imports to additional files.
Hello @user. I'm a self contained template because I don't require anything else.
As far as I can tell a project is effectively the ‘source’ of your .cshtml templates. E.g a folder somewhere or an embedded resource etc.
But my point above is that we have a method on the RazorEngine that just lets you compile a template by passing it in as a string (CompileRenderStringAsync). The ‘project’ (or source) is not relevant, so why do we need to set it when creating the RazorEngine?
Looking at the source the project is used everywhere and it seems to have become enforced during a big redesign of the compilation process. I suspect this particular use-case was maybe forgotten about?
Anyway, as far as the implications go, I just set RazorEngine to use the embedded resource project, passing in the type of the current class, but carried on calling CompileRenderStringAsync() anyway and passing in a string as the template and everything seems to work fine.
The resource project is totally ignored as far as I can tell and I haven’t seen any issues (yet).
@RedX2501 Interesting, it would be cool to create a list in the README of projects using RazorLight and their use cases. I got involved because I want my project FluentMigrator to use it for customizing SQL templates. FluentMigrator is arguably the most powerful SQL abstraction tool out there for modifying db schemas. But a pain point exists around SQL-level overrides ; core templates cannot be trivially overridden.
Sorry, just following up again here. I think there's a bit of design flaw here. In 2.0.0-beta1, you MUST specify a project type when creating the engine:
var razorEngine = new RazorLightEngineBuilder() .UseEmbeddedResourcesProject(typeof(EmailService)) // exception without this (or another project type) .UseMemoryCachingProvider() .Build();
Excuse my stupidity but I just compiled 2.0.0-beta1 and I can't seem to find the RazorLightEngineBuilder
class. Where is it?
I can't seem to find it anywhere with the available source code for beta 1:
I'm absolutely confused now :( I installed version 2.0.0-beta1 from the nuget and voila. A RazorLightEngineBuilder is available. Yet in the source I can't find any trace of it...
Well if I use version 2.0.0-beta1 I get the following exception:
You need a German Delta Layer on RazorLight to prevent it from leaking 😆 https://www.youtube.com/watch?v=ZbQmKsXIBYc
100 jahre langzeitbestandigkeit
Master (60fdee0b937233d201f8c57410e6ee5a02b2dffc) seems to work at least.
I think we can close this as it seems to work now.
Maybe it would be interesting to retag 2.0.0-beta1 to the proper commit that was used to generate the nuget package...
@jzabroski @mattwendels Can you please suggest to me what is the issue here
public async Task<string> GenerateHtml(EmailModel model)
{
var engine = new RazorLightEngineBuilder()
.UseFileSystemProject("C:/Users/vijku/source/repos/CalendarApp/CalendarApp/bin/Release/net6.0/win-x64/publish/win-x64")
.UseMemoryCachingProvider()
.Build();
string result = await engine.CompileRenderAsync("Templates/Email.cshtml", model);
return result;
}
I am getting the below error :
DefaultMetadataReferenceManager uses specific paths that may not be supported by your deployment option. This can happen if you compile everything into a giant dll where the CodeBase property is null. You'll have to implement an alternative if you stick with whatever deployment you are using that is causing this
@jzabroski thanks for the help . I was able to fix the issue . Now i am getting below issue
Code used:
public async Task
return result;
Error coming
RazorLight.TemplateNotFoundException: RazorLightProjectItem of type RazorLight.Razor.EmbeddedRazorProjectItem with key Email.cshtml could not be found by the RazorLightProject of type RazorLight.Razor.EmbeddedRazorProject and does not exist in dynamic templates. See the "KnownDynamicTemplateKeys" and "KnownProjectTemplateKeys" properties for known template keys.
at RazorLight.Compilation.RazorTemplateCompiler.CreateRuntimeCompilationWorkItem(String templateKey)
at RazorLight.Compilation.RazorTemplateCompiler.OnCacheMissAsync(String templateKey)
at RazorLight.EngineHandler.CompileTemplateAsync(String key)
at RazorLight.EngineHandler.CompileRenderAsync[T](String key, T model, ExpandoObject viewBag)
at CalendarAppService.EmailSender.GenerateHtml(EmailModel model) in C:\Users\vijku\source\repos\CalendarApp\CalendarApp\CalendarApp.cs:line 179
at CalendarAppService.EmailSender.Main() in C:\Users\vijku\source\repos\CalendarApp\CalendarApp\CalendarApp.cs:line 47
at CalendarApp.Worker.ExecuteAsync(CancellationToken stoppingToken) in C:\Users\vijku\source\repos\CalendarApp\CalendarApp\Worker.cs:line 21
at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService)
Please re-read the error message for next steps:
RazorLight.TemplateNotFoundException: RazorLightProjectItem of type RazorLight.Razor.EmbeddedRazorProjectItem with key Email.cshtml could not be found by the RazorLightProject of type RazorLight.Razor.EmbeddedRazorProject and does not exist in dynamic templates. See the "KnownDynamicTemplateKeys" and "KnownProjectTemplateKeys" properties for known template keys.
@jzabroski yeah, I did get through an error, but no fruitful result as such. do you know how to fix it? I tried many things but no result.
saw this link as well https://github.com/toddams/RazorLight/issues/474
What is not fruitful?
Is your feature request related to a problem? Please describe. Currently a
???Project
must be passed to the builder to be able to render templates even when usingCompileRenderStringAsync
.Describe the solution you'd like It would be nice if nothing was needed if the templates I'm using are self-contained.