RazorLight
RazorLight copied to clipboard
IViewLocalizer in cshtml template
Hello people,
I'm trying to create an email using Razorlight.
In my template, I wan't to inject IViewLocalizer
to have a localized email.
My issue is when I render the template, I have a Null Reference
if I use the IViewLocalizer
This is normal or I'm doing something wrong ?
Code
@using RazorLight
@inherits TemplatePage<Gardendynamics.Commons.Picaplant.Models.Output.OrderModel>
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> @Localizer["OrderTitleEmail"]</title>
<style type="text/css">
body {margin: 0; padding: 0; min-width: 100%!important;}
.content {width: 100%; max-width: 800px;}
.header {padding: 40px 30px 20px 30px;}
.body {padding: 10px 20px;}
.footer {padding: 10px 0px;}
.orderitem{
border-collapse:separate; border-spacing:0 5px;
}
.orderitem thead tr th{border-bottom: 1px solid black; border-collapse:separate; border-spacing:5px 5px;}
</style>
</head>
string result = await engine.CompileRenderAsync("OrderCompleteEmail.cshtml", new { Name = "John Doe" });
Do you add RazorLight to IServicecollection?
Hi,
Yes I add it to my service collection. Possibly my implementation is incorrect...
I can't access to the code now, I will provide my code late in the day
Hi,
My Code :
internal class GardendynamicsRazorLightEngine
{
private static string templatePath = $@"{Directory.GetCurrentDirectory()}/EmailTemplates";
private static IRazorLightEngine engine;
public static IRazorLightEngine Engine{
get{
if(engine == null){
engine = new RazorLightEngineBuilder()
.UseFilesystemProject(templatePath)
.UseMemoryCachingProvider()
.Build();
}
return engine;
}
}
}
services.AddSingleton(f =>
{
return GardendynamicsRazorLightEngine.Engine;
});
Any Idea?
Please, use this extension method
https://github.com/toddams/RazorLight/blob/master/src/RazorLight/Extensions/ServiceCollectionExtensions.cs#L10
@toddams I have the same problem as OP. I have used the extension method above and it doesn't work. Usages of 'Localizer[]' throws null reference exception. Using RazorLight 2.0 beta 1.
services.AddRazorLight(() => {
return new RazorLightEngineBuilder()
.UseFilesystemProject(AppContext.BaseDirectory)
.UseMemoryCachingProvider()
.Build();
});
If I do serviceProvider.GetService<IViewLocalizer>()
I see that ViewLocalizer is correctly registered.
Hi, @toddams
Our company really really needs this fix. We would like to help. Do you have any ideia/advice on how to fix it, so we can help you with the implementation?
Thanks!
are there any workarounds for this? I suppose you could just put all the localized strings into the ViewBag? Would be a lot of work to do and eventually undo though...
Having the same problem when using this functionality via FluentEmail.Razor
package, found no workaround yet (apart from moving all translatable strings to the model instance and translating it upfront).
@atsvetkov, the following workaround adds support for @inject
attributes to FluentEmail.Razor
:
services.AddRazorLight(() => new RazorLightEngineBuilder()
.UseMemoryCachingProvider()
.Build());
public static class FluentEmailExtensions
{
public static FluentEmailServicesBuilder AddInjectedRazorRenderer(
this FluentEmailServicesBuilder builder)
{
builder.Services.TryAddSingleton<ITemplateRenderer, InjectedRazorRenderer>();
return builder;
}
public class InjectedRazorRenderer : ITemplateRenderer
{
private readonly IRazorLightEngine _engine;
public InjectedRazorRenderer(IRazorLightEngine engine)
{
_engine = engine;
}
public string Parse<T>(string template, T model, bool isHtml = true)
{
return ParseAsync(template, model, isHtml).GetAwaiter().GetResult();
}
public async Task<string> ParseAsync<T>(string template, T model, bool isHtml = true)
{
return await _engine.CompileRenderAsync(RazorRenderer.GetHashString(template), template, model);
}
}
}
So is this going to be fixed without a workaround? We are really hoping to have localization working...
Hey, can I get a update on this? Is it fixed or do I need a workaround?
I am always willing to accept PRs. It always amazes me when I get workarounds posted and people don't want to help create a PR to fix the issue. The issue is that the Builder pattern doesn't register things using .TryAddSingleton
Microsoft DI extension method, which is what the workaround accomplishes.
In any event, this isn't something I need for my applications and the path forward seems pretty straightforward to me.
I am also trying to get localization to work in a generated HTML page.
The above workaround is specific to FluentMail and not to RazorLight.
I would be more than happy to make a PR with a fix/workaround for this issue, but I don't know enough about the workings of Razorlight (yet) to know where to find the root cause.
@arvdrpoo (1) Does the solution in the FAQ work for you? It disables encoding entirely. As for what RazorLight does, it registers Razor compiler Directives and then adds "callbacks" for things like @inject
. There are a few tests around RawString if you search the code base.
I had also started to rework some of the DI registration logic, but the complicated part is how to handle the callback logic.
@jzabroski If you mean this part of the ReadMe/FAQ, it doesn't seem to work. Or do you mean something else?
I'll try to take a look at the callbacks, and see what I can find
I don't know if this is still an issue. I couldn't get the localizer to inject into the view. I have created a workaround by injecting the localizer into the model and exposing it as a model property for use in the view. Works fine for my purposes.
Minimal implementation here: https://github.com/Ric43/RazorLightPoC