.netazure-durable-functions

Is it possible to inject DurableTaskClient in Durable Functions (isolated model)?


I would like to have a service that is capable of starting an orchestration. I am using isolated model. Is it possible to inject DurableTaskClient through dependency injection?

I tried configuring service below and while DurableTaskClient gets injected it throws an exception. I suspect GRPC needs to be additionally configured somehow, maybe to point to task hub or something like that.

Any advice?

`

using DurableFuncExperiment;
using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services =>
    {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
        services.AddTransient<DurableTaskService, DurableTaskService>();
        services.AddDurableTaskClient((builder) =>
        {
            builder.UseGrpc();
        });
    })
    .Build();

host.Run();


using Microsoft.DurableTask.Client;

namespace DurableFuncExperiment;
public class DurableTaskService(DurableTaskClient durableTaskClient)
{
    public async Task Execute()
    {
        string instanceId = await durableTaskClient.ScheduleNewOrchestrationInstanceAsync(Function.SayHelloEventOrchestrator);
    }
}`

Executed 'Functions.Jobs_SayHelloEventOrchestrator' (Failed, Id=9bc3cec2-749e-4a4a-9f6a-1b821839d6d4, Duration=6741ms) [2024-10-11T03:24:15.460Z] System.Private.CoreLib: Exception while executing function: Functions.Jobs_SayHelloEventOrchestrator. System.Private.CoreLib: Result: Failure Exception: System.MissingMethodException: Method not found: 'System.String Microsoft.DurableTask.Protobuf.ExecutionStartedEvent.get_CorrelationData()'. [2024-10-11T03:24:15.467Z] at Microsoft.DurableTask.ProtoUtils.ConvertHistoryEvent(HistoryEvent proto) [2024-10-11T03:24:15.469Z] at System.Linq.Enumerable.SelectIListIterator2.MoveNext() [2024-10-11T03:24:15.475Z] at Microsoft.DurableTask.Worker.Grpc.GrpcOrchestrationRunner.LoadAndRun(String encodedOrchestratorRequest, ITaskOrchestrator implementation, IServiceProvider services) [2024-10-11T03:24:15.479Z] at Microsoft.Azure.Functions.Worker.Extensions.DurableTask.DurableTaskFunctionsMiddleware.RunOrchestrationAsync(FunctionContext context, BindingMetadata triggerBinding, FunctionExecutionDelegate next) in /_/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs:line 58 [2024-10-11T03:24:15.483Z] at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77 [2024-10-11T03:24:15.491Z] at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request) in D:\a\_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 88 Stack: at Microsoft.DurableTask.ProtoUtils.ConvertHistoryEvent(HistoryEvent proto) [2024-10-11T03:24:15.494Z] at System.Linq.Enumerable.SelectIListIterator2.MoveNext() [2024-10-11T03:24:15.496Z] at Microsoft.DurableTask.Worker.Grpc.GrpcOrchestrationRunner.LoadAndRun(String encodedOrchestratorRequest, ITaskOrchestrator implementation, IServiceProvider services) [2024-10-11T03:24:15.498Z] at Microsoft.Azure.Functions.Worker.Extensions.DurableTask.DurableTaskFunctionsMiddleware.RunOrchestrationAsync(FunctionContext context, BindingMetadata triggerBinding, FunctionExecutionDelegate next) in //src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs:line 58 [2024-10-11T03:24:15.501Z] at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77 [2024-10-11T03:24:15.511Z] at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request) in D:\a_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 88. [2024-10-11T03:24:15.514Z] ede0fd849a0d409b9f0c4bee61e938fb: Function 'Jobs_SayHelloEventOrchestrator (Orchestrator)' failed with an error. Reason: Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Functions.Jobs_SayHelloEventOrchestrator [2024-10-11T03:24:15.517Z] ---> Microsoft.Azure.WebJobs.Script.Workers.Rpc.RpcException: Result: Failure Exception: System.MissingMethodException: Method not found: 'System.String Microsoft.DurableTask.Protobuf.ExecutionStartedEvent.get_CorrelationData()'. [2024-10-11T03:24:15.521Z] at Microsoft.DurableTask.ProtoUtils.ConvertHistoryEvent(HistoryEvent proto) [2024-10-11T03:24:15.523Z] at System.Linq.Enumerable.SelectIListIterator2.MoveNext() [2024-10-11T03:24:15.524Z] at Microsoft.DurableTask.Worker.Grpc.GrpcOrchestrationRunner.LoadAndRun(String encodedOrchestratorRequest, ITaskOrchestrator implementation, IServiceProvider services) [2024-10-11T03:24:15.526Z] at Microsoft.Azure.Functions.Worker.Extensions.DurableTask.DurableTaskFunctionsMiddleware.RunOrchestrationAsync(FunctionContext context, BindingMetadata triggerBinding, FunctionExecutionDelegate next) in /_/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs:line 58 [2024-10-11T03:24:15.528Z] at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77 [2024-10-11T03:24:15.530Z] at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request) in D:\a\_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 88 Stack: at Microsoft.DurableTask.ProtoUtils.ConvertHistoryEvent(HistoryEvent proto) [2024-10-11T03:24:15.535Z] at System.Linq.Enumerable.SelectIListIterator2.MoveNext() [2024-10-11T03:24:15.537Z] at Microsoft.DurableTask.Worker.Grpc.GrpcOrchestrationRunner.LoadAndRun(String encodedOrchestratorRequest, ITaskOrchestrator implementation, IServiceProvider services) [2024-10-11T03:24:15.540Z] at Microsoft.Azure.Functions.Worker.Extensions.DurableTask.DurableTaskFunctionsMiddleware.RunOrchestrationAsync(FunctionContext context, BindingMetadata triggerBinding, FunctionExecutionDelegate next) in //src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs:line 58 [2024-10-11T03:24:15.542Z] at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 77 [2024-10-11T03:24:15.544Z] at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request) in D:\a_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 88 [2024-10-11T03:24:15.546Z] at Microsoft.Azure.WebJobs.Script.Description.WorkerFunctionInvoker.InvokeCore(Object[] parameters, FunctionInvocationContext context) in //src/WebJobs.Script/Description/Workers/WorkerFunctionInvoker.cs:line 101 [2024-10-11T03:24:15.551Z] at Microsoft.Azure.WebJobs.Script.Description.FunctionInvokerBase.Invoke(Object[] parameters) in //src/WebJobs.Script/Description/FunctionInvokerBase.cs:line 82 [2024-10-11T03:24:15.553Z] at Microsoft.Azure.WebJobs.Script.Description.FunctionGenerator.Coerce[T](Task1 src) in /_/src/WebJobs.Script/Description/FunctionGenerator.cs:line 225 [2024-10-11T03:24:15.556Z] at Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker2.InvokeAsync(Object instance, Object[] arguments) in D:\a_work\1\s\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionInvoker.cs:line 53 [2024-10-11T03:24:15.558Z] at Microsoft.Azure.WebJobs.Extensions.DurableTask.OutOfProcMiddleware.<>c__DisplayClass10_0.<b__0>d.MoveNext() in D:\a_work\1\s\src\WebJobs.Extensions.DurableTask\OutOfProcMiddleware.cs:line 130 [2024-10-11T03:24:15.560Z] --- End of stack trace from previous location --- [2024-10-11T03:24:15.561Z] at Microsoft.Azure.WebJobs.Host.Executors.TriggeredFunctionExecutor`1.<>c__DisplayClass7_0.<b__0>d.MoveNext() in D:\a_work\1\s\src\Microsoft.Azure.WebJobs.Host\Executors\TriggeredFunctionExecutor.cs:line 51 [2024-10-11T03:24:15.563Z] --- End of stack trace from previous location --- [2024-10-11T03:24:15.568Z] at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.InvokeWithTimeoutAsync(IFunctionInvoker invoker, ParameterHelper parameterHelper, CancellationTokenSource timeoutTokenSource, CancellationTokenSource functionCancellationTokenSource, Boolean throwOnTimeout, TimeSpan timerInterval, IFunctionInstance instance) in D:\a_work\1\s\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 581 [2024-10-11T03:24:15.572Z] at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithWatchersAsync(IFunctionInstanceEx instance, ParameterHelper parameterHelper, ILogger logger, CancellationTokenSource functionCancellationTokenSource) in D:\a_work\1\s\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 527 [2024-10-11T03:24:15.574Z] at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(IFunctionInstanceEx instance, FunctionStartedMessage message, FunctionInstanceLogEntry instanceLogEntry, ParameterHelper parameterHelper, ILogger logger, CancellationToken cancellationToken) in D:\a_work\1\s\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 306 [2024-10-11T03:24:15.576Z] --- End of inner exception stack trace --- [2024-10-11T03:24:15.578Z] at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(IFunctionInstanceEx instance, FunctionStartedMessage message, FunctionInstanceLogEntry instanceLogEntry, ParameterHelper parameterHelper, ILogger logger, CancellationToken cancellationToken) in D:\a_work\1\s\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 352 [2024-10-11T03:24:15.583Z] at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.TryExecuteAsync(IFunctionInstance functionInstance, CancellationToken cancellationToken) in D:\a_work\1\s\src\Microsoft.Azure.WebJobs.Host\Executors\FunctionExecutor.cs:line 108. IsReplay: False. State: Failed. RuntimeStatus: Failed. HubName: TestHubName. AppName: . SlotName: . ExtensionVersion: 2.13.1. SequenceNumber: 11. TaskEventId: -1


