RazorLight icon indicating copy to clipboard operation
RazorLight copied to clipboard

NullReferenceException when @inject directive is used in built-in FilesystemProject (RazorLightEngineBuilder.UseFilesystemProject)

Open reponemec opened this issue 7 years ago • 10 comments
trafficstars

If I use

void ConfigureRazorLight(IServiceCollection services)
        {
            services.AddSingleton<IMyService, MyService>();

            RazorLightEngine engine = new RazorLightEngineBuilder()
              .UseFilesystemProject(_hostingEnvironment.ContentRootPath)
              .UseMemoryCachingProvider()
              .Build();

            services.AddRazorLight(() => engine);
        }

And if I have a

@inject IMyService _myService

directive in Razor view then _myService is always compiled as null. In case of built-in embeded resources (.UseEmbeddedResourcesProject(typeof(Program))) it works fine.

I don't know whether it is a bug or something is wrong in my code.

reponemec avatar Jul 31 '18 21:07 reponemec

Did you find a solution to this?

TrieBr avatar Dec 04 '18 02:12 TrieBr

Hi, @reponemec , i got the same issue, are you found a solution about this? Thanks!

smartlei24 avatar Jan 22 '19 07:01 smartlei24

https://www.bountysource.com/issues/69012066-no-effect-with-inject-when-use-filesystem-project

reponemec avatar Dec 13 '19 21:12 reponemec

@reponemec In looking at this, we only have one test covering @inject - do you think you can create a PR with a failing test for me to look into? I wonder if this is a bug due to "cross-wiring". Are you using Microsoft DI or a custom DI container?

		[Fact]
		public async Task Ensure_Registered_Properties_Are_Injected()
		{
			var collection = new ServiceCollection();
			string expectedValue = "TestValue";
			string templateKey = "key";
			collection.AddSingleton(new TestViewModel() { Title = expectedValue });
			var propertyInjector = new PropertyInjector(collection.BuildServiceProvider());

			var builder = new StringBuilder();
			builder.AppendLine("@model object");
			builder.AppendLine("@inject RazorLight.Tests.Models.TestViewModel test");
			builder.AppendLine("Hello @test");

			var engine = new RazorLightEngineBuilder()
				.UseEmbeddedResourcesProject(typeof(Root))
				.Build();

			engine.Options.DynamicTemplates.Add(templateKey, builder.ToString());
			ITemplatePage templatePage = await engine.CompileTemplateAsync(templateKey);

			//Act
			propertyInjector.Inject(templatePage);

			//Assert
			var prop = templatePage.GetType().GetProperty("test").GetValue(templatePage);

			Assert.NotNull(prop);
			Assert.IsAssignableFrom<TestViewModel>(prop);
			Assert.Equal((prop as TestViewModel).Title, expectedValue);
		}

jzabroski avatar Dec 13 '19 22:12 jzabroski

Note to self: This issue, #317, and #239 all are related to people wanting to transitively inject IRazorLightEngine into another class instance with Microsoft DI. The action item is to write a test case that demonstrates this failing.

jzabroski avatar Mar 26 '20 01:03 jzabroski

Hi,

Is there any update or workaround ?

vd3d avatar Apr 19 '20 11:04 vd3d

Hi there,

I am also experiencing this issue, has there been an update to this? With regards to your test case it's using UseEmbeddedResourcesProject where like others I'm using UseFilesystemProject

Trying @inject AppSettings AppSettings

image

dotnetshadow avatar Jan 29 '21 04:01 dotnetshadow

Please post your DI config. The screenshot is pretty much useless and nobody can Google search it and benefit.

jzabroski avatar Jan 29 '21 12:01 jzabroski

Sorry about that, I'm using FluentEmail (https://github.com/lukencode/FluentEmail,) which uses RazorLight underneath. For my DI configuration I'm using

var emailSettings = config.GetSection("EmailSettings").Get<AuthMessageSenderOptions>();

            var smtpClientOptions = new SmtpClientOptions
            {
                UseSsl = emailSettings.UseSsl,
                Password = emailSettings.Password,
                Port = emailSettings.Port,
                Server = emailSettings.Server,
                User = emailSettings.Username,
                UsePickupDirectory = false,
                RequiresAuthentication = !string.IsNullOrEmpty(emailSettings.Username),
                SocketOptions = SecureSocketOptions.StartTlsWhenAvailable
            };
            
            services.AddFluentEmail(emailSettings.SystemEmailFrom, emailSettings.SystemEmailFromName)
                .AddRazorRenderer()
                .AddMailKitSender(smtpClientOptions);

services..AddTransient<IEmailSender, EmailService>();

Not sure if that helps or not.

I think the issue is related to this ticket: https://github.com/toddams/RazorLight/issues/166 so I think I can work around it Thanks for creating a great library much appreciated

dotnetshadow avatar Jan 31 '21 06:01 dotnetshadow

For the record, I experienced the same issue. The engine was build as follow (i.e. not with some dependency injection).

var engine = new CustomRazorLightEngineBuilder()
  .UseFileSystemProject(Path.Combine(Directory.GetCurrentDirectory(), "Views"))
    .UseMemoryCachingProvider()
    .Build();

Adding the following two lines below the snippet fixed the issue:

var injector = new PropertyInjector(_serviceProvider);
engine.Options.PreRenderCallbacks.Add(template => injector.Inject(template));

ancailliau avatar Jun 26 '23 16:06 ancailliau