Skip to content

Commit 79e6068

Browse files
authored
Shimming legacy .NET worker JsonFunctionProvider to ensure backwards compatibility (#10411)
1 parent 51dc962 commit 79e6068

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

release_notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
- Update grpc-protobuf to 1.64.0 and application insights agent version to 3.5.2
1818
- Resolved thread safety issue in the `GrpcWorkerChannel.LoadResponse` method. (#10352)
1919
- Worker termination path updated with sanitized logging (#10367)
20+
- Added logic to shim older versions of the .NET Worker JsonFunctionProvider to ensure backwards compatibility (#10410)

src/WebJobs.Script.WebHost/DependencyInjection/JobHostScopedServiceProviderFactory.cs

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public IServiceProvider CreateServiceProvider(IServiceCollection services)
6262
throw new HostInitializationException("Invalid host services detected.", ex);
6363
}
6464

65-
ShimBreakingChange(services);
65+
ShimBreakingChanges(services, _logger);
6666

6767
// Start from the root (web app level) as a base
6868
var jobHostServices = _rootProvider.CreateChildContainer(_rootServices);
@@ -76,12 +76,71 @@ public IServiceProvider CreateServiceProvider(IServiceCollection services)
7676
return jobHostServices.BuildServiceProvider();
7777
}
7878

79+
private static void ShimBreakingChanges(IServiceCollection services, ILogger logger)
80+
{
81+
ShimActivatorUtilitiesConstructorAttributeTypes(services, logger);
82+
ShimLegacyNetWorkerMetadataProvider(services, logger);
83+
}
84+
85+
/// <summary>
86+
/// Versions 1.3.0 and older of Microsoft.Azure.Functions.Worker.Sdk register a type with a constructor that
87+
/// takes a string parameter. This worked with DryIoc, but not with the new DI container.
88+
/// Shimming those types to provide backwards compatibility, but this should be removed in the future.
89+
/// </summary>
90+
/// <param name="services">The <see cref="ServiceCollection"/> to inspect and modify.</param>
91+
/// <param name="logger">The <see cref="ILogger"/> to log information.</param>
92+
private static void ShimLegacyNetWorkerMetadataProvider(IServiceCollection services, ILogger logger)
93+
{
94+
const string functionProviderTypeName = "Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.JsonFunctionProvider, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c";
95+
const string jsonReaderTypeName = "Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.FunctionMetadataJsonReader, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c";
96+
97+
Type functionProviderType = Type.GetType(functionProviderTypeName);
98+
if (functionProviderType is null)
99+
{
100+
return;
101+
}
102+
103+
Type jsonReaderType = Type.GetType(jsonReaderTypeName);
104+
var constructor = functionProviderType.GetConstructor([jsonReaderType, typeof(string)]);
105+
if (constructor is null)
106+
{
107+
return;
108+
}
109+
110+
ServiceDescriptor descriptorToShim = null;
111+
foreach (ServiceDescriptor descriptor in services)
112+
{
113+
if (descriptor.ImplementationType == functionProviderType)
114+
{
115+
logger.LogInformation("Shimming .NET Worker Function Provider constructor for {ImplementationType}.", descriptor.ImplementationType);
116+
descriptorToShim = descriptor;
117+
break;
118+
}
119+
}
120+
121+
if (descriptorToShim is not null)
122+
{
123+
var newDescriptor = ServiceDescriptor.Describe(
124+
descriptorToShim.ServiceType,
125+
sp =>
126+
{
127+
var jsonReader = sp.GetRequiredService(jsonReaderType);
128+
return constructor.Invoke([jsonReader, null]);
129+
},
130+
descriptorToShim.Lifetime);
131+
132+
services.Remove(descriptorToShim);
133+
services.Add(newDescriptor);
134+
}
135+
}
136+
79137
/// <summary>
80138
/// .NET 8 has a breaking change regarding <see cref="ActivatorUtilitiesConstructorAttribute"/> no longer functioning as expected.
81139
/// We have some known extension types which are impacted by this. To avoid a regression, we are manually shimming those types.
82140
/// </summary>
83141
/// <param name="services">The service collection.</param>
84-
private void ShimBreakingChange(IServiceCollection services)
142+
/// <param name="logger">The <see cref="ILogger"/> to log information.</param>
143+
private static void ShimActivatorUtilitiesConstructorAttributeTypes(IServiceCollection services, ILogger logger)
85144
{
86145
Dictionary<ServiceDescriptor, ServiceDescriptor> toReplace = null;
87146
static bool HasPreferredCtor(Type type)
@@ -105,7 +164,7 @@ bool TryCreateReplacement(ServiceDescriptor descriptor, out ServiceDescriptor re
105164
return false;
106165
}
107166

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

111170
replacement = ServiceDescriptor.Describe(

0 commit comments

Comments
 (0)