logging - ¿Cómo puedo registrar todas las solicitudes de resolución en el contenedor de Autofac?
dependency-injection (2)
Estoy tratando de corregir algunos problemas en una base de código heredado. Creo que está siendo causado por una excepción que se produce porque algo no se puede resolver desde el contenedor de Autofac. Sin embargo, creo que la excepción está siendo enterrada en algún lugar y no estoy viendo la causa raíz. Estoy seguro de que se está solicitando algo a un controlador que no se puede encontrar o algo que se puede encontrar tiene una dependencia que no se puede satisfacer. No hay cláusulas de protección, etc., así que creo que tengo un problema de referencia nulo. Para probar y depurar esto, quiero ver todas las solicitudes que no se encuentran en el contenedor.
¿Hay alguna forma de registrar todas las solicitudes que Autofac no pudo resolver? O, alternativamente, simplemente registrar todas las solicitudes en el contenedor?
Solo para construir una excelente respuesta de Travis, en caso de que ayude a alguien en el futuro.
Si la estructura de su clase es muy profunda, puede ser más fácil detectar la ruta problemática, si muestra objetos en una jerarquía de composición. Esto se puede lograr con algo como esto:
using System;
using System.Text;
using Autofac;
using Autofac.Core;
namespace Tests
{
public class LogRequestModule : Module
{
public int depth = 0;
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
IComponentRegistration registration)
{
registration.Preparing += RegistrationOnPreparing;
registration.Activating += RegistrationOnActivating;
base.AttachToComponentRegistration(componentRegistry, registration);
}
private string GetPrefix()
{
return new string(''-'', depth * 2);
}
private void RegistrationOnPreparing(object sender, PreparingEventArgs preparingEventArgs)
{
Console.WriteLine("{0}Resolving {1}", GetPrefix(), preparingEventArgs.Component.Activator.LimitType);
depth++;
}
private void RegistrationOnActivating(object sender, ActivatingEventArgs<object> activatingEventArgs)
{
depth--;
Console.WriteLine("{0}Activating {1}", GetPrefix(), activatingEventArgs.Component.Activator.LimitType);
}
}
}
Salida de muestra:
--Resolving SomeProject.Web.Integration.RestApiAdapter.RestApiAdapter
----Resolving SomeProject.Web.Integration.RestApiAdapter.Client.ClientFactory
------Resolving SomeProject.Web.Integration.RestApiAdapter.RestApiAdapterConfiguration
------Activating SomeProject.Web.Integration.RestApiAdapter.RestApiAdapterConfiguration
------Resolving SomeProject.Web.Integration.RestApiAdapter.Client.Authentication.ApiClientAuthenticationService
--------Resolving SomeProject.Web.Integration.RestApiAdapter.RestApiAdapterConfiguration
--------Activating SomeProject.Web.Integration.RestApiAdapter.RestApiAdapterConfiguration
------Activating SomeProject.Web.Integration.RestApiAdapter.Client.Authentication.ApiClientAuthenticationService
Puede agregar el registro de solicitudes al contenedor al registrar un módulo especial que detectará el evento Preparing
para todos los registros:
public class LogRequestsModule : Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry,
IComponentRegistration registration)
{
// Use the event args to log detailed info
registration.Preparing += (sender, args) =>
Console.WriteLine(
"Resolving concrete type {0}",
args.Component.Activator.LimitType);
}
}
Esta es la forma más sencilla de ir y probablemente obtendrá lo que desea. Justo después de que un evento de Preparing
registre la información, verá la excepción emergente y sabrá qué componente estaba lanzando.
Si desea obtener más sofisticado, puede configurar algunos controladores de eventos en los ChildLifetimeScopeBeginning
contenedor ChildLifetimeScopeBeginning
, ResolveOperationBeginning
, ResolveOperationEnding
y CurrentScopeEnding
.
- Durante
ChildLifetimeScopeBeginning
, necesitaría configurar algo para adjuntarlo automáticamente a cualquier eventoResolveOperationBeginning
vida. - Durante
ResolveOperationBeginning
, registraría lo que se va a resolver. - Durante
ResolveOperationEnding
, registrarías las excepciones que salen. - Durante
CurrentScopeEnding
, deberá cancelar la suscripción de cualquier evento en ese ámbito para que el recolector de basura pueda limpiar el alcance de por vida con todas sus instancias.
El proyecto del perfilador de Whitebox tiene un módulo que implementa parte de este registro más avanzado, pero no está configurado para el último Autofac, por lo que tendría que usarlo como punto de partida, no como una muestra de cortar / pegar.
Una vez más, la solución más fácil es ese módulo que publiqué arriba.