Skip to content

.NET: [Feature]: Support for or guidance on async code in ASP.Net Core hosting #7987

Description

Description

https://learn.microsoft.com/en-us/agent-framework/get-started/hosting?pivots=programming-language-csharp shows how to register agents and workflows with the DI service registration framework of ASP.NET Core.

However, it does not seem to support async code.

Some agents or workflows require async code to be setup. E.g. the A2A agent registration requires async code in multiple scenarios like when fetching the agent card.

This seems to make these framework components incompatible with each other.

It also prevents using async logic in workflows. E.g. dynamically selecting agents based on the response of an async API call does not work this way

Code Sample

⚠️ This code does not compile because the delegate for AddWorkflow does not support an asynchronous delegate

using Microsoft.Agents.AI.Hosting;
using Microsoft.Extensions.AI;
using A2A;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;

var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();

var azureOpenAIDeploymentName = builder.Configuration["AzureOpenAI:DeploymentName"];

builder.AddAzureOpenAIClient(connectionName: "openai")
       .AddChatClient(azureOpenAIDeploymentName); // model deployment name from Azure AI Foundry

builder.Services.AddOpenAIResponses();
builder.Services.AddOpenAIConversations();

var workflowAsAgent = builder
    .AddWorkflow("workflow-as-agent", CreateWorkflowDelegate)
    .AddAsAIAgent();  // Now the workflow can be used as an agent

var app = builder.Build();
app.MapDefaultEndpoints();

app.MapOpenAIResponses();            // OpenAI-compatible endpoints (DevUI)
app.MapOpenAIConversations();

app.Run();

Workflow CreateWorkflowDelegate(IServiceProvider sp, string workflowName)
{
    // Initialize a resolver pointing at the remote agent's host.
    A2ACardResolver agentResolverA = new(new Uri("https://localhost:8093"));

    // Resolve the agent card and create an AIAgent in one step.
    AIAgent agentA = await agentResolverA.GetAIAgentAsync();

    // Initialize a resolver pointing at the remote agent's host.
    A2ACardResolver agentResolverB = new(new Uri("https://localhost:8093"));

    // Resolve the agent card and create an AIAgent in one step.
    AIAgent agentB = await agentResolverB.GetAIAgentAsync();

    var agents = new[] { agentA, agentB };

    var workflow = AgentWorkflowBuilder.BuildConcurrent(agents, aggregator: (responses) =>
    {
        // Custom aggregation logic: simply concatenate all messages from all agents.
        var aggregatedMessages = new List<ChatMessage>();
        foreach (var agentResponses in responses)
        {
            aggregatedMessages.AddRange(agentResponses);
        }
        return aggregatedMessages;
    });

    return workflow;
}

Language/SDK

.NET

Metadata

Metadata

Assignees

No one assigned

    Labels

    .NETUsage: [Issues, PRs], Target: .NettriageUsage: [Issues], Target: All issues that still need to be triaged

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions