El contenedor LightInject IoC lanza stackoverflow al resolver el tipo

Al probar el contenedor LightInject IoC http://www.lightinject.net/ lanza una excepción de stackoverflow al resolver el tipo ISomeService:

Todos los tipos están registrados en App_Start:

container.RegisterAssembly("MyApp*.dll");

Y luego, cuando intento resolverlo en el controlador, falla y arroja una excepción de desbordamiento de pila:

    public SomeController(ISomeService someService)
    {
         _someService = someService;
    }

También tiene el mismo error al usar ServiceLocator:

ServiceLocator.Current.GetInstance<ISomeService>();

Lo rastreé y puedo ver que está fallando en la clase LightInject ServiceContainer justo aquí, pero no veo por qué está fallando todavía.

public object GetInstance(Type serviceType)
{
    return GetDefaultDelegate(serviceType, true)(constants.Items);
}

Después de llamar a GetDefaultDelegate, la ruta de ejecución vuelve a terminar en GetInstance, lo que provoca un bucle infinito y un desbordamiento de pila.

EDITAR 2: he rastreado esto más y parece ser causado por SomeService que tiene tanto el constructor como la inyección de propiedad al mismo tiempo:

public class SomeService : ISomeService 
{
    public IAnotherService AnotherService { get; set; }
    public SomeService(IAnotherService anotherService)
    {
        AnotherService = anotherService;
    }
}

La dependencia IAnotherService AnotherService se está inyectando a través del constructor y la propiedad, pero no había intención de usar inyectores de propiedad.

EDIT 3

Hay varias capas en la aplicación que usan ServiceLocator, así que inicialmente agregué LI a su propio proyecto usando NuGet, así que tenía:

MyApp.IoC.LightInject
MyApp.Repositories
MyApp.Services
MyApp.Web.UI

Pero en realidad no es necesario agregarlo a su propio proyecto porque el proveedor del localizador de servicios se puede configurar en la capa de la interfaz de usuario:

var serviceLocator = new LightInjectServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);

Así que acabo de eliminar el proyecto adicional y, en su lugar, puse los paquetes NuGet en la capa de la interfaz de usuario. También instalé LightInject.Annotation y deliberadamente no llamé al método container.EnableAnnotatedPropertyInjection(), para garantizar que solo se use la inyección del constructor. Todavía está lanzando un stackoverflow.

Para probar si la resolución está funcionando, solo estoy haciendo esto en mi método HomeController.Index():

public ActionResult Index()
{
    var a = ServiceLocator.Current.GetInstance<ISomeService>();
}

Agregué algunos registros de consola a los métodos ServiceController.GetInstance para poder ver cuál era el flujo de llamadas a métodos que conducía al desbordamiento de pila. Este es el registro, y los resultados son un poco inesperados. Puede ver que cuando llama a CreateDelegate() para ISomeService, primero intenta obtener una instancia de HomeController, ¿por qué?

DoGetInstance: ISomeService. Key = ''
GetInstance: ISomeService
TryGetValue: ISomeService not found
TryAddValue: trying to add ISomeService now
CreateDynamicMethodDelegate: ISomeService
CreateDynamicMethodDelegate: calling CreateDelegate() for ISomeService
DoGetInstance: HomeController. Key = ''
GetInstance: HomeController
TryGetValue: HomeController not found
TryAddValue: trying to add HomeController now
CreateDynamicMethodDelegate: HomeController
CreateDynamicMethodDelegate: calling CreateDelegate() for HomeController
DoGetInstance: ISomeService. Key = ''
GetInstance: ISomeService
TryGetValue: ISomeService not found
TryAddValue: trying to add ISomeService now
CreateDynamicMethodDelegate: ISomeService
CreateDynamicMethodDelegate: calling CreateDelegate() for ISomeService
DoGetInstance: HomeController. Key = ''
GetInstance: HomeController
TryGetValue: HomeController not found
TryAddValue: trying to add HomeController now
CreateDynamicMethodDelegate: HomeController
CreateDynamicMethodDelegate: calling CreateDelegate() for HomeController
DoGetInstance: ISomeService. Key = ''
GetInstance: ISomeService
TryGetValue: ISomeService not found
TryAddValue: trying to add ISomeService now
CreateDynamicMethodDelegate: ISomeService
CreateDynamicMethodDelegate: calling CreateDelegate() for ISomeService
DoGetInstance: HomeController. Key = ''
GetInstance: HomeController
TryGetValue: HomeController not found
TryAddValue: trying to add HomeController now
CreateDynamicMethodDelegate: HomeController
CreateDynamicMethodDelegate: calling CreateDelegate() for HomeController
DoGetInstance: ISomeService. Key = ''
GetInstance: ISomeService
TryGetValue: ISomeService not found
TryAddValue: trying to add ISomeService now
CreateDynamicMethodDelegate: ISomeService
CreateDynamicMethodDelegate: calling CreateDelegate() for ISomeService

