1

DryIOC has a VerifyResolutions method. Microsoft Azure Functions DI uses DryIOC, but does not appear to expose any similar method.

The reason I need to know is that I am getting a System.NulLReferenceException at lambda_method when trying to get a registered service in Azure functions.

Googling this error suggests, something ...somewhere has a malformed registration. In earlier versions of Azure functions some of the errors were Microsoft registration errors. Internally Azure Functions is currently using DryIoc which you can see in the error (stacktrace) I am getting. (see below).

My question is, ... Is there any equivalent way to verify registrations and get a helpful error message to tell you what is incorrectly configured? (i.e. access either the internal DryIOC.Scope.Container and call VerifyResolutions()` or any other way to get a detailed error report? Currently the error message we get from Microsoft and absolutely useless. Null Reference exception, ...like a bad movie scene in a 1990's hacker movie and we're all yelling, that's rubbish, no decent developer WOULD EVER throw an error message like that!

Anyway...don't get me started.

Below is the ...wonderful...(sic) ...error message we currently get from Microsoft's wrapper around the excellent DryIOC.

System.NullReferenceException: Object reference not set to an instance of an object.
   at lambda_method(Closure )
   at DryIoc.Scope.TryGetOrAdd(ImMap`1 items, Int32 id, CreateScopedValue createValue, Int32 disposalOrder) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7849
   at DryIoc.Scope.GetOrAdd(Int32 id, CreateScopedValue createValue, Int32 disposalOrder) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7834
   at lambda_method(Closure )
   at DryIoc.Scope.TryGetOrAdd(ImMap`1 items, Int32 id, CreateScopedValue createValue, Int32 disposalOrder) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7849
   at DryIoc.Scope.GetOrAdd(Int32 id, CreateScopedValue createValue, Int32 disposalOrder) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7834
   at lambda_method(Closure )
   at DryIoc.Scope.TryGetOrAdd(ImMap`1 items, Int32 id, CreateScopedValue createValue, Int32 disposalOrder) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7849
   at DryIoc.Scope.GetOrAdd(Int32 id, CreateScopedValue createValue, Int32 disposalOrder) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 7834
   at DryIoc.Container.ResolveAndCacheDefaultFactoryDelegate(Type serviceType, IfUnresolved ifUnresolved) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 225
   at DryIoc.Container.DryIoc.IResolver.Resolve(Type serviceType, IfUnresolved ifUnresolved) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.cs:line 196
   at Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection.ScopedServiceProvider.GetService(Type serviceType) in D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\ScopedServiceProvider.cs:line 25
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
   at lambda_method(Closure , IServiceProvider , Object[] )
   at Microsoft.Azure.WebJobs.Host.Executors.DefaultJobActivator.CreateInstance[T](IServiceProvider serviceProvider) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\DefaultJobActivator.cs:line 37
   at Microsoft.Azure.WebJobs.Host.Executors.DefaultJobActivator.CreateInstance[T](IFunctionInstanceEx functionInstance) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\DefaultJobActivator.cs:line 32
   at Microsoft.Azure.WebJobs.Host.Executors.ActivatorInstanceFactory`1.<>c__DisplayClass1_1.<.ctor>b__0(IFunctionInstanceEx i) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\ActivatorInstanceFactory.cs:line 20
   at Microsoft.Azure.WebJobs.Host.Executors.ActivatorInstanceFactory`1.Create(IFunctionInstanceEx functionInstance) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\ActivatorInstanceFactory.cs:line 26
   at Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`2.CreateInstance(IFunctionInstanceEx functionInstance) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionInvoker.cs:line 44
   at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ParameterHelper.Initialize() in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 794
   at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.TryExecuteAsyncCore(IFunctionInstanceEx functionInstanceEx, CancellationToken cancellationToken, ILogger logger) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 96
[2021-01-05T08:32:25.312Z] An unhandled host error has occurred.
[2021-01-05T08:32:25.317Z] Anonymously Hosted DynamicMethods Assembly: Object reference not set to an instance of an object.

TLDR;

Is there any equivalent way to verify registrations and get a helpful error message to tell you what is incorrectly configured with Microsoft IOC? IServiceCollection (i.e. access either the internal DryIOC.Scope.Container and call VerifyResolutions()` or any other way to get a detailed error report?

snowcode
  • 1,033
  • 10
  • 24

2 Answers2

