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

@inject razor views #362

Closed
mathysd opened this issue Dec 24, 2016 · 9 comments
Closed

@inject razor views #362

mathysd opened this issue Dec 24, 2016 · 9 comments
Labels

Comments

@mathysd
Copy link

mathysd commented Dec 24, 2016

Good job on the migration to .net core!
Will there be support for @Inject inside razors views? Or did I miss something?

As explained here

@dotnetjunkie
Copy link
Collaborator

dotnetjunkie commented Dec 24, 2016

UPDATE: There is Blazor Server App integration guide in the Simple Injector documentation.

I have to look into that, but my gut feeling is that this is a feature that shouldn't exist at all. Views should not have dependencies. Views should be dumb and all required data should be supplied to the view by the controller.

@dotnetjunkie
Copy link
Collaborator

dotnetjunkie commented Dec 25, 2016

After some investigation, I have to come to the conclusion that ASP.NET Core MVC currently lacks the proper hook that allows intercepting injection of Razor View Properties (i.e. services that are injected using @inject).

You can see that the way to resolve properties is hard-wired into the RazorPageActivator at line 204. At that line, GetRequiredService is called directly on the HttpContext.RequestServices object, which always points to the built-in container.

The only way to intercept this is by replacing the default RazorPageActivator with a custom implementation, because the RazorPageActivator doesn't have any virtual methods that allow us to override, nor does it depend on a dependency (e.g. an imaginary IRazorPagePropertyActivator) that we can override.

This design flaw means that the only way to add this behavior is to copy all the code from the original RazorPageActivator (and the internal PropertyActivator<TContext> and PropertyHelper as well) into your custom implementation of IRazorPageActivator. This allows you to make a few changes that would allow you to intercept the creation of properties to your own container.

This solution however isn't really feasible, because it causes a severe 'synchronization burden' on you, because you will have to keep these three files in sync with any possible changes and bug fixes that Microsoft will do on these three classes itself.

This does mean that the statements I made months ago about MVC having all the required interception points in place, where unfortunately false. This is an omission in the design of MVC.

But as I said previously, IMO from a design perspective, views should not have any dependencies; not even for "localization or data required only for populating view elements". This is better done at the controller level (or perhaps at a level between the controller and the view, by using decoration or interception to enrich this data). This keeps the views truly dumb.

@mathysd
Copy link
Author

mathysd commented Dec 25, 2016

Thanks for looking into this and I agree with you that views should be kept simple. I have a shared layout that displays some information about the current user and I don't want every controller to get this information and "push" it to the layout. But for now I think I can solve it with a view component that does support constructor injection.

As a last resort I could cross-wire the asp.mvc container to make use of the simple injector container to resolve dependencies for the views. Something like:

services.AddScoped<ISomething>(provider => container.GetInstance<ISomething>());
Pragmatic aproach but it feels a bit hacky :)

@dotnetjunkie
Copy link
Collaborator

dotnetjunkie commented Dec 25, 2016

That isn't that hacky at all, I must say. What you are doing is called "cross-wiring" and is almost always required when to run an application-specific container besides the built-in framework container. You sometimes have to cross-wire registrations from one side to the other. You want to keep the number of cross-wired dependencies (on both sides) to a minimum, but you will always need a few.

@dotnetjunkie
Copy link
Collaborator

ASP.NET Core 5.0 will allow the creation of Razor Components to be intercepted. Here's how to integrate it with Simple Injector.

@irmtim
Copy link

irmtim commented Dec 25, 2020

ASP.NET Core 5.0 will allow the creation of Razor Components to be intercepted. Here's how to integrate it with Simple Injector.

So and there's still no way to add support of @Inject in razor views?

@dotnetjunkie
Copy link
Collaborator

@irmtim ,

See https://simpleinjector.readthedocs.io/en/latest/advanced.html#enabling-property-injection

@dotnetjunkie
Copy link
Collaborator

@irmtim, I finally had some time to deep deeper into this, and unfortunately due to current limitations of Blazor (.NET 5.0) it is practically impossible to use the @inject attribute. But there is a workaround. You can read about what the issue is, what workaround there is, which issue I reported with Microsoft, and join the discussion here.

@dotnetjunkie
Copy link
Collaborator

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

No branches or pull requests

3 participants