ipjohnson / Grace

Grace is a feature rich dependency injection container library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ASP.NET Controller activation fails

jods4 opened this issue · comments

commented

I encountered a blocking bug that I can't explain.

I use Grace as IoC container in my asp.net core project, set up as described in Grace.AspNetCore.(Hosting,Mvc).

My ASP.NET Core controllers are created by DI, thanks to:

services.AddMvcCore().AddControllersAsServices()

(Notice that I don't add controllers to Grace directly, it's only done by the ASP.NET call above).

I have split my application in multiple assembly and I now notice that controllers that inject classes from other assemblies fail, although the classes are registered in the Grace container (locating them works).

Here are some error details.

Consider a basic Test class:

[Export] class Test { }

(Registration is made by attributes, I observed that this happens after ASP.NET Core registrations such as controllers above)

Consider a basic HelloController that imports Test:

[Route("hello")]
public class HelloController
{
  public HelloController(Test t)
  { }
}

When Test is in the main assembly, this works fine.
But when Test is in another assembly (which is also imported into Grace at startup, more on that later) then locating the controller fails:

Grace.DependencyInjection.Exceptions.LocateException: Could not locate Type Portal.Test
1 Importing Portal.Controllers.HelloController 
2 Importing Portal.Test  for constructor parameter t

   at Grace.DependencyInjection.Impl.InjectionContextValueProvider.GetValueFromInjectionContext[T](IExportLocatorScope locator, StaticInjectionContext staticContext, Object key, IInjectionContext dataProvider, Object defaultValue, Boolean useDefault, Boolean isRequired)
   at lambda_method195(Closure , IExportLocatorScope , IDisposalScope , IInjectionContext )
   at Grace.AspNetCore.MVC.GraceControllerActivator.Create(ControllerContext context)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()

I do not understand this problem because if I inspect the container at the end of ConfigureContainer, then clearly Test is there.
From WhatDoIHave:

--------------------------------------------------------------------------------
Export Type: Portal.Controllers.HelloController
As Type: Portal.Controllers.HelloController
Priority: 0
Externally Owned: False
Lifestyle: Transient
Depends On
	Dependency Type: ConstructorParameter
	Member Name: t
	Import Type: Portal.Test
	Has Filter: False
	Has Value Provider: False
	Is Satisfied: False
--------------------------------------------------------------------------------
Export Type: Portal.Test
As Type: Portal.Test
Priority: 0
Externally Owned: False
Lifestyle: Transient
Depends On
	None

Notice that HelloController says Is Satisfied: False, although Test is clearly in there.
Doing scope.Locate<Test>() works, but scope.Locate<HelloController>() fails.

Any idea what can be causing this?
Is there anything I could do to try and debug this issue? Thanks!

commented

Not sure if that's expected or not, but I just noticed (HelloController).TypeBeingImported != (Test).ActivationType.
That's surprising to me, trying to figure out why (.net 5.0).

EDIT: no, that's extremely suspicious, probably why it fails.
According to MSDN, Types can be compared for equality:
https://docs.microsoft.com/en-us/dotnet/api/system.type?view=net-5.0#comparing-type-objects-for-equality

I wonder if I found a bug in .net 5.0...

commented

Sorry for the noise, digging further I found the error and it's in my code.

I used Assembly.LoadFile to dynamically load all assemblies, and it turns out this way can load the same assembly twice (with different types, then). Assembly.LoadFrom is the way to go and fixes the problem.

Source: https://stackoverflow.com/a/48712787/2427990