Skip to content

Commit

Permalink
Shimming legacy .NET worker JsonFunctionProvider to ensure backwards …
Browse files Browse the repository at this point in the history
…compatibility
  • Loading branch information
fabiocav committed Aug 21, 2024
1 parent 17bad4f commit a132223
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -497,4 +497,4 @@ local.settings.json
/tools/ExtensionsMetadataGenerator/packages
/tools/ExtensionsMetadataGenerator/src/ExtensionsMetadataGenerator/runtimeassemblies.txt
/tools/ExtensionsMetadataGenerator/test/ExtensionsMetadataGeneratorTests/runtimeAssemblies.txt
BenchmarkDotNet.Artifacts/
BenchmarkDotNet.Artifacts/
1 change: 1 addition & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
- Update grpc-protobuf to 1.64.0 and application insights agent version to 3.5.2
- Resolved thread safety issue in the `GrpcWorkerChannel.LoadResponse` method. (#10352)
- Worker termination path updated with sanitized logging (#10367)
- Added logic to shim older versions of the .NET Worker JsonFunctiopnProvider to ensure backwards compatibility (#10410)
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public IServiceProvider CreateServiceProvider(IServiceCollection services)
throw new HostInitializationException("Invalid host services detected.", ex);
}

ShimBreakingChange(services);
ShimBreakingChanges(services, _logger);

// Start from the root (web app level) as a base
var jobHostServices = _rootProvider.CreateChildContainer(_rootServices);
Expand All @@ -76,12 +76,69 @@ public IServiceProvider CreateServiceProvider(IServiceCollection services)
return jobHostServices.BuildServiceProvider();
}

private void ShimBreakingChanges(IServiceCollection services, ILogger logger)
{
ShimActivatorUtilitiesConstructorAttributeTypes(services, logger);
ShimLegacyNetWorkerMetadataProvider(services, logger);
}

/// <summary>
/// Versions 1.3.0 and older of Microsoft.Azure.Functions.Worker.Sdk register a type with a constructor that
/// takes a strign parameter. This workeed with DryIoc, but not with the new DI container.
/// Shimming those types to provide backwards compatibility, but this should be removed in the future.
/// </summary>
/// <param name="services">The <see cref="ServiceCollection"/> to inspect and modify.</param>
private static void ShimLegacyNetWorkerMetadataProvider(IServiceCollection services, ILogger logger)
{
const string functionProviderTypeName = "Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.JsonFunctionProvider, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c";
const string jsonReaderTypeName = "Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.FunctionMetadataJsonReader, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c";

Type functionProviderType = Type.GetType(functionProviderTypeName);
if (functionProviderType is null)
{
return;
}

Type jsonReaderType = Type.GetType(jsonReaderTypeName);
var constructor = functionProviderType.GetConstructor([jsonReaderType, typeof(string)]);
if (constructor is null)
{
return;
}

ServiceDescriptor descriptorToShim = null;
foreach (ServiceDescriptor descriptor in services)
{
if (descriptor.ImplementationType == functionProviderType)
{
logger.LogInformation("Shimming .NET Worker Function Provider constructor for {ImplementationType}.", descriptor.ImplementationType);
descriptorToShim = descriptor;
break;
}
}

if (descriptorToShim is not null)
{
var newDescriptor = ServiceDescriptor.Describe(
descriptorToShim.ServiceType,
sp =>
{
var jsonReader = sp.GetRequiredService(jsonReaderType);
return constructor.Invoke([jsonReader, null]);
},
descriptorToShim.Lifetime);

services.Remove(descriptorToShim);
services.Add(newDescriptor);
}
}

/// <summary>
/// .NET 8 has a breaking change regarding <see cref="ActivatorUtilitiesConstructorAttribute"/> no longer functioning as expected.
/// We have some known extension types which are impacted by this. To avoid a regression, we are manually shimming those types.
/// </summary>
/// <param name="services">The service collection.</param>
private void ShimBreakingChange(IServiceCollection services)
private static void ShimActivatorUtilitiesConstructorAttributeTypes(IServiceCollection services, ILogger logger)
{
Dictionary<ServiceDescriptor, ServiceDescriptor> toReplace = null;
static bool HasPreferredCtor(Type type)
Expand All @@ -105,7 +162,7 @@ bool TryCreateReplacement(ServiceDescriptor descriptor, out ServiceDescriptor re
return false;
}

_logger.LogInformation("Shimming DI constructor for {ImplementationType}.", descriptor.ImplementationType);
logger.LogInformation("Shimming DI constructor for {ImplementationType}.", descriptor.ImplementationType);
ObjectFactory factory = ActivatorUtilities.CreateFactory(descriptor.ImplementationType, Type.EmptyTypes);

replacement = ServiceDescriptor.Describe(
Expand Down

0 comments on commit a132223

Please sign in to comment.