Razor.Templating.Core icon indicating copy to clipboard operation
Razor.Templating.Core copied to clipboard

DI Scoped service

Open anddrzejb opened this issue 4 years ago • 5 comments

I have been successfully using your library in my prod env. Thank you for your great work on this! However I have an issue, that maybe you can shed some light on. My scoped services are available in the views but apparently in a different scope. So whatever data is loaded to them in my blazor app, when I get them from the views, the service is instantiated again. Do you know how can I get services coming from the same scope? I imagine I could pass to my models IServiceProvider, but I'd rather avoid that...

anddrzejb avatar Jun 22 '21 12:06 anddrzejb

Hi @anddrzejb ,I'll look into this.. If possible you can send me a sample project. That will be helpful to debug the issue.

soundaranbu avatar Jun 24 '21 05:06 soundaranbu

No problem. Here is the minimal repro. In Common project there is a class AppState that is added to DI as scoped. It has its property ManuallySetProperty initialized in the Index.razor. You can see the property is still initialized in Counter. But when it is requested in the view, it is set to null.

scoped-issue

anddrzejb avatar Jun 24 '21 06:06 anddrzejb

Thanks for this! I'll look into it this weekend & let you know :)

soundaranbu avatar Jun 25 '21 05:06 soundaranbu

Update: I'm quite surprised that the library works with .NET 6+Blazor Server which is in my to do list to test. Okay coming to the issue, I found & fixed it for app models that uses scoped DI in http context (mvc, api) but blazor seems to be little tricky with scoped dependencies. Because In addition to http context, blazor server components use circuits over SignalR and they have their own scope (if I'm not wrong). I need to find a way to resolve the component/circuit context dependencies from within our library which is the challenging part.

Until then, I will suggest to resolve the scoped dependency within component & pass it as view model.

soundaranbu avatar Jul 06 '21 16:07 soundaranbu

That is what I do now. But, as you may realize, is quite uncomfortable. I actually have to prep a number of dtos with common data. Anyway, I will be waiting for your solution. Thanks a lot for this great lib!

anddrzejb avatar Jul 06 '21 16:07 anddrzejb

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.

pbolduc avatar Sep 13 '22 19:09 pbolduc

Hey @anddrzejb, if possible please try the fix in the new prerelease version and let us know! https://github.com/soundaranbu/Razor.Templating.Core/releases/tag/v1.8.0-rc.1

soundaranbu avatar Sep 18 '22 05:09 soundaranbu

Hi! I have a very little time to play around here. Unfortunatelly, bumping the version 1.8.0-rc.1 does not seem to work for the repro I mentioned in my second post in this issue. The @inject does not seem to provide me with State from the container. However I did not have any time to play around with this. Is there anything new in the dependency area that I should try or the new solution should work out-of-the-box?

anddrzejb avatar Sep 18 '22 18:09 anddrzejb

Oh sorry that I didn't mention the change. We need to inject the IRazorTemplateEngine instance instead of using the RazorTemplateEngine static class. So in your .razor file, you can try:

@inject IRazorTemplateEngine RazorTemplateEngine

soundaranbu avatar Sep 19 '22 06:09 soundaranbu

Two changes were required to get your sample application to work,

  1. Update reference Razor.Templating.Core in Common project to 1.8.0-rc.1
  2. Add @inject IRazorTemplateEngine RazorTemplateEngine to the top of Index.razor

This will ensure the new IRazorTemplateEngine interface is injected in the same scope as your view.

image

pbolduc avatar Sep 19 '22 16:09 pbolduc

Indeed that was enough. I must admit I find the solution quite unintuitive (the injection part, not the version bump), however it does work. Thank you for your work guys!

anddrzejb avatar Sep 19 '22 18:09 anddrzejb

The static class makes it easy to get started, especially for those use cases where your application/service doesn't natively use DI, like Azure Functions or a console app. However, in the more feature rich environments like your use case, using an injected service in the correct scope appeared to be a reasonable solution. Also, using an injectable service, it allows components to be tested independently for the actual rendering of the template.

I would think the general recommendation is to use the IRazorTemplateEngine interface instead of the static class unless you are not natively using DI in your application.

Thanks for raising your issue.

pbolduc avatar Sep 19 '22 19:09 pbolduc