Cuando comento el constructor del servicio, la resolución funciona y todas las dependencias se resuelven mediante inyección de propiedad. Si el constructor está incluido, lanza la excepción stackoverflow.

Y aunque la resolución de ISomeService funciona solo cuando se usan propiedades, no puedo resolver IAnotherService si ese servicio incluye ISomeService en sus dependencias. Espero que el registro anterior arroje algo de luz sobre el problema. El rendimiento de LightInject hasta ahora ha sido significativamente mejor que Unity

preguntado el 21 de septiembre de 13 a las 12:09

1 Respuestas

Siendo el autor de LightInject, intentaré responder lo mejor que pueda.

En primer lugar, LightInject nunca debe lanzar una StackOverflowException, por lo que es algo que debe analizarse en función de lo que describa aquí.

Y entiendo claramente que la inyección de propiedad no era su intención aquí, ya que tendría poco sentido inyectar el servicio dos veces (Constructor y Propiedad).

En realidad, hay varias cosas que podemos hacer para evitar que la dependencia se inyecte en la propiedad.

  1. Haga que la propiedad sea de solo lectura eliminando el setter público.
  2. Registre el servicio utilizando lo que la documentación denomina registro de servicio "explícito".

    container.Register<ISomeService>(f => new SomeService(f.GetInstance<IAnotherService>())); 
    

    Esto hará que se ignoren las propiedades públicas porque ahora hemos sido explícitos sobre cómo resolver las dependencias de la clase SomeService.

  3. Hacer uso de LightInject.Annotation

    Esto asegurará que solo las propiedades marcadas con InjectAttribute tendrán sus dependencias inyectadas. En su caso específico, esto significaría simplemente dejar la propiedad como está sin el atributo. En la raíz de la composición, podemos habilitar esto haciendo esta configuración simple.

    container.EnableAnnotatedPropertyInjection(); 
    

Como dije antes, investigaré más a fondo la StackOverflowException y haré los ajustes adecuados para este caso. Mi primer pensamiento sería lanzar una excepción si el contenedor encuentra una dependencia que es elegible para la inyección tanto como una dependencia del constructor como una dependencia de la propiedad.

Espero que esto ayude.

Atentamente

bernhard richter

EDITAR

Aunque el problema parece estar resuelto para su caso, todavía me gustaría poder reproducir esto en una prueba. La razón por la que obtiene una excepción probablemente no sea tan simple como que el servicio tiene una dependencia de constructor y una dependencia de propiedad del mismo tipo.

Considere este servicio

public class FooWithConstructorAndPropertyDependency : IFoo
{
    public FooWithConstructorAndPropertyDependency(IBar bar)
    {
        Bar = bar;
    }

    public IBar Bar { get; set; }
}

LightInject felizmente inyectará la dependencia.

container.Register<IBar, Bar>();
container.Register<IFoo, FooWithConstructorAndPropertyDependency>();

container.GetInstance<IFoo>();

Entonces debe haber algo más que esté causando la excepción. Le agradecería si pudiera encontrar el ejemplo más pequeño que reproduzca la excepción para que esto pueda solucionarse. Es un poco difícil para mí hacer más investigaciones sin que algo falle :) Si elige hacer este esfuerzo, puede publicarlo aquí o enviarme un correo electrónico a bernhard.richter@gmail.com.

Respondido el 24 de Septiembre de 13 a las 07:09

La pregunta se ha actualizado con más detalles, lamentablemente LightInject.Annotations no ha ayudado. - JK.

Lo siento, corrección de mi edición anterior. ahora estoy llamando container.EnableAnnotatedPropertyInjection() y está resolviendo el servicio mediante inyección de constructor. Gracias :) Volveré a ejecutar mis pruebas para ver si se pueden resolver todos los servicios/controladores. JK.

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.