diff --git a/host/src/FunctionsNetHost/Grpc/Exceptions/EnvironmentReloadNotSupportedException.cs b/host/src/FunctionsNetHost/Grpc/Exceptions/EnvironmentReloadNotSupportedException.cs
new file mode 100644
index 000000000..a0996236e
--- /dev/null
+++ b/host/src/FunctionsNetHost/Grpc/Exceptions/EnvironmentReloadNotSupportedException.cs
@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// The exception that is thrown when the current function app payload does not support environment reload.
+ ///
+ public sealed class EnvironmentReloadNotSupportedException : NotSupportedException
+ {
+ public EnvironmentReloadNotSupportedException() { }
+
+ public EnvironmentReloadNotSupportedException(string message) : base(message) { }
+ }
+}
diff --git a/host/src/FunctionsNetHost/Grpc/Exceptions/FunctionAppPayloadNotFoundException.cs b/host/src/FunctionsNetHost/Grpc/Exceptions/FunctionAppPayloadNotFoundException.cs
new file mode 100644
index 000000000..97bfac80a
--- /dev/null
+++ b/host/src/FunctionsNetHost/Grpc/Exceptions/FunctionAppPayloadNotFoundException.cs
@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// The exception that is thrown when there is no function app payload found.
+ ///
+ public sealed class FunctionAppPayloadNotFoundException : Exception
+ {
+ public FunctionAppPayloadNotFoundException() { }
+
+ public FunctionAppPayloadNotFoundException(string message) : base(message) { }
+ }
+}
diff --git a/host/src/FunctionsNetHost/Grpc/IncomingGrpcMessageHandler.cs b/host/src/FunctionsNetHost/Grpc/IncomingGrpcMessageHandler.cs
index bac4f5f42..af0a5c43f 100644
--- a/host/src/FunctionsNetHost/Grpc/IncomingGrpcMessageHandler.cs
+++ b/host/src/FunctionsNetHost/Grpc/IncomingGrpcMessageHandler.cs
@@ -1,6 +1,7 @@
// 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;
using Microsoft.Azure.Functions.Worker.Grpc.Messages;
namespace FunctionsNetHost.Grpc
@@ -50,16 +51,26 @@ private async Task Process(StreamingMessage msg)
Logger.LogTrace("Specialization request received.");
var envReloadRequest = msg.FunctionEnvironmentReloadRequest;
- var applicationExePath = PathUtils.GetApplicationExePath(envReloadRequest.FunctionAppDirectory);
- Logger.LogTrace($"application path {applicationExePath}");
- if (string.IsNullOrWhiteSpace(applicationExePath))
+ var workerConfig = await WorkerConfigUtils.GetWorkerConfig(envReloadRequest.FunctionAppDirectory);
+
+ if (workerConfig?.Description is null)
+ {
+ responseMessage.FunctionEnvironmentReloadResponse = BuildFailedEnvironmentReloadResponse(new FunctionAppPayloadNotFoundException());
+ break;
+ }
+
+ // function app payload which uses an older version of Microsoft.Azure.Functions.Worker package does not support specialization.
+ if (!workerConfig.Description.CanUsePlaceholder)
{
- var ex = new InvalidOperationException($"Unable to find a valid function app payload at '{envReloadRequest.FunctionAppDirectory}'");
- responseMessage.FunctionEnvironmentReloadResponse = BuildFailedEnvironmentReloadResponse(ex);
+ Logger.LogTrace("App payload uses an older version of worker package which does not support specialization.");
+ responseMessage.FunctionEnvironmentReloadResponse = BuildFailedEnvironmentReloadResponse(new EnvironmentReloadNotSupportedException());
break;
}
+ var applicationExePath = Path.Combine(envReloadRequest.FunctionAppDirectory, workerConfig.Description.DefaultWorkerPath!);
+ Logger.LogTrace($"application path {applicationExePath}");
+
foreach (var kv in envReloadRequest.EnvironmentVariables)
{
EnvironmentUtils.SetValue(kv.Key, kv.Value);
diff --git a/host/src/FunctionsNetHost/Grpc/PathUtils.cs b/host/src/FunctionsNetHost/Grpc/PathUtils.cs
deleted file mode 100644
index 839d79d0d..000000000
--- a/host/src/FunctionsNetHost/Grpc/PathUtils.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the MIT License. See License.txt in the project root for license information.
-
-using System.Text.Json;
-using System.Text.Json.Nodes;
-
-namespace FunctionsNetHost.Grpc
-{
- internal static class PathUtils
- {
- ///
- /// Gets the absolute path to worker application executable.
- /// Builds the path by reading the worker.config.json
- ///
- /// The FunctionAppDirectory value from environment reload request.
- internal static string? GetApplicationExePath(string applicationDirectory)
- {
- string jsonString = string.Empty;
- string workerConfigPath = string.Empty;
- try
- {
- workerConfigPath = Path.Combine(applicationDirectory, "worker.config.json");
-
- jsonString = File.ReadAllText(workerConfigPath);
- var workerConfigJsonNode = JsonNode.Parse(jsonString)!;
- var executableName = workerConfigJsonNode["description"]?["defaultWorkerPath"]?.ToString();
-
- if (executableName == null)
- {
- Logger.Log($"Invalid worker configuration. description > defaultWorkerPath property value is null. jsonString:{jsonString}");
- return null;
- }
-
- return Path.Combine(applicationDirectory, executableName);
- }
- catch (FileNotFoundException ex)
- {
- Logger.Log($"{workerConfigPath} file not found.{ex}");
- return null;
- }
- catch (JsonException ex)
- {
- Logger.Log($"Error parsing JSON in GetApplicationExePath.{ex}. jsonString:{jsonString}");
- return null;
- }
- catch (Exception ex)
- {
- Logger.Log($"Error in GetApplicationExePath.{ex}. jsonString:{jsonString}");
- return null;
- }
- }
- }
-}
diff --git a/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfig.cs b/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfig.cs
new file mode 100644
index 000000000..b15b46e3f
--- /dev/null
+++ b/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfig.cs
@@ -0,0 +1,13 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+namespace FunctionsNetHost.Grpc
+{
+ ///
+ /// Represents a worker configuration instance.
+ ///
+ public sealed class WorkerConfig
+ {
+ public WorkerDescription? Description { set; get; }
+ }
+}
diff --git a/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfigSerializerContext.cs b/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfigSerializerContext.cs
new file mode 100644
index 000000000..d37bcd11e
--- /dev/null
+++ b/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfigSerializerContext.cs
@@ -0,0 +1,11 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System.Text.Json.Serialization;
+
+namespace FunctionsNetHost.Grpc
+{
+ [JsonSerializable(typeof(WorkerConfig))]
+ [JsonSourceGenerationOptions(IncludeFields = true, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
+ internal partial class WorkerConfigSerializerContext : JsonSerializerContext { }
+}
diff --git a/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfigUtils.cs b/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfigUtils.cs
new file mode 100644
index 000000000..98c430718
--- /dev/null
+++ b/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfigUtils.cs
@@ -0,0 +1,39 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System.Text.Json;
+
+namespace FunctionsNetHost.Grpc
+{
+ internal static class WorkerConfigUtils
+ {
+ ///
+ /// Builds and returns an instance of from the worker.config.json file if present in the application directory.
+ ///
+ /// The directory where function app deployed payload is present.
+ internal static async Task GetWorkerConfig(string applicationDirectory)
+ {
+ string workerConfigPath = string.Empty;
+
+ try
+ {
+ workerConfigPath = Path.Combine(applicationDirectory, "worker.config.json");
+
+ using Stream stream = File.OpenRead(workerConfigPath);
+ var workerConfig = await JsonSerializer.DeserializeAsync(stream, WorkerConfigSerializerContext.Default.WorkerConfig);
+
+ return workerConfig;
+ }
+ catch (FileNotFoundException)
+ {
+ Logger.Log($"worker.config.json not found at {workerConfigPath}. This may indicate missing app payload.");
+ return null;
+ }
+ catch (Exception ex)
+ {
+ Logger.Log($"Error in WorkerConfigUtils.GetWorkerConfig.{ex}");
+ return null;
+ }
+ }
+ }
+}
diff --git a/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerDescription.cs b/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerDescription.cs
new file mode 100644
index 000000000..5ad21dd0a
--- /dev/null
+++ b/host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerDescription.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+namespace FunctionsNetHost.Grpc
+{
+ public sealed class WorkerDescription
+ {
+ public string? DefaultWorkerPath { set; get; }
+
+ public bool CanUsePlaceholder { set; get; }
+ }
+}
diff --git a/host/src/FunctionsNetHost/global.json b/host/src/FunctionsNetHost/global.json
index f735d6ed6..27928313f 100644
--- a/host/src/FunctionsNetHost/global.json
+++ b/host/src/FunctionsNetHost/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.100-rc.1.23455.8",
+ "version": "8.0.100-rc.2.23502.2",
"allowPrerelease": true,
"rollForward": "latestMinor"
}
diff --git a/host/tools/build/Microsoft.Azure.Functions.DotnetIsolatedNativeHost.nuspec b/host/tools/build/Microsoft.Azure.Functions.DotnetIsolatedNativeHost.nuspec
index c2ab2b44b..36c3591a6 100644
--- a/host/tools/build/Microsoft.Azure.Functions.DotnetIsolatedNativeHost.nuspec
+++ b/host/tools/build/Microsoft.Azure.Functions.DotnetIsolatedNativeHost.nuspec
@@ -4,7 +4,7 @@
Microsoft.Azure.Functions.DotNetIsolatedNativeHost
Microsoft Azure Functions dotnet-isolated native host
dotnet-isolated azure-functions azure
- 1.0.0
+ 1.0.1
Microsoft
Microsoft
https://github.com/Azure/azure-functions-dotnet-worker