Skip to content

Commit

Permalink
initial fix of duplicate registrations if AddFunctionsWorkerCore call…
Browse files Browse the repository at this point in the history
…ed twice (#2790)
  • Loading branch information
brettsam authored Oct 21, 2024
1 parent 04e8bd1 commit 96db64d
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 14 deletions.
23 changes: 23 additions & 0 deletions src/DotNetWorker.Core/Hosting/DefaultInputConverterInitializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Azure.Functions.Worker.Converters;
using Microsoft.Extensions.Options;

namespace Microsoft.Azure.Functions.Worker.Core;

internal class DefaultInputConverterInitializer : IConfigureOptions<WorkerOptions>
{
public void Configure(WorkerOptions options)
{
options.InputConverters.Register<FunctionContextConverter>();
options.InputConverters.Register<TypeConverter>();
options.InputConverters.Register<GuidConverter>();
options.InputConverters.Register<DateTimeConverter>();
options.InputConverters.Register<MemoryConverter>();
options.InputConverters.Register<StringToByteConverter>();
options.InputConverters.Register<JsonPocoConverter>();
options.InputConverters.Register<ArrayConverter>();
options.InputConverters.Register<CancellationTokenConverter>();
}
}
16 changes: 3 additions & 13 deletions src/DotNetWorker.Core/Hosting/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static IFunctionsWorkerApplicationBuilder AddFunctionsWorkerCore(this ISe
}
});

services.AddSingleton<ILoggerProvider, WorkerLoggerProvider>();
services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, WorkerLoggerProvider>());
services.AddSingleton(NullLogWriter.Instance);
services.AddSingleton<IUserLogWriter>(s => s.GetRequiredService<NullLogWriter>());
services.AddSingleton<ISystemLogWriter>(s => s.GetRequiredService<NullLogWriter>());
Expand Down Expand Up @@ -123,18 +123,8 @@ public static IFunctionsWorkerApplicationBuilder AddFunctionsWorkerCore(this ISe
/// </summary>
internal static IServiceCollection AddDefaultInputConvertersToWorkerOptions(this IServiceCollection services)
{
return services.Configure<WorkerOptions>((workerOption) =>
{
workerOption.InputConverters.Register<FunctionContextConverter>();
workerOption.InputConverters.Register<TypeConverter>();
workerOption.InputConverters.Register<GuidConverter>();
workerOption.InputConverters.Register<DateTimeConverter>();
workerOption.InputConverters.Register<MemoryConverter>();
workerOption.InputConverters.Register<StringToByteConverter>();
workerOption.InputConverters.Register<JsonPocoConverter>();
workerOption.InputConverters.Register<ArrayConverter>();
workerOption.InputConverters.Register<CancellationTokenConverter>();
});
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<WorkerOptions>, DefaultInputConverterInitializer>());
return services;
}

/// <summary>
Expand Down
49 changes: 48 additions & 1 deletion test/DotNetWorkerTests/ServiceCollectionExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using Microsoft.Azure.Functions.Worker.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Xunit;

Expand All @@ -26,5 +29,49 @@ public void ConfigureOptions_IsCalled()

Assert.True(configured);
}

[Fact]
public void DefaultInputConverters_RegisteredOnce()
{
var serviceColl = new ServiceCollection();
serviceColl.AddFunctionsWorkerDefaults();
serviceColl.AddFunctionsWorkerDefaults();

var services = serviceColl.BuildServiceProvider();

// request the worker options, which forces their configuration to be called.
var workerOptions = services.GetService<IOptions<WorkerOptions>>().Value;

// Ensure that even though we've called the registration twice, only one
// set of default input converters is registered.
var count = workerOptions.InputConverters.Count();
Assert.Equal(9, count);
}

[Fact]
public void LoggerProvider_RegisteredOnce()
{
var serviceColl = new ServiceCollection();
serviceColl.AddFunctionsWorkerDefaults();
serviceColl.AddFunctionsWorkerDefaults();

var services = serviceColl.BuildServiceProvider();

var loggerProviders = services.GetServices<ILoggerProvider>();

// Ensure that even though we've called the registration twice, only one
// WorkerLoggerProvider is registered.
Assert.Single(loggerProviders.Where(p => p is WorkerLoggerProvider));
}

[Fact]
public void SameBuilder_Returned()
{
var serviceColl = new ServiceCollection();
var builder1 = serviceColl.AddFunctionsWorkerCore();
var builder2 = serviceColl.AddFunctionsWorkerCore();

Assert.Same(builder1, builder2);
}
}
}

0 comments on commit 96db64d

Please sign in to comment.