如何将 function.json 添加到现有的 .NET 函数 2.0
How to add function.json to existing .NET function 2.0
当我使用 func new --name MyHttpTrigger --template "HttpTrigger"
添加新函数时,此函数中没有创建 function.json
,当我尝试将其添加到当前目录时 运行 func start --build
,我得到这个错误:
未找到工作职能。尝试让你的工作 类 和方法 public。如果您正在使用绑定扩展(例如 Azure 存储、ServiceBus、计时器等),请确保您已在启动代码中调用扩展的注册方法(例如 builder.AddAzureStorage()、builder.AddServiceBus(), builder.AddTimers(), 等等).
你可以在这里找到我的 function.json
内容 :
{
"disabled": false,
"bindings": [
{
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in"
},
{
"name": "res",
"type": "http",
"direction": "out"
}
]
}
之前的 httpTrigger 函数
namespace final
{
public static class httpTrigger
{
[FunctionName("httpTrigger")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
}
新的 httpTrigger 功能
namespace final
{
public static class httpTrigger
{
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
}
简答
构建过程负责根据您附加到方法的属性为您在 .cs 文件中定义的函数生成 function.json
文件。函数文档中有几个示例,例如。 a BlobTrigger function in C#. 您不需要添加自己的 function.json
。
请参阅长答案部分,详细了解幕后工作原理。如果您看到为已编译的 C# 函数描述的所有预期构建输出,并且函数运行时仍未找到任何函数,请检查您是否在函数的顶级目录中 运行 func start --build
应用结构。
长答案
您描述的行为是设计使然。听起来您已经习惯了脚本语言使用的 Functions 文件夹结构,例如 .csx(C# 脚本)文件。这是一个定义两个函数的示例,MyFunction
和 MySecondFunction
:
FunctionApp
| - bin
| - MyFunction
| | - function.json
| | - run.csx
| - MySecondFunction
| | - function.json
| | - run.csx
| ...
| host.json
| local.settings.json
原来Functions运行时只能识别这个文件夹结构,C#函数只能用C#脚本编写。 (original blog announcement | MSDN magazine article) 后来,添加了常规 C# 支持。我将常规 C# 称为 编译 C# 以强调它与 C# 脚本之间的区别。
与已编译的 C# 函数应用相同的示例具有如下文件夹结构:
FunctionApp
| - bin
| - obj
| - host.json
| - local.settings.json
| - FunctionApp.csproj
| - MyFunction.cs
| - MySecondFunction.cs
如果您构建此项目并展开 FunctionApp/bin
文件夹,您将看到如下内容:
FunctionApp
| - bin
| | - Debug
| | | - net461
| | | | - bin
| | | | - MyFunction
| | | | | - function.json
| | | | - MySecondFunction
| | | | | - function.json
| | | - host.json
| | | - local.settings.json
| | | - netstandard2.0
| | | | - …
| - obj
| - host.json
| - local.settings.json
| - FunctionApp.csproj
| - MyFunction.cs
| - MySecondFunction.cs
(netstandard2.0
文件夹将包含与 net461
文件夹相似的内容;它们只是不同的框架构建目标。)
请注意 FunctionApp/bin/Debug/net461 in the compiled C# function app's folder structure and
FunctionAppin the C# script app's folder structure. This is because the build process for C# (not C# script) function apps uses the attributes of the methods in the .cs files (ex.
HttpTrigger`) 之间的相似性以确定定义了哪些函数并创建原始文件夹结构作为其构建输出。
当 Azure Functions 运行时启动时(例如 func host start
),它不会查看 FunctionApp
来确定存在哪些函数并连接绑定。它查看 FunctionApp/bin/Debug/net461/MyFunction
.
唯一的区别在于每个函数的文件夹。在编译的C#函数应用中,每个函数的文件夹都缺少C#脚本函数应用中的.csx文件。仔细查看已编译的 C# 函数应用程序的 FunctionApp/bin/Debug/net461/MyFunction
文件夹中的 function.json
,您会看到类似这样的内容:
{
"generatedBy": "Microsoft.NET.Sdk.Functions-1.0.13",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"methods": [
"post"
],
"authLevel": "function",
"name": "req"
}
],
"disabled": false,
"scriptFile": "../bin/VSSample.dll",
"entryPoint": "VSSample.HttpStart.Run"
}
与为 C# 脚本函数创建的 function.json
相比,编译后的 C# 函数的 function.json
多了一些字段。这是每个函数运行时指示的内容:
generatedBy
:这个function.json
是编译时生成的,不是手写的
configurationSource
:这个function.json
是从C#属性生成的
scriptFile
:包含此函数对应的编译代码的DLL的位置,相对于此function.json
文件的位置
entryPoint
: 已编译 DLL 中函数的方法签名
长话短说,已编译的 C# 函数应用在运行时依赖于与 C# 脚本函数应用相同的文件夹结构,但它是由构建过程生成的,而不是由开发人员构建的。在编译的 C# 中编写函数应用程序的开发人员通过 C# 属性定义其绑定,将 function.json
生成留给构建过程。
当我使用 func new --name MyHttpTrigger --template "HttpTrigger"
添加新函数时,此函数中没有创建 function.json
,当我尝试将其添加到当前目录时 运行 func start --build
,我得到这个错误:
未找到工作职能。尝试让你的工作 类 和方法 public。如果您正在使用绑定扩展(例如 Azure 存储、ServiceBus、计时器等),请确保您已在启动代码中调用扩展的注册方法(例如 builder.AddAzureStorage()、builder.AddServiceBus(), builder.AddTimers(), 等等).
你可以在这里找到我的 function.json
内容 :
{
"disabled": false,
"bindings": [
{
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in"
},
{
"name": "res",
"type": "http",
"direction": "out"
}
]
}
之前的 httpTrigger 函数
namespace final
{
public static class httpTrigger
{
[FunctionName("httpTrigger")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
}
新的 httpTrigger 功能
namespace final
{
public static class httpTrigger
{
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
}
简答
构建过程负责根据您附加到方法的属性为您在 .cs 文件中定义的函数生成 function.json
文件。函数文档中有几个示例,例如。 a BlobTrigger function in C#. 您不需要添加自己的 function.json
。
请参阅长答案部分,详细了解幕后工作原理。如果您看到为已编译的 C# 函数描述的所有预期构建输出,并且函数运行时仍未找到任何函数,请检查您是否在函数的顶级目录中 运行 func start --build
应用结构。
长答案
您描述的行为是设计使然。听起来您已经习惯了脚本语言使用的 Functions 文件夹结构,例如 .csx(C# 脚本)文件。这是一个定义两个函数的示例,MyFunction
和 MySecondFunction
:
FunctionApp
| - bin
| - MyFunction
| | - function.json
| | - run.csx
| - MySecondFunction
| | - function.json
| | - run.csx
| ...
| host.json
| local.settings.json
原来Functions运行时只能识别这个文件夹结构,C#函数只能用C#脚本编写。 (original blog announcement | MSDN magazine article) 后来,添加了常规 C# 支持。我将常规 C# 称为 编译 C# 以强调它与 C# 脚本之间的区别。
与已编译的 C# 函数应用相同的示例具有如下文件夹结构:
FunctionApp
| - bin
| - obj
| - host.json
| - local.settings.json
| - FunctionApp.csproj
| - MyFunction.cs
| - MySecondFunction.cs
如果您构建此项目并展开 FunctionApp/bin
文件夹,您将看到如下内容:
FunctionApp
| - bin
| | - Debug
| | | - net461
| | | | - bin
| | | | - MyFunction
| | | | | - function.json
| | | | - MySecondFunction
| | | | | - function.json
| | | - host.json
| | | - local.settings.json
| | | - netstandard2.0
| | | | - …
| - obj
| - host.json
| - local.settings.json
| - FunctionApp.csproj
| - MyFunction.cs
| - MySecondFunction.cs
(netstandard2.0
文件夹将包含与 net461
文件夹相似的内容;它们只是不同的框架构建目标。)
请注意 FunctionApp/bin/Debug/net461 in the compiled C# function app's folder structure and
FunctionAppin the C# script app's folder structure. This is because the build process for C# (not C# script) function apps uses the attributes of the methods in the .cs files (ex.
HttpTrigger`) 之间的相似性以确定定义了哪些函数并创建原始文件夹结构作为其构建输出。
当 Azure Functions 运行时启动时(例如 func host start
),它不会查看 FunctionApp
来确定存在哪些函数并连接绑定。它查看 FunctionApp/bin/Debug/net461/MyFunction
.
唯一的区别在于每个函数的文件夹。在编译的C#函数应用中,每个函数的文件夹都缺少C#脚本函数应用中的.csx文件。仔细查看已编译的 C# 函数应用程序的 FunctionApp/bin/Debug/net461/MyFunction
文件夹中的 function.json
,您会看到类似这样的内容:
{
"generatedBy": "Microsoft.NET.Sdk.Functions-1.0.13",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"methods": [
"post"
],
"authLevel": "function",
"name": "req"
}
],
"disabled": false,
"scriptFile": "../bin/VSSample.dll",
"entryPoint": "VSSample.HttpStart.Run"
}
与为 C# 脚本函数创建的 function.json
相比,编译后的 C# 函数的 function.json
多了一些字段。这是每个函数运行时指示的内容:
generatedBy
:这个function.json
是编译时生成的,不是手写的configurationSource
:这个function.json
是从C#属性生成的scriptFile
:包含此函数对应的编译代码的DLL的位置,相对于此function.json
文件的位置entryPoint
: 已编译 DLL 中函数的方法签名
长话短说,已编译的 C# 函数应用在运行时依赖于与 C# 脚本函数应用相同的文件夹结构,但它是由构建过程生成的,而不是由开发人员构建的。在编译的 C# 中编写函数应用程序的开发人员通过 C# 属性定义其绑定,将 function.json
生成留给构建过程。