Open vkirienko opened 9 months ago
The discussion that you mentioned last actually contains code that, according to the OP, works.
Thank you! That's what I wanted to confirm.
I just curios why it is not part of SimpleInjector default integration with .NET Core MVC?
I just curios why it is not part of SimpleInjector default integration with .NET Core MVC?
Mainly because of two reasons:
ITimeProvider
into the page, return a model that contains a DateTime CurrentTime
property or something similar.I hope this makes sense.
Good points, especially #2. I'm about to migrate large application to .NET Core. It has clever framework on top of MVC with again clever code in MVC views. And I agree it would be better not to have it and keep views as simple as possible.
Thank you, again for great DI library!
@dotnetjunkie thank you again for pointing to right direction. Code from this response works as intended and I was able to inject dependencies using [Import] attribute. It is nice to be able to do it as I have couple of properties in our base razor page class where we use service locator pattern and now we can use proper DI.
But my question was not clear and in fact I was looking to way to inject dependency using @inject directive.
Index,cshtml
@inject IDueToReminderInfoService dueToReminderInfoService
It still fails with error:
InvalidOperationException: No service for type 'MyApp.Services.Dates.IDueToReminderInfoService' has been registered.
Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
Microsoft.AspNetCore.Mvc.Razor.RazorPagePropertyActivator+<>c__DisplayClass8_0.<CreateActivateInfo>b__2(ViewContext context)
Microsoft.Extensions.Internal.PropertyActivator<TContext>.Activate(object instance, TContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorPagePropertyActivator.Activate(object page, ViewContext context)
MyApp.Core.SimpleInjector.SimpleInjectorRazorpageActivator.Activate(IRazorPage page, ViewContext context) in SimpleInjectorRazorpageActivator.cs
+
activator.Activate(page, context);
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, bool invokeViewStarts)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
In generated Index.cshtml.cs file property I'm trying to inject RazorInject attribute
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public IDueToReminderInfoService dueToReminderInfoService { get; private set; } = default!;
From the stack trace I understand that your custom SimpleInjectorRazorpageActivator
calls into the Microsoft.AspNetCore.Mvc.Razor.RazorPagePropertyActivator
class. This means that your custom SimpleInjectorRazorpageActivator
does not correctly differentiate between dependencies that should be resolved from Simple Injector and dependencies that should be resolved from the built-in DI infrastructure. Clearly, IDueToReminderInfoService
is something that should be pulled in from Simple Injector. This means that in this stack trace, SimpleInjectorRazorpageActivator
should not call RazorPagePropertyActivator
, but rather call Simple Injector instead.
I guess we have to call Microsoft.AspNetCore.Mvc.Razor.RazorPagePropertyActivator from SimpleInjectorRazorpageActivator. Comment in SimpleInjectorRazorpageActivator says:
// This implementation depends on the default RazorPageActivator, because initialization
// of framework dependencies is required for activation to succeed.
As far as I can see RazorPagePropertyActivator uses build-in service provider and not extendable,
var serviceProvider = context.HttpContext.RequestServices;
var value = serviceProvider.GetRequiredService(property.PropertyType);
I think I'm starting to see the problem here. The implementation I proposed in 25, calls into the core behavior and let Simple Injector inject properties that are marked with the ImportAttribute
. That would work great, but doesn't allow using the @inject tag. With @inject, Razor is generating an [Inject]
attribute, but the framework's behavior is to resolve dependencies marked with inject. This is what is causing the exception in your case.
Since the core behavior isn't extendable, the only option is to skip calling into the core behavior. But that causes new problems, because there is a set of dependencies that seem to be injected through a different mechanism. Not initializing them might cause issues of its own.
It might be possible to work around these issues, but at this point I'm unsure how to proceed.
I don't have that many services used @inject. So in my case I think reasonable workaround would be to register services used with @inject in MS DI container and resolve them through SimpleInjector.
services.AddScoped<IDueToReminderInfoService>(c => SI.Container.GetInstance<IDueToReminderInfoService>());
Hi,
I think this question was already asked before but reading through several threads I still don't have clear understanding if @inject can be used with SimpleInjector. Clearly it does not work by default but is there any workaround?
For the record I went through these.
https://github.com/simpleinjector/SimpleInjector/issues/860 https://github.com/simpleinjector/SimpleInjector/issues/362 https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/issues/25
Thank you