Jonas Stensved
Jonas Stensved

Reputation: 15276

NullReferenceException when checking if index exists with Azure Search for .NET?

When trying to see if an index exists for a non-existing index with the .NET SDK (both 3.0.4 and 4.0.0-preview) the ExistsAsync (as well as Exists, and ExistsWithHttpMessagesAsync) throws the following exception.

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Azure.Search.IndexesOperations.<GetWithHttpMessagesAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Search.ExistsHelper.<ExistsFromGetResponse>d__0`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Search.IndexesOperationsExtensions.<ExistsAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at InphizCore.MiddleLayer.Services.AzureSearch.Services.AzureSearchWriter`1.<AssertIndexExists>d__8.MoveNext() in C:\xxx\AzureSearchWriter.cs:line 109

Using http rest from postman works fine and returns a message saying the index doesn't exists.

 public async Task AssertIndexExists()
        {
            try
            {
                if (await searchServiceClient.Indexes.ExistsAsync(options.Value.IndexName) == false)
                {
                    searchServiceClient.Indexes.Create(new Index(options.Value.IndexName, FieldBuilder.BuildForType<SearchableItemModel>(), corsOptions: new CorsOptions(new List<string> { "*" })));
                }
            }
            catch (Exception e)
            {
                logger.LogError($"Azure Search Index '{options.Value.IndexName}' could not be created. ({e.Message})");
                throw e;
            }
        }

How can I troubleshoot this in a meaningful way?

UPDATE:

This is how the client looks when running in a Unit Test:

enter image description here

This is how it looks from AspNetCore MVC:

enter image description here

Is seems like the Search Client fails to create instances of FirstMessageHandler, HttpClient and HttpClientHandler. Why doesn't it throw?

Upvotes: 3

Views: 764

Answers (1)

Jonas Stensved
Jonas Stensved

Reputation: 15276

Well, this is strange but possibly some inner workings of the SearchServiceClient.

This (EDIT: doesn't) work:

If I add a HttpClientHandler which I pass along to another of the constructors AND set lifetime to Singleton or Transient it works. I previously had Scoped.

 services.AddTransient<SearchServiceClient>(x =>
 {
     var httpClientHandler = new HttpClientHandler();

     var options = x.GetRequiredService<IOptions<AzureSearchOptions>>();
     var client = new SearchServiceClient(options.Value.SearchServiceName, new SearchCredentials(options.Value.AdminApiKey), httpClientHandler);
     return client;
 });

UPDATE: This works:

Behavior in solution above was unpredictable and I ended up with this method in the calling class.

When I created a new instance for each time I need a client it doesn't seem to give any errors at all:

  protected SearchServiceClient GetAzureSearchServiceClient()
        {
            return new SearchServiceClient(options.Value.SearchServiceName, new SearchCredentials(options.Value.AdminApiKey));
        }

Upvotes: 3

Related Questions