Solution

  • You need to make sure that you are using correct packages and also verify your code. I am sharing my code here which I have used for testing purpose.

    I have following packages in .csproj file.

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <AzureFunctionsVersion>v4</AzureFunctionsVersion>
        <OutputType>Exe</OutputType>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <RootNamespace>_79076732</RootNamespace>
      </PropertyGroup>
      <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.23.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.7" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.2.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.3.2" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.18.1" />
        <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.4.0" />
      </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>
    

    I have created a separate file named DurableTaskService which has below given code.

    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Azure.Functions.Worker.Http;
    using Microsoft.DurableTask.Client;
    
    namespace _79076732
    {
        public class DurableTaskService
        {
            private readonly DurableTaskClient _durableTaskClient;
    
            public DurableTaskService(DurableTaskClient durableTaskClient)
            {
                _durableTaskClient = durableTaskClient;
            }
    
            public async Task<HttpResponseData> ExecuteAsync(HttpRequestData req)
            {
                string instanceId = await _durableTaskClient.ScheduleNewOrchestrationInstanceAsync("SayHelloEventOrchestrator");
                Console.WriteLine($"Started orchestration with ID = {instanceId}");
                var result = await _durableTaskClient.CreateCheckStatusResponseAsync(req, instanceId);
    
                return result;
            }
        }
    }
    

    Then I registered it in program.cs file.

    using _79076732;
    using Microsoft.AspNetCore.Server.Kestrel.Core;
    using Microsoft.Azure.Functions.Worker;
    using Microsoft.DurableTask.Client;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    
    var host = new HostBuilder()
        .ConfigureFunctionsWebApplication()
        .ConfigureServices(services =>
        {
            services.AddApplicationInsightsTelemetryWorkerService();
            services.ConfigureFunctionsApplicationInsights();
            services.Configure<KestrelServerOptions>(options =>
            {
                options.AllowSynchronousIO = true;
            });
            services.AddTransient<DurableTaskService, DurableTaskService>();
            services.AddDurableTaskClient((builder) =>
            {
                builder.UseGrpc();
            });
        })
        .Build();
    
    host.Run();
    

    Lastly, I am invoking DurableTaskService using a http triggered function.

    using Microsoft.DurableTask;
    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Azure.Functions.Worker.Http;
    using Microsoft.Extensions.Logging;
    
    namespace _79076732
    {
        public class Function1
        {
            private readonly DurableTaskService _durableTaskService;
    
            public Function1 (DurableTaskService durableTaskService)
            {
                _durableTaskService = durableTaskService;
            }
    
            [Function("SayHelloEventOrchestrator")]
            public async Task<string> SayHelloOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context)
            {
                var result = await context.CallActivityAsync<string>("SayHello", "Afreen");
                return result;
            }
    
            [Function("SayHello")]
            public string SayHello([ActivityTrigger] string name)
            {
                return $"Hello, {name}!";
            }
    
            [Function("StartOrchestration")]
            public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext executionContext)
            {
                var logger = executionContext.GetLogger("StartOrchestrationFunction");
                logger.LogInformation("Starting orchestration...");
    
                var orchestrationResult = await _durableTaskService.ExecuteAsync(req);
    
                return orchestrationResult;
            }
        }
    }
    

    By doing the above given steps, I am able to get the expected response.

    Azure Functions Core Tools
    Core Tools Version:       4.0.6280 Commit hash: N/A +421f0144b42047aa289ce691dc6db4fc8b6143e6 (64-bit)
    Function Runtime Version: 4.834.3.22875
    
    [2024-10-11T08:04:13.447Z] Found C:\Users\*****\79076732\79076732.csproj. Using for user secrets file configuration.
    [2024-10-11T08:04:17.440Z] Azure Functions .NET Worker (PID: 19544) initialized in debug mode. Waiting for debugger to attach...
    [2024-10-11T08:04:17.497Z] Worker process started and initialized.
    
    Functions:
    
            StartOrchestration: [GET,POST] http://localhost:7230/api/StartOrchestration
    
            SayHello: activityTrigger
    
            SayHelloEventOrchestrator: orchestrationTrigger
    
    For detailed output, run func with --verbose flag.
    [2024-10-11T08:04:22.487Z] Host lock lease acquired by instance ID '0000000000000000000000000D2022A4'.
    [2024-10-11T08:04:30.630Z] Executing 'Functions.StartOrchestration' (Reason='This function was programmatically called via the host APIs.', Id=70ee6cb7-000e-462d-b6b0-db15a0d812a2)
    [2024-10-11T08:04:31.024Z] Scheduling new SayHelloEventOrchestrator orchestration with instance ID 'c626f9f4c2904356aa9fce247ac270ee' and 0 bytes of input data.
    [2024-10-11T08:04:31.024Z] Starting orchestration...
    [2024-10-11T08:04:31.226Z] Started orchestration with ID = c626f9f4c2904356aa9fce247ac270ee
    [2024-10-11T08:04:31.301Z] Executed 'Functions.StartOrchestration' (Succeeded, Id=70ee6cb7-000e-462d-b6b0-db15a0d812a2, Duration=712ms)
    [2024-10-11T08:04:31.320Z] Executing 'Functions.SayHelloEventOrchestrator' (Reason='(null)', Id=fc774ab1-d7fe-42e1-bc68-45c275bcd0f8)
    [2024-10-11T08:04:31.508Z] Executed 'Functions.SayHelloEventOrchestrator' (Succeeded, Id=fc774ab1-d7fe-42e1-bc68-45c275bcd0f8, Duration=202ms)
    [2024-10-11T08:04:31.567Z] Executing 'Functions.SayHello' (Reason='(null)', Id=f376e280-6741-4eda-9fe2-4d43f79ff1f9)
    [2024-10-11T08:04:31.582Z] Executed 'Functions.SayHello' (Succeeded, Id=f376e280-6741-4eda-9fe2-4d43f79ff1f9, Duration=17ms)
    [2024-10-11T08:04:31.651Z] Executing 'Functions.SayHelloEventOrchestrator' (Reason='(null)', Id=f52075b5-c10b-4f67-af85-bd933754b8ab)
    [2024-10-11T08:04:31.685Z] Executed 'Functions.SayHelloEventOrchestrator' (Succeeded, Id=f52075b5-c10b-4f67-af85-bd933754b8ab, Duration=36ms)
    

    enter image description here

    enter image description here