I am trying to debug some problems in a legacy code base. I think is being caused by an exception being thrown because something can't be resolved from the Autofac container. However I think the exception is getting buried somewhere and I am not seeing the root cause. I am sure something is being requested from a controller that either can't be found or something that can be found has a dependency that can't be satisfied. There aren't any guard clauses etc. so I think I am getting a null reference issue. To try and debug this I want to see all requests that aren't found in the container.
Is there anyway to log all requests that Autofac couldn't resolve? Or alternatively just log all requests to the container?
From Visual Studio, you can get it via NuGet. The package name is Autofac. Alternatively, the NuGet package can be downloaded from the GitHub repository (https://github.com/autofac/Autofac/releases).
You can read more about this in the section on controlling scope and lifetime. When resolving a service, Autofac will automatically chain down the entire dependency hierarchy of the service and resolve any dependencies required to fully construct the service.
Autofac can automatically dispose of some components, but you have the ability to manually specify a disposal mechanism, too.
You can add logging for requests to the container by registering a special module that will catch the Preparing
event for all registrations:
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); } }
This is the simplest way to go and will probably get you what you want. Right after a Preparing
event logs the information, you'll see the exception pop up and you'll know which component was throwing.
If you want to get fancier, you can set up some event handlers on the container ChildLifetimeScopeBeginning
, ResolveOperationBeginning
, ResolveOperationEnding
, and CurrentScopeEnding
events.
ChildLifetimeScopeBeginning
you'd need to set up something to automatically attach to any child lifetime ResolveOperationBeginning
events.ResolveOperationBeginning
you'd log what is going to be resolved.ResolveOperationEnding
you'd log any exceptions coming out.CurrentScopeEnding
you'd need to unsubscribe from any events on that scope so the garbage collector can clean up the lifetime scope with all of its instances.The Whitebox profiler project has a module that implements some of this more advanced logging but it's not set up for the latest Autofac so you'd have to use it as a starting point, not a cut/paste sample.
Again, the easiest solution is that module I posted above.
Just to build on an excellent answer by Travis, in case it helps someone in future.
If your class structure is very deep, it may be easier to spot the problematic path, if you display objects in a composition hierarchy. This can be accomplished with somehting like this:
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); } } }
Sample output:
--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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With