You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中Azure Functions的IFunctionsWorkerMiddleware未触发问题排查

Azure Functions中间件未触发的原因及解决方案

核心原因:函数模型与中间件类型不兼容

你使用的IFunctionsWorkerMiddleware是Azure Functions Isolated Worker(独立进程)模型专属的中间件接口,但你的函数代码属于In-Process(进程内)模型——从继承FunctionsStartup、使用HttpRequest参数、FunctionName特性这些特征都能看出来。两种模型的中间件体系完全独立,因此你的中间件不会被触发。

解决方案:根据当前模型选择对应中间件实现

方案1:继续使用In-Process模型,改用IHttpMiddleware

In-Process模型下的HTTP触发函数,需要实现IHttpMiddleware接口来编写中间件:

1. 修改中间件代码

public class HistoryLogMiddleware : IHttpMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        // 启用请求流缓冲,确保函数后续能重复读取
        context.Request.EnableBuffering();
        var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();
        // 重置流位置,避免函数读取时跳过内容
        context.Request.Body.Position = 0;

        Console.WriteLine($"Request Body: {requestBody}");

        // 包装响应流,以便读取响应内容
        var originalResponseBody = context.Response.Body;
        using var responseStream = new MemoryStream();
        context.Response.Body = responseStream;

        // 执行后续中间件和函数逻辑
        await next(context);

        // 读取响应内容并重置流位置
        responseStream.Position = 0;
        var responseContent = await new StreamReader(responseStream).ReadToEndAsync();
        responseStream.Position = 0;

        // 将响应内容复制回原流,确保客户端能收到响应
        await responseStream.CopyToAsync(originalResponseBody);
        context.Response.Body = originalResponseBody;

        Console.WriteLine($"Response: {responseContent}");
    }
}

2. 修改Startup注册代码

在Configure方法中通过AddHttpMiddleware注册中间件:

[assembly: FunctionsStartup(typeof(Startup))]
public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddDatabases();
        builder.Services.AddExternals();
        builder.Services.AddUseCases();

        // 注册HTTP中间件
        builder.Services.AddHttpMiddleware<HistoryLogMiddleware>();
    }
}

方案2:切换到Isolated Worker模型,适配现有中间件

如果想继续使用IFunctionsWorkerMiddleware,需要将函数项目切换到Isolated Worker模型:

1. 修改项目文件(.csproj)

更新Sdk引用和依赖包:

<Project Sdk="Microsoft.NET.Sdk.Functions.Worker">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <OutputType>Exe</OutputType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.19.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.14.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
  </ItemGroup>
</Project>

2. 替换Startup为Program.cs

用WorkerHost替代FunctionsStartup来注册中间件:

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(worker =>
    {
        // 注册中间件
        worker.UseMiddleware<HistoryLogMiddleware>();
    })
    .ConfigureServices(services =>
    {
        services.AddDatabases();
        services.AddExternals();
        services.AddUseCases();
    })
    .Build();

host.Run();

3. 修改函数代码适配Isolated模型

将HttpRequest改为HttpRequestData,并调整响应返回方式:

public class RegisterClientFunction
{
    private readonly IClientsDomain _clientsDomain;

    public RegisterClientFunction(IClientsDomain clientsDomain)
    {
        _clientsDomain = clientsDomain;
    }

    [Function(nameof(RegisterClientFunction))]
    public async Task<HttpResponseData> Run(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestData req,
        FunctionContext context)
    {
        var logger = context.GetLogger<RegisterClientFunction>();
        logger.LogInformation("C# HTTP trigger function processed a request.");

        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        var data = JsonConvert.DeserializeObject<RegisterClientRequest>(requestBody);

        var resp = await ExecuterDomain.ExecuteAsync(() => _clientsDomain.RegisterClient(data));
        
        var response = req.CreateResponse(HttpStatusCode.OK);
        await response.WriteAsJsonAsync(resp);
        return response;
    }
}

4. 调整中间件的响应读取逻辑

Isolated模型下默认响应流不可读,需要包装后读取:

public class HistoryLogMiddleware : IFunctionsWorkerMiddleware
{
    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        var requestData = await context.GetHttpRequestDataAsync();
        var body = await new StreamReader(requestData.Body).ReadToEndAsync();
        // 重置请求流位置
        requestData.Body.Position = 0;

        Console.WriteLine($"Request Body: {body}");

        // 包装响应流
        var originalResponseFeature = context.Features.Get<IHttpResponseFeature>();
        var originalBody = originalResponseFeature.Body;
        using var responseStream = new MemoryStream();
        originalResponseFeature.Body = responseStream;

        await next(context);

        responseStream.Position = 0;
        var resp = await new StreamReader(responseStream).ReadToEndAsync();
        responseStream.Position = 0;

        await responseStream.CopyToAsync(originalBody);
        originalResponseFeature.Body = originalBody;

        Console.WriteLine($"Response: {resp}");
    }
}

内容的提问来源于stack exchange,提问作者Dr oscar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 09:00:57