2

From the StackTrace, it can be seen that DryIOC is trying to Get or Add your Service.

  • Check if you are using correct syntax for DI in Azure Functions Startup class.
  • Check if your target service's constructor does not have null reference error - debug it by putting breakpoints and hovering over the variables to check their values.
  • After addition of Services through DI is done, check value of FunctionsHostBuilder.Services - it should have services mapped correctly.
Harshita Singh
  • 4,590
  • 1
  • 10
  • 13
  • I agree with @singhh-msft that you've probably had the null reference in the constructor of one of the scoped services. You may call the `Validate(type)` on the specific root service type, but I am not personally worked with the Azure Functions myself - so I am not sure where you should call it. – dadhi Jan 05 '21 at 13:51
  • this is great and valuable information, hence why I've upvoted the answer, but it's not what I'm actually after. I need something like VeryResolutions() which will most of the time laser in on the exact problem, first time, every time. (mostly) grin. I suspect that I may be able to hack this with some awfully nasty reflection, and that will be ok, because if the service bootstrap fails, it's dead anyway, can't make it any deader. A helpful error message is gold. – snowcode Jan 05 '21 at 17:50
  • Your point about debugging the constructor is a manual process. That's kind of what DryIoc does auto-magically for you. So what I'm looking for, is a way to programmatically do this, so that me, (a human) does not have to do what a computer can do automatically. #shiftLeft p.s. I'm just trying to be humerouse, that's not me being sarcastic, I really do appreciate all feedback I can get here, even if it does mean a bit of manual steps, because I have a strange feeling that might be all I can do. I can imagine it's locked down tighter than a {bleep} in a {bleep}. – snowcode Jan 05 '21 at 17:55
  • Great, I don't think you will be able to get more information apart from this as DryIOC is internally used and we cannot do anything about it. Further, I will pass on this feedback to the my team. Happy Coding! – Harshita Singh Jan 05 '21 at 18:42
  • Does this answer help you? – Harshita Singh Jan 08 '21 at 07:47
2

I managed to get the validation I was after. I don't know if this is a proper way to do this, if anyone thinks there's a better way, please drop a comment, or another answer here, I'll happily accept something else as the correct answer.

so, this is what worked for me in the end;

 // example registration
services.AddScoped<IAdminService, AdminService>();
services.AddScoped<IUserService, UserService>();
services.AddScoped<ISpikeController, SpikeController>();

// this code in Startup now gives me advance checking and detailed description of the exact error
#if DEBUG
var provider = services.BuildServiceProvider();
using (var scope = provider.CreateScope())
{
    scope.ServiceProvider.GetServices<ISpikeController>();
}
#endif

with the above code in place, when I start my azure function, I now get this detailed error message, exactly what I need to go straight to the problem and fix, no debugging, no hovering;

Azure Functions Core Tools
Core Tools Version:       3.0.3160 Commit hash: 00aa7f43cc5c5f15241b5e6e5363256f19ceb990
Function Runtime Version: 3.0.14916.0

[2021-01-05T19:16:22.326Z] A host error has occurred during startup operation 'd5d86642-e75d-4a29-b2a0-ab8fe4adfa56'.
[2021-01-05T19:16:22.329Z] Microsoft.Extensions.DependencyInjection: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'Mattstack.ServicePipeline'.
Value cannot be null. (Parameter 'provider')
Press any to continue....

perfect! * almost *

Update: (a little bit later) my final code now looks like this; (This is the simplest and hackiest solution that works for me. Read the comment below to see why I needed to do this (grin!)

//// uncomment to debug a configuration error
// var provider = services.BuildServiceProvider();
// using (var scope = provider.CreateScope())
// {   
//     scope.ServiceProvider.GetServices<ISpikeController>();
// }
snowcode
  • 1,033
  • 10
  • 24
  • 1
    Update: ok, so that works really well to identify the exact dependancy configuration error, except that when you've finally fixed all the errors, this trick will blow up one last time with a false negative exception, 'unable to resolve service for type Microsoft.Azure.WebJobs.Script.IFileLoggingStatusManager` if any of the services you are testing uses Ilogger. see this for detailed description (I am checking to see if I can find a simple hack/fix) https://stackoverflow.com/questions/54900982/weird-exception-when-trying-to-use-dependency-injection-in-an-azure-function – snowcode Jan 05 '21 at 19:57