FunctionsFramework.Generator
0.3.0
dotnet add package FunctionsFramework.Generator --version 0.3.0
NuGet\Install-Package FunctionsFramework.Generator -Version 0.3.0
<PackageReference Include="FunctionsFramework.Generator" Version="0.3.0" />
<PackageVersion Include="FunctionsFramework.Generator" Version="0.3.0" />
<PackageReference Include="FunctionsFramework.Generator" />
paket add FunctionsFramework.Generator --version 0.3.0
#r "nuget: FunctionsFramework.Generator, 0.3.0"
#:package FunctionsFramework.Generator@0.3.0
#addin nuget:?package=FunctionsFramework.Generator&version=0.3.0
#tool nuget:?package=FunctionsFramework.Generator&version=0.3.0
FunctionsFramework
Define HTTP handlers once and generate ASP.NET Core Minimal APIs, AWS Lambda Annotations functions, Azure Functions, a typed C# HTTP client, and OpenAPI from the same declarations. The framework is standalone. Its runtime and examples target .NET 10; the Roslyn generator targets .NET Standard 2.0.
NuGet packages
Each push to main builds, tests, and publishes
FunctionsFramework, FunctionsFramework.AwsLambda,
FunctionsFramework.Generator, and FunctionsFramework.Templates to
NuGet.org.
GitVersion computes a unique version for each main-branch commit: Conventional
Commits feat: bump the minor version, fix: and perf: bump the patch,
and a ! or BREAKING CHANGE: footer bumps the major. Other commits bump
the patch. +semver: skip and +semver: none are rejected on main so they
cannot reuse a published version. No release tags are required. CI also builds
and tests pull requests. Publishing uses NuGet.org trusted publishing through
GitHub Actions OIDC; no stored API key is required. Set the repository Actions
variable NUGET_USER to the NuGet.org username associated with the trusted
publishing policy. The policy must authorize this repository and publish.yml
with no GitHub environment specified.
The packages are available from the standard NuGet.org source. The generator package includes the analyzer and both adapter targets, but does not import them automatically: a producer and each host must select the appropriate targets explicitly. Use the published packages in application projects; no FunctionsFramework source checkout is needed. For example, add the generator package and producer target import:
<ItemGroup>
<PackageReference Include="FunctionsFramework.Generator" Version="1.2.3"
GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>
<Import Project="$(PkgFunctionsFramework_Generator)/tools/FunctionAdapterProducer.targets" />
In a host, use the same package reference and import
$(PkgFunctionsFramework_Generator)/tools/FunctionAdapters.targets. The
functions library can reference FunctionsFramework; AWS hosts can also
reference FunctionsFramework.AwsLambda. Keep all package versions aligned.
Get started with dotnet new
The FunctionsFramework.Templates package installs a dotnet new template
that scaffolds a ready-to-run solution: a functions library, a generator
producer, and an ASP.NET Core Minimal API host.
dotnet new install FunctionsFramework.Templates
dotnet new functions-app -n MyApplication
cd MyApplication
dotnet run --project MyApplication.Host
GET /greetings/world returns a typed JSON greeting, and in Development the
generated OpenAPI document is served at /openapi/v1.json. Use
--FunctionsFrameworkVersion to pin the referenced package versions.
Contents
| Path | Purpose |
|---|---|
src/FunctionsFramework |
HTTP attributes, parameter binding attributes, results, and typed result unions; no hosting dependencies |
src/FunctionsFramework.Generator |
Incremental generator, embedded result converters, client generation, OpenAPI, and diagnostics |
src/FunctionsFramework.AwsLambda |
Shared Lambda bootstrap and generated SAM HTTP API template reader |
src/FunctionsFramework.OpenApiClientGenerator |
OpenAPI-based standalone browser client, DTO, interface, and JSON context generator |
build/FunctionAdapterProducer.targets |
Generates the complete adapter set in a separate compilation |
build/FunctionAdapters.targets |
Compiles the selected adapter into a host and exports openapi.json |
templates |
dotnet new template package for scaffolding a Functions Framework solution |
samples |
One functions project, a producer, all three hosts, and a client |
tests/FunctionsFramework.Tests |
Framework regression tests independent of any application |
Try the example
From this directory:
dotnet build FunctionsFramework.slnx '-bl:/tmp/functions-build-{}.binlog'
dotnet test tests/FunctionsFramework.Tests/FunctionsFramework.Tests.csproj '-bl:/tmp/functions-tests-{}.binlog'
dotnet run --project samples/Example.MinimalApi -- --urls http://localhost:5187
GET /greetings/Ada?title=Dr returns a typed JSON greeting. POST /greetings
accepts {"name":"Ada"} and returns HTTP 201 with a Location header; an empty
name returns HTTP 400. Set ASPNETCORE_ENVIRONMENT=Development to serve the
Minimal API's generated document at /openapi/v1.json.
The Azure and AWS sample projects compile the same handlers using their own SDKs.
Azure local execution additionally requires Functions Core Tools and host storage
configuration. AWS deployment uses the generated serverless.template. Building
these samples does not deploy resources.
Add functions to an application
In the application's functions class library, reference the published
FunctionsFramework package:
<ItemGroup>
<PackageReference Include="FunctionsFramework" Version="1.2.3" />
</ItemGroup>
Use using FunctionsFramework; in handlers:
using FunctionsFramework;
namespace MyApplication.Functions;
public sealed record Greeting(string Message);
public sealed class GreetHandler
{
[HttpFunction("greetings/{name}", FunctionHttpMethod.Get, Name = "Greet")]
public OkFunctionResult<Greeting> Handle(string name)
=> FunctionResults.Ok(new Greeting($"Hello, {name}!"));
}
Register application services in each host. The generated
AddGeneratedFunctionHandlers() registers the instance handlers as scoped
services. Handlers can depend on application interfaces through their constructors.
Create a separate producer class library next to the functions project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<FunctionGeneratedNamespace>MyApplication.Generated</FunctionGeneratedNamespace>
<FunctionApiClientNamespace>MyApplication.ApiClient</FunctionApiClientNamespace>
<FunctionOpenApiTitle>My Application API</FunctionOpenApiTitle>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Functions/Functions.csproj" />
<PackageReference Include="FunctionsFramework.Generator" Version="1.2.3"
GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>
<Import Project="$(PkgFunctionsFramework_Generator)/tools/FunctionAdapterProducer.targets" />
</Project>
The three settings are optional. Defaults are FunctionsFramework.Generated,
FunctionsFramework.ApiClient, and HTTP API. Set them in the producer; every
consuming host receives the same generated contract. Multiple applications can
choose distinct client namespaces.
Each host or client references the functions project, selects an adapter, and imports the consumer targets:
<PropertyGroup>
<FunctionAdapterHost>MinimalApi</FunctionAdapterHost>
<FunctionAdapterProducerProject>../Functions.Generated/Functions.Generated.csproj</FunctionAdapterProducerProject>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Functions/Functions.csproj" />
<PackageReference Include="FunctionsFramework.Generator" Version="1.2.3"
GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>
<Import Project="$(PkgFunctionsFramework_Generator)/tools/FunctionAdapters.targets" />
Supported hosts are MinimalApi, Aws, Azure, and ApiClient. Use the sample
projects for the corresponding SDK and package references. Azure's SDK version
also appears in global.json so generated extension projects can resolve it.
In Minimal API startup, import your configured generated namespace and call:
builder.Services.AddGeneratedFunctionHandlers();
var app = builder.Build();
app.MapGeneratedFunctions();
app.Run();
Azure and AWS call AddGeneratedFunctionHandlers() in their normal startup code.
AWS additionally needs a LambdaStartup, a serializer assembly attribute, and
a serverless.template; these are shown in samples/Example.AwsLambda.
The separate producer is necessary because source generators cannot consume each other's output in the same compilation. The targets copy generated source beneath each host's intermediate directory so Azure and AWS's SDK generators can discover entry points and deployment metadata. Generated files are tracked for cleaning; design-time builds do not rewrite the adapters or AWS deployment template.
Handler contracts
Routes support literal segments and {parameter} segments. Route constraints,
optional segments, catch-alls, duplicate placeholders, and reserved parameter names
are rejected. Supported verbs are Get, Post, Put, Patch, Delete, Head, and Options.
Names default to the class name with Handler removed; explicitly set Name to
keep generated operation and client names stable across class renames.
Parameters matching a placeholder bind from the route. Other scalar parameters
bind from the query string. [FromFunctionRoute(Name = "id")] and
[FromFunctionQuery(Name = "limit")] override binding names. Scalars include
strings, booleans, characters, numbers, enums, Guid, DateTime, DateTimeOffset,
DateOnly, and TimeOnly. Parsing uses invariant culture and respects nullable
query parameters and defaults. Missing or invalid inputs return HTTP 400.
Use [FromFunctionBody] for one JSON body. A CancellationToken receives request
cancellation (or Lambda's remaining execution time). Public non-generic handlers
may return FunctionResult subtypes, Task<T>, or ValueTask<T>; static methods
are also supported.
FunctionResults provides Ok, Created, Accepted, NoContent, BadRequest, NotFound,
Conflict, Unauthorized, Forbid, StatusCode, Json, Text, and File factories.
FunctionResults<T1, T2> supports two to four alternatives with implicit conversion.
Declare typed payload results, such as OkFunctionResult<Greeting>, so the client
and OpenAPI generator can discover the response DTO. Untyped results remain
available when the response cannot be described statically.
Object bodies use JSON, including JSON string quoting. Json(null) writes JSON
null. Created results set Location; Unauthorized and Forbid return bare 401/403
responses. Hosts own authentication and authorization configuration.
Hosts dispose returned file streams after writing them. ASP.NET Core and Azure stream directly. AWS buffers binary output into a base64 API Gateway response and remains subject to AWS payload limits. File results can enable single-byte-range and suffix-range requests, including HTTP 206 and 416 responses.
Typed client and OpenAPI
The ApiClient adapter emits IApiClient, ApiClient, and per-operation response
families. Each <Operation>Async method accepts typed route/query/body parameters
and an optional cancellation token. Dispose the response after use:
using FunctionsFramework.ApiClient; // Or your configured namespace.
using var http = new HttpClient { BaseAddress = new Uri("http://localhost:5187/") };
IApiClient client = new ApiClient(http);
using var response = await client.GreetAsync("Ada");
if (response is GreetResponse.Ok(var greeting))
Console.WriteLine(greeting.Message);
The caller owns HttpClient. Configure its base address as the API root, including
Azure's /api/ or an API Gateway stage prefix when applicable. Optional null query
values are omitted and path/query values are escaped. Undeclared responses use an
Unexpected case; malformed required JSON throws JsonException. File responses
keep their content stream open until disposed and support an optional range header.
Each consumer receives FunctionOpenApi.Document in the generated namespace and
an openapi.json in its build/publish output. The OpenAPI 3.0.3 contract includes
operation names, bindings, request bodies, and typed response schemas. Azure and
AWS expose a generated GET openapi/v1.json endpoint unless a handler already owns
that route. Azure applies the same function authorization as its other endpoints.
Minimal API hosts choose when to map the document, as demonstrated in the sample.
Standalone browser client generator
When a browser client should use its own DTOs rather than reference the server's functions assembly, generate a standalone client from the exported OpenAPI file:
dotnet run --project src/FunctionsFramework.OpenApiClientGenerator -- \
--openapi samples/Example.MinimalApi/bin/Debug/net10.0/openapi.json \
--contracts-dir /tmp/example-client \
--namespace Example.Client.Api \
--client-name ExampleApiClient \
--json-context-name ExampleJsonContext
The generator also exposes OpenApiClientGenerator.Generate(options) in the
FunctionsFramework.OpenApiClientGeneration namespace for application-specific
commands. --client-path overrides the client file location; --route-prefix
optionally removes a leading API prefix from operation paths. No prefix is
removed by default.
This generator retains its existing OpenAPI subset: object DTO schemas and JSON
response families. Binary success bodies are consumed directly by browser URLs;
use the Roslyn-generated ApiClient adapter for typed streaming responses.
Lambda local hosting
Reference src/FunctionsFramework.AwsLambda from a shared executable runner and
from orchestration code that reads the generated template:
await FunctionsFramework.AwsLambda.LambdaRunner.RunAsync();
Set FUNCTIONS_FRAMEWORK_LAMBDA_HANDLER to the generated handler entry point, or
pass it directly to RunAsync(handler). The executable also references the
application's Lambda project so its handlers are present at runtime.
LambdaHttpApiTemplate.Read(path) returns each HTTP function's logical ID,
handler, and method/path routes. The application controls resource names, database
references, environment configuration, and publishing.
Diagnostics: FF001 invalid handler signature; FF002 invalid routing metadata;
FF003 invalid parameter binding; FF004 duplicate endpoint/name; FF005
invalid configured namespace.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.