Search code examples
c#.netazure-functionshttprequestmiddleware

In my IFunctionsWorkerMiddleware cannot get value request body and next(context) do nothing


Hi i'm implementing a middleware in project azure function (Isolated), i need get the value from request body and show it in console (from middleware class), but i ever get empty value "", and another problem its the functionality in the next(context) method apparently its not called and never ends.

The middleware:

 public class HistoryLogMiddleware : IFunctionsWorkerMiddleware
 {
   public HistoryLogMiddleware() { }

   public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
   {
     var requestData = await context.GetHttpRequestDataAsync();
     var body = await new StreamReader(requestData.Body).ReadToEndAsync();

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

     requestData.Body.Position = 0;
     await next(context); //when arrivals here does nothing...     
  }
}

The function:

 public class RegisterClientFunction
 {
   private readonly IClientsDomain _clientsDomain;
   public RegisterClientFunction(IClientsDomain clientsDomain)
   {
     _clientsDomain = clientsDomain;
   }

   [Function(nameof(RegisterClientFunction))]
   public async Task<HttpResponseData> RunAsync(
     [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
   {
     //log.LogInformation("C# HTTP trigger function processed a request.");

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

     var respDomain = await ExecuterDomain.ExecuteAsync(() => _clientsDomain.RegisterClient(data));

     var response = req.CreateResponse((HttpStatusCode)respDomain.Status);
     response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
     await response.WriteStringAsync(JsonConvert.SerializeObject(respDomain).ToString(), Encoding.UTF8);

     return response;
   }
 }

The Program.cs :

var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureFunctionsWorkerDefaults(worker => worker.UseMiddleware<HistoryLogMiddleware>())
.ConfigureServices(services => {
    services.AddApplicationInsightsTelemetryWorkerService();
    services.ConfigureFunctionsApplicationInsights();
    services.AddDatabases();
    services.AddExternals();
    services.AddUseCases();
})
.Build();

await host.RunAsync();

Result with middleware: console no shows body and never ends

Result without miiddleware (i comment .ConfigureFunctionsWorkerDefaults(worker => worker.UseMiddleware())): console shows results ok

ignore the result 500, its normal in my example.

Does anybody know why it occurs when i use the middleware?


Solution

  • Remove .ConfigureFunctionsWebApplication() from program.cs file. You should have below code-

    using _78438359;
    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    
    var host = new HostBuilder()
        .ConfigureFunctionsWorkerDefaults(worker => worker.UseMiddleware<HistoryLogMiddleware>())
        .ConfigureServices(services =>
        {
            services.AddApplicationInsightsTelemetryWorkerService();
            services.ConfigureFunctionsApplicationInsights();
        })
        .Build();
    
    await host.RunAsync();
    

    Your .csproj file should have below packages in it.

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <AzureFunctionsVersion>v4</AzureFunctionsVersion>
        <OutputType>Exe</OutputType>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <RootNamespace>_78438359</RootNamespace>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.22.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.3-preview1" />
        <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
        <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
      </ItemGroup>
      <ItemGroup>
        <None Update="host.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <None Update="local.settings.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
          <CopyToPublishDirectory>Never</CopyToPublishDirectory>
        </None>
      </ItemGroup>
      <ItemGroup>
        <Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
      </ItemGroup>
    </Project>
    

    For testing purpose, I have given code in RegisterClientFunction.cs file and no changes made in the HistoryLogMiddleware.cs file.

    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Azure.Functions.Worker.Http;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using System.Net;
    using System.Text;
    
    namespace _78438359
    {
        public class RegisterClientFunction
        {
            public RegisterClientFunction() { }
    
            [Function(nameof(RegisterClientFunction))]
            public async Task<HttpResponseData> RunAsync(
              [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req)
            {
                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                var data = JsonConvert.DeserializeObject<RegisterClientRequest>(requestBody);
    
                var response = req.CreateResponse(HttpStatusCode.OK);
                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
                await response.WriteStringAsync("Client registered successfully.", Encoding.UTF8);
    
                return response;
            }
        }
    }
    

    I am able to get the request body while executing the function.

    enter image description here

    Azure Functions Core Tools
    Core Tools Version:       4.0.5700 Commit hash: N/A +71cc84964a60bfb07d95839b7c666bd239507bdd (64-bit)
    Function Runtime Version: 4.33.2.22572
    
    [2024-05-07T06:17:12.240Z] Found C:\Users\******\78438359\78438359\78438359.csproj. Using for user secrets file configuration.
    [2024-05-07T06:17:15.329Z] Azure Functions .NET Worker (PID: 12756) initialized in debug mode. Waiting for debugger to attach...
    [2024-05-07T06:17:15.374Z] Worker process started and initialized.
    
    Functions:
    
            RegisterClientFunction: [POST] http://localhost:7295/api/RegisterClientFunction
    
    For detailed output, run func with --verbose flag.
    [2024-05-07T06:17:20.445Z] Host lock lease acquired by instance ID '000000000000000000000000BF6D1ED5'.
    [2024-05-07T06:17:59.976Z] Executing 'Functions.RegisterClientFunction' (Reason='This function was programmatically called via the host APIs.', Id=af21e1ad-f53b-4361-90fa-a285fb2e2b88)
    [2024-05-07T06:18:00.136Z] Request Body: {
    [2024-05-07T06:18:00.138Z]     "Name": "Hello Afreen"
    [2024-05-07T06:18:00.139Z] }
    [2024-05-07T06:18:00.357Z] Executed 'Functions.RegisterClientFunction' (Succeeded, Id=af21e1ad-f53b-4361-90fa-a285fb2e2b88, Duration=408ms)