Knowledge Base as a Service in Azure Logic Apps

The Logic Apps Agent Loop series published here between May and June 2026 documented the agentic capabilities of Azure Logic Apps in depth. Notably, one recurring limitation across that series was the complexity of knowledge retrieval: building a proper Retrieval-Augmented Generation pipeline required a separately configured Azure AI Search index, an indexer, a data source, and a significant setup overhead before the agent could answer a question from enterprise content.

Consequently, the Knowledge Base-as-a-Service (KBaaS) capability in Azure Logic Apps, announced at Integrate 2026 and now in preview, addresses this directly. This post, as a follow-up to the previous post on all the announcements, walks through what KBaaS is, how it works, and how to build a practical HR policy agent that answers employee questions from uploaded policy documents, with a complete sample available on GitHub.

What is Knowledge Base as a Service?

KBaaS is a Logic Apps-native RAG pipeline that sits in front of Azure Cosmos DB and Azure OpenAI. Instead of building and managing the ingestion and retrieval infrastructure yourself, you upload documents and KBaaS handles the rest.

Specifically, the service has two pipelines:

  • Ingestion pipeline — when you upload a document, KBaaS automatically parses, chunks, summarises, and vectorises the content using your Azure OpenAI embeddings model. The results are stored in four Cosmos DB containers that KBaaS creates and manages on your behalf.
  • Retrieval pipeline — when an agent loop queries the knowledge base, KBaaS rewrites the query if needed, generates a vector representation, performs a semantic search against Cosmos DB, and returns the most relevant chunks to the language model for response generation.
Structural diagram showing the two KBaaS pipelines. The ingestion pipeline flows left to right: document upload, parse, chunk, summarise, embed, then into Cosmos DB across four containers. A dashed arrow connects the stored vectors in Cosmos DB down to the retrieval pipeline. The retrieval pipeline flows left to right: agent loop query, rewrite, vector search against Cosmos DB, top ranked chunks, LLM response. The bottom row shows the Logic Apps agent loop wrapper: HTTP trigger, knowledge base tool, Response action.
Figure 1 — The two pipelines that power Knowledge Base as a Service in Azure Logic Apps. The ingestion pipeline (top) runs automatically when you upload a document: it parses and extracts text, chunks it into segments, summarises using Azure OpenAI, and embeds the content using an embeddings model before storing everything in four Cosmos DB containers. The retrieval pipeline (middle) runs when the agent loop queries the knowledge base: the query is rewritten if needed, vectorized, and matched against the stored embeddings in Cosmos DB via semantic search. The top-ranked chunks are passed to the LLM to generate a grounded answer. The agent loop wrapper (bottom) shows how these two pipelines sit inside a standard Logic Apps autonomous workflow.

In contrast, the key difference from a manually configured RAG pipeline is the abstraction layer. You do not configure chunking strategies, embedding dimensions, index schemas, or retrieval parameters. Instead, you upload documents and add the knowledge base as a tool. The agent loop does the rest.

Knowledge Base as a Service: Deploying the sample

The complete sample is available at steefjan1/logic-apps-kbaas-sample. It includes the workflow definition, Bicep infrastructure template, sample HR policy documents, and connection configuration.

Step 1: Provision infrastructure with azd

cd C:\Dev\logic-apps-kbaas-sample
azd auth login
azd init
azd env new <your-env-name>
azd provision

Naming note: avoid hyphens in your environment name. The Bicep template appends store to the prefix for the storage account name, and hyphens are not valid in storage account names. Use a short alphanumeric name such as kbaas rather than kbaas-preview.

Specifically, azd provision creates the resource group, a Logic App Standard, a Cosmos DB with vector search enabled, a storage account, an App Service Plan, and RBAC role assignments.

Step 2: Set app settings

$cosmosKey = az cosmosdb keys list `
--name <cosmos-name> `
--resource-group <resource-group> `
--query primaryMasterKey -o tsv
$storageKey = az storage account keys list `
--account-name <storage-name> `
--resource-group <resource-group> `
--query "[0].value" -o tsv
az logicapp config appsettings set `
--name <logic-app-name> `
--resource-group <resource-group> `
--settings `
AzureWebJobsStorage="DefaultEndpointsProtocol=https;AccountName=<storage-name>;AccountKey=$storageKey;EndpointSuffix=core.windows.net" `
FUNCTIONS_EXTENSION_VERSION="~4" `
FUNCTIONS_WORKER_RUNTIME="dotnet" `
APP_KIND="workflowapp" `
OPENAI__endpoint="https://<your-aoai-resource>.openai.azure.com/" `
OPENAI__key="<your-aoai-key>" `
agent_openAIKey="<your-aoai-key>" `
agent_openAIEndpoint="https://<your-aoai-resource>.openai.azure.com/" `
COSMOS__endpoint="https://<cosmos-name>.documents.azure.com:443/" `
COSMOS__key="$cosmosKey"

Step 3: Deploy the workflow

Compress-Archive `
-Path connections.json, host.json, hr-policy-agent `
-DestinationPath ..\kbaas-deploy.zip `
-Force
az logicapp deployment source config-zip `
--name <logic-app-name> `
--resource-group <resource-group> `
--subscription "<your-subscription>" `
--src ..\kbaas-deploy.zip
az logicapp restart `
--name <logic-app-name> `
--resource-group <resource-group>

Verify the workflow deployed cleanly go to the Logic App OverviewNotifications tab and confirm no WorkflowProcessingFailed errors appear before proceeding.

Step 4: Create the knowledge base connection

In the Azure portal, open your Logic App. Under Agents in the left sidebar, select Knowledge base then + Set up.

Basics tab:

  • Display name: hr-knowledge-base
  • Authentication type: Key-based
  • Database: select your Cosmos DB account — URL endpoint and key auto-populate
  • Click Next

Model tab:

  • Authentication type: URL and key-based authentication
  • Azure OpenAI resource: select your Azure OpenAI resource
  • Completions model: enter your GPT-4o deployment name exactly as it appears in Azure OpenAI
  • Embeddings model: text-embedding-3-small
  • Click Create

Preview limitation: The knowledge base connection does not persist across page refreshes in the current preview — this is a known portal UI bug. Do not refresh the page after clicking Create. Proceed immediately to adding files.

Note: Furthermore, after creating the connection, you can only edit display names. Authentication type, endpoint, and model deployment names cannot be changed. Get these right before clicking Create.

Step 5: Upload knowledge sources

Immediately after creating the connection, without refreshing, click New → Add files.

  • Group name: type hrpolicies
  • Upload hr-leave-policy.md from the sample’s docs/ folder
  • Artifact name: hr-leave-policy
  • Click Add

Once the status changes to Completed, then repeat for hr-expense-policy.md.

Preview limitation: The portal uploads one file at a time. Wait for each file to reach Completed before uploading the next.

Preview limitation: The Add button may remain greyed out if the artifact name field does not register keyboard input. If this happens, try dragging and dropping the file onto the upload area rather than using the file picker, then type the artifact name. If the button remains inactive, try a private/incognito browser window.

Azure portal Knowledge base page for the kbass-preview-la Standard logic app. The page shows the hrpolicies group containing two files: hr-leave-policy and hr-expense-policy, both showing Completed status after KBaaS ingestion processing.
Figure 2 — Both HR policy documents successfully ingested into the knowledge base. The KBaaS ingestion pipeline parsed, chunked, summarised, and vectorised each document automatically no manual configuration of Cosmos DB containers, indexers, or embedding pipelines required. The Completed status confirms the content is ready for semantic retrieval by the agent loop.

KBaaS creates the following Cosmos DB containers during ingestion:

ContainerPurpose
KnowledgeHubsKnowledge base metadata
KnowledgeArtifactsSource metadata and document references
KnowledgeArtifactChunksFull-text document chunks
KnowledgeArtifactChunkSummariesSummarised chunks with vector embeddings

Step 6: Add the knowledge base as a tool

Open the hr-policy-agent workflow in the Logic Apps designer. Select the HR Policy Agent action and scroll to the Knowledge base section in the parameters pane. Select Create and choose hr-knowledge-base from the list. Save the workflow.

Testing the agent

Get the trigger URL from hr-policy-agentOverviewRun trigger → copy the callback URL.

Test 1 — grounded answer from the leave policy:

In postman execute: https://kbass-preview-la.azurewebsites.net:443/api/hr-policy-agent/triggers/When_an_HTTP_request_is_received/invoke?api-version=2022-05-01&sp=%2Ftriggers%2FWhen_an_HTTP_request_is_received%2Frun&sv=1.0&sig=<sig>

With payload (application\json): {“question”: “How many days of annual leave am I entitled to?”}

Postman request showing a POST to the hr-policy-agent trigger URL with body containing question: How many days of annual leave am I entitled to? The response shows 200 OK with a JSON body containing the question and a grounded answer citing the annual leave policy document.
Figure 3 — The HR policy agent returns a grounded answer to a leave entitlement question. The agent queried the knowledge base, retrieved the relevant section from the annual leave policy document, and returned a cited response, all within a single autonomous agent loop run. The answer is grounded in the uploaded policy content rather than the model’s general training knowledge.

Test 2 — grounded answer from the expense policy:

In postman execute: https://kbass-preview-la.azurewebsites.net:443/api/hr-policy-agent/triggers/When_an_HTTP_request_is_received/invoke?api-version=2022-05-01&sp=%2Ftriggers%2FWhen_an_HTTP_request_is_received%2Frun&sv=1.0&sig=<sig>

With payload: (application\json):{“question”: “What is the maximum I can claim per night for hotel accommodation?”}

Test 3 — correct fallback when knowledge base has no answer:

In postman execute: https://kbass-preview-la.azurewebsites.net:443/api/hr-policy-agent/triggers/When_an_HTTP_request_is_received/invoke?api-version=2022-05-01&sp=%2Ftriggers%2FWhen_an_HTTP_request_is_received%2Frun&sv=1.0&sig=<sig>

With payload: {“question”: “What is the company policy on remote working?”}

As a result, the agent answers the first two questions from the uploaded documents and correctly declines the third exactly as the system prompt instructs.

Logic Apps run history for the hr-policy-agent workflow showing a successful run. The log panel shows the HTTP trigger, a user chat message, the agent action completing with tool invocations including the knowledge base retrieval tool, a sent chat message, and the Response action. The canvas shows the workflow steps with green success indicators.
Figure 4 — The run history of the HR policy agent showing the full agent loop execution. The knowledge base tool invocation is visible as a discrete step within the agent iterations: the agent reasoned over the question, decided to query the knowledge base, received the relevant policy chunks, and composed a grounded answer before returning the Response action result. This is the same Think → Act → Observe loop covered in the Logic Apps Agent Loop series, now with KBaaS providing the retrieval step automatically.

Knowledge Base as a Service:: Practitioner notes

Several things in the current preview are worth documenting for anyone following along:

Connection persistence bug — the knowledge base connection disappears on page refresh in the portal. The connection is correctly stored in connections.json on disk and the workflow runs correctly — but the portal UI does not display it after refresh. Work around this by not refreshing after creating the connection and uploading files in the same browser session.

knowledgeHubConnections format — the connections.json format for knowledge base connections is not publicly documented. If you include a knowledgeHubConnections block with incorrect structure in your deployed connections.json, the Logic App runtime will fail to start with The 'knowledgeHubConnections' property in connection.json has a value that cannot be parsed. The safest approach is to omit knowledgeHubConnections from your deployed connections.json entirely and let the portal write it after deployment.

Embeddings model region availabilitytext-embedding-3-small with Standard SKU is not available in all Azure regions. Use GlobalStandard SKU as shown in the prerequisites command above.

Managed Identity for agent connections — KBaaS supports Managed Identity authentication for the Cosmos DB connection. However, Managed Identity is not supported for the agent model connection when using the MicrosoftFoundry model type. If your workflows use Foundry Models, the agent connection must use Key authentication. Managed Identity remains the right choice for the Cosmos DB connection and all other backend services.

workflow.json schema — the Agent action requires a limit property at the action level (not inside inputs) and a modelConfigurations block with a referenceName pointing to the agent connection. The Microsoft Learn documentation does not show these as required, but the runtime rejects the workflow without them.

Preview limitations

  • Only uploaded files are supported as knowledge sources — live API connectors and SharePoint libraries are not yet available
  • Supported formats: DOC, DOCX, HTML, MD, PDF, PPT, PPTX, TXT, XLS, XLSX
  • Text-based content only — images within documents are not parsed
  • Default chunking only — custom chunk size and overlap configuration is not yet available
  • Azure portal only — VS Code is not yet supported for knowledge base configuration
  • One file upload at a time — wait for each file to reach Completed before uploading the next

GitHub sample

The complete sample workflow definition, Bicep infrastructure template, sample HR policy documents, and connection configuration are available on my GitHub.

What comes next

KBaaS is the most significant reduction in RAG pipeline complexity that Logic Apps has offered to date. For scenarios where uploaded documents are the primary knowledge source, it removes the Azure AI Search setup entirely and replaces it with a portal-native upload flow. The preview limitations, particularly the connection persistence bug and the lack of live source connectors, will be addressed in subsequent releases.

The natural next step is combining KBaaS with the multi-agent patterns from Part 5 of the Logic Apps Agent Loop series, an orchestrator agent that routes questions to specialist knowledge bases, each containing documents for a specific domain.

Azure Logic Apps at Integrate 2026: The Announcements

Integrate 2026 took place on June 8–9 and brought the Microsoft integration product group together with the community for the first time since the platform’s agentic capabilities became generally available. For Azure Logic Apps, the announcements from Divya Swarnkar and Wagner Silveira’s session “What’s New and What’s Next in Azure Logic Apps” signal something more than a feature release cycle. They signal a platform repositioning.

Historically, Logic Apps has always occupied the integration and workflow orchestration layer of the Azure stack. Consequently, it is also firmly in the AI orchestration layer, connecting systems, knowledge, and intelligent agents in ways that were not possible twelve months ago. As a result, this post unpacks the five announcements that matter most for integration architects and connects them to the work covered in the Logic Apps Agent Loop series published here over the past two months.

Azure Logic Apps Integrate: The announcements

1. Azure Logic Apps Automation

The headline announcement is Logic Apps Automation, a new managed offering that sits alongside Logic Apps Standard and Consumption. It introduces a dedicated automation portal, AI-assisted workflow authoring, and a fully managed infrastructure model that removes the App Service Plan configuration and management required by Standard.

For integration architects in particular, this is significant in two ways. First, AI-assisted authoring lowers the barrier to building workflows; natural language descriptions of what a workflow should do can generate a starting point for the designer. Second, the fully managed model means organizations can adopt Logic Apps at scale without dedicated infrastructure expertise for every deployment.

In practice, Logic Apps Automation targets the enterprise automation use case: the high-volume, repeatable processes that currently live in RPA tools, home-grown scripts, or overly complex BPMN platforms. Importantly, it retains Logic Apps’ governance and security capabilities while making the platform accessible to a broader audience within the organization.

2. Knowledge as a Service

Microsoft announced Knowledge as a Service for Logic Apps, a capability that simplifies how organizations prepare enterprise data for AI-driven scenarios. Rather than building and maintaining complex data ingestion, chunking, embedding, and retrieval pipelines, teams can upload content, and Logic Apps handles the orchestration required to make that data available to AI agents.

Notably, this is directly relevant to the agentic workflows covered in this series. In Post 4, the agent tool layer relied on Azure AI Search as the retrieval mechanism, which required a separately configured search index, an indexer, a data source, and a skill set. Instead, Knowledge as a Service abstracts that complexity into a Logic Apps-native capability, reducing the setup time for a retrieval-augmented generation pattern from hours to minutes.

Significantly, the capability will be available across both Logic Apps Automation and Logic Apps Standard.

3. Azure AI Foundry Agent Integration

Logic Apps now supports invoking Azure AI Foundry Agents directly from workflows. Organisations can build, evaluate, and govern agents within Azure AI Foundry and use Logic Apps to orchestrate those agents as part of broader business processes.

Crucially, this closes a gap that the agent loop series ran into directly. Moreover, in Post 4, the attempt to call a Logic Apps workflow as an OpenAPI tool from Foundry hit network restrictions between the two platforms. As a result, the native Foundry Agent Integration announced at Integrate 2026 addresses this at the platform level; the connection between Logic Apps and Foundry is a first-class integration, not a custom OpenAPI workaround.

In practice, for multi-agent architectures, this means the orchestrator-worker pattern from Post 5 can now span both platforms: a Foundry agent as the orchestrator, Logic Apps autonomous workflows as the workers, with native connectivity between them rather than the SAS token-based HTTP invocation used in the demo.

4. Logic Apps Standard SDK

Microsoft introduced the Logic Apps Standard SDK, enabling workflows to be authored directly in C#. Developers gain access to familiar .NET tooling, type safety, NuGet packaging, and proper source control practices, while continuing to use the existing Logic Apps runtime and operational infrastructure.

Of all the announcements, this is the most relevant to the DevOps content in Post 7 of this series. The JSON-on-disk deployment model covered there remains valid, but the SDK adds a code-first authoring path that developer teams will strongly prefer for complex workflows. Type-safe workflow definitions, unit testability, and IDE integration (Visual Studio, VS Code) address the most common developer friction points with the current designer-first model.

For integration architects evaluating Logic Apps for new projects, the SDK changes the “who builds this” conversation. Workflows no longer need to be designer-authored by integration specialists; they can be written by developers using the tools they already know.

5. Azure Connector Namespace

Microsoft unveiled Azure Connector Namespace, which decouples Logic Apps connectors from Logic Apps workflows. The connector ecosystem, which includes over 1,400 connectors covering Microsoft and third-party services, can now be used from custom applications, Azure Functions, Container Apps, and AI agent platforms without the workflow runtime.

Of the five, this is architecturally the most significant for the longer term. Previously, the three-layer tool model covered in Post 4 (built-in connectors, custom connectors, MCP servers) assumed that connectors lived inside Logic Apps workflows. Azure Connector Namespace removes that constraint. Now, an Azure Function or a Foundry agent can now consume a Logic Apps connector directly, accessing Office 365, Service Bus, SAP, or any of the other 1,400+ services without a workflow in between.

Side-by-side diagram showing the architectural shift introduced by Azure Connector Namespace. Left side labelled Before shows connectors and agent tools locked inside a Logic Apps workflow boundary, with the workflow runtime required for all connector use, and a coral box at the bottom indicating connectors are locked to the Logic Apps runtime only. Right side labelled After shows a shared Azure Connector Namespace layer at the top containing Office 365, SAP, Service Bus, and 1,400 plus connectors, with four consumers below it connected by arrows: Logic Apps workflows, Azure Functions serverless compute, Container Apps custom apps, and AI agents including Foundry, MCP, and custom. A teal box at the bottom indicates connectors are decoupled from the workflow runtime and usable anywhere.
Figure 1 — The architectural shift introduced by Azure Connector Namespace. Before the announcement (left), connectors were tightly coupled to the Logic Apps workflow runtime, accessible only from within a workflow, with the runtime always in the execution path. After (right), the connector ecosystem becomes a shared infrastructure layer. Logic Apps workflows, Azure Functions, Container Apps, and AI agents, whether running in Azure AI Foundry, via MCP, or as custom implementations, can all consume the same 1,400+ connectors independently of the workflow runtime.

For enterprise AI architectures, this means the connectivity layer and the orchestration layer are now separable. An AI agent can reach any enterprise system through the connector ecosystem without Logic Apps being the runtime that executes the connection.

Azure Logic Apps Integrate: The direction of travel

Taken together, the five announcements describe a platform moving in a consistent direction: Logic Apps is becoming the connectivity and orchestration substrate for enterprise AI, not just enterprise integration.

The diagram below maps the five announcements against the platform layers they affect: authoring, orchestration, knowledge, connectivity, and developer experience.

Structural diagram showing five Integrate 2026 Logic Apps announcements organised into three platform layers. Layer 1 authoring and developer experience contains Logic Apps Automation with AI-assisted authoring and fully managed infrastructure, and the Logic Apps Standard SDK with C# workflow authoring and .NET tooling. Layer 2 orchestration and AI contains Azure AI Foundry Agent Integration spanning the full width, enabling native invocation of Foundry agents from workflows without an OpenAPI workaround. Layer 3 knowledge and connectivity contains Knowledge as a Service with RAG pipeline abstraction, and Azure Connector Namespace giving access to 1,400 plus connectors without the workflow runtime. A series connection row at the bottom links the announcements to Posts 4, 5, and 7 of the Logic Apps Agent Loop series.
Figure 2 — Five announcements from the Logic Apps product group session at Integrate 2026, mapped to the platform layers they affect. Layer 1 addresses the authoring and developer experience gap. Logic Apps Automation brings AI-assisted workflow creation and a fully managed infrastructure model, while the Standard SDK opens a code-first C# path for development teams. Layer 2 closes the orchestration gap between Logic Apps and Azure AI Foundry with a native agent integration that removes the OpenAPI workaround documented in Post 4 of this series. Layer 3 extends the platform’s reach: Knowledge as a Service abstracts RAG pipeline complexity, and Azure Connector Namespace decouples the 1,400+ connector ecosystem from the workflow runtime entirely.

The agent loop series documented the platform as it stood at the general availability of the agentic capabilities. Encouragingly, several of the limitations called out in that series the Foundry network restrictions, the complexity of knowledge retrieval setup, and the JSON-only authoring model are directly addressed by the Integrate 2026 announcements. That is a healthy sign: the platform team is hearing the practitioner feedback and moving quickly.

Azure Logic Apps Integrate: What this means for integration architects

Three practical implications for architects evaluating or already using Logic Apps:

  • First, revisit your hosting model decision. Logic Apps Automation changes the Standard-versus-Consumption decision for new projects. If the fully managed model meets your governance requirements, the App Service Plan overhead goes away.
  • Secondly, reconsider your knowledge retrieval approach. If you are building RAG patterns on Azure today using manually configured AI Search indexes, Knowledge as a Service is worth evaluating as a simpler path, particularly for projects where the data preparation pipeline is more complex than the agent itself.
  • Third, plan for SDK adoption. If your organization has strong .NET development capability, the Logic Apps Standard SDK should be on the evaluation list for any new workflow project. The designer-first model remains valid, but the code-first path will be preferred by development teams working in existing C# codebases.

Azure Logic Apps Integrate: Series connection

The Logic Apps Agent Loop series published here between May and June 2026 covered the agentic capabilities of Logic Apps in depth, from the anatomy of a single agent loop through to multi-agent patterns, security, and production operations. The Integrate 2026 announcements build directly on that foundation. Post 4’s MCP server pattern connects to the Azure Connector Namespace. Subsequently, Post 5’s orchestrator-worker pattern connects to the Foundry Agent Integration. Post 7’s DevOps section connects to the Standard SDK.

Microsoft Foundry Citadel Platform Azure: A Practitioner’s Deployment Guide

Microsoft Foundry Citadel Platform on Azure is a layered AI governance architecture that delivers production-ready agent deployments with unified governance, end-to-end observability, and centralized policy enforcement via Azure API Management. It is still in preview, and the documentation assumes a degree of familiarity with Azure infrastructure that not everyone has on day one. This post walks through what it actually takes to get a working hub-and-spoke running in Sweden Central, including the pitfalls, so you can decide whether it is a viable starting point for your own AI platform journey.

What Citadel Is (and Is Not)

Before touching the tooling, it helps to understand what Citadel actually deploys. The architecture has four layers:

The first layer — Governance Hub is the runtime enforcement plane: Azure API Management as a centralized AI gateway, Azure API Center as a model registry, and supporting services for content safety, PII detection, cost attribution, and usage telemetry.

Subsequent second layer 2 — AI Control Plane provides observability via the Foundry Control Plane: agent-level execution traces, AI evaluations in development and production, red-teaming, drift monitoring, and fleet dashboards.

The next third layer — Agent Identity transforms agents into managed enterprise assets via Microsoft Entra ID, with lifecycle management, sponsorship models for human accountability, and shadow AI discovery.

Finally, the last fourth layer, 4 Security Fabric, weaves Defender, Purview, and Entra across the other three layers for real-time threat intelligence, data governance, and compliance automation.

For this guide, we deploy Layer 1 (the Governance Hub via the AI Hub Gateway Solution Accelerator) and a Layer 1/2 spoke (via the AI Landing Zone Bicep). Layers 3 and 4 reference existing Azure services (Entra ID, Defender, Purview) that you integrate separately.

Important: Citadel is currently in preview. The repos, parameter schemas, and CLI commands will change. Treat everything in this post as a starting point, not a stable reference.

Prerequisites

Before you start, make sure you have:

  • An Azure subscription with Azure OpenAI access approved (aka.ms/oaiapply)
  • Microsoft.Authorization/roleAssignments/write on the subscription (Owner or User Access Administrator role)
  • Azure CLI installed and authenticated (az login)
  • Azure Developer CLI (azd) installed
  • Node.js — use v20 LTS, not v24. Node 24 on Windows has a known issue where npm bundles are incomplete, causing MODULE_NOT_FOUND errors on npm-cli.js and npm-prefix.js when azd tries to package Logic App components

If you run into npm issues on Windows, the cleanest workaround is Azure Cloud Shell, where Node, npm, az, and azd are all pre-installed and healthy.

Part 1: Deploying the Microsoft Foundry Citadel Governance Hub

Clone the AI Hub Gateway Solution Accelerator:

git clone https://github.com/Azure-Samples/ai-hub-gateway-solution-accelerator.git
cd ai-hub-gateway-solution-accelerator

Create your azd environment:

azd auth login
azd env new ai-hub-gateway-dev
azd env set AZURE_LOCATION swedencentral

Create a parameters file at infra/main.parameters.json. The key decisions:

Model versions matter. At the time of writing, gpt-4o-mini versions 2024-07-18 and 2024-10-18 are retired. Use gpt-4o version 2024-11-20 with GlobalStandard SKU. Always verify current model availability at aka.ms/aoai-regions before deploying these changes frequently.

{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environmentName": { "value": "ai-hub-gateway-dev" },
"location": { "value": "swedencentral" },
"apimSku": { "value": "Developer" },
"openAiInstances": {
"value": {
"openAi1": {
"name": "openai1",
"location": "swedencentral",
"deployments": [
{
"name": "chat",
"model": { "format": "OpenAI", "name": "gpt-4o", "version": "2024-11-20" },
"sku": { "name": "GlobalStandard", "capacity": 20 }
},
{
"name": "embedding",
"model": { "format": "OpenAI", "name": "text-embedding-3-large", "version": "1" },
"sku": { "name": "Standard", "capacity": 20 }
}
]
}
}
},
"provisionFunctionApp": { "value": false },
"createAppInsightsDashboard": { "value": false },
"enableAIGatewayPiiRedaction": { "value": true },
"enableAIModelInference": { "value": true }
}
}

Deploy:

azd up

Expect 45–90 minutes. APIM Developer SKU is the slow component. If the deployment fails partway through, re-run azd up it is idempotent and will pick up where it left off.

Azure CLI output showing successful deployment of the Microsoft Foundry Citadel Governance Hub including APIM, Azure OpenAI chat and embedding model deployments, private endpoints, and Logic App in Sweden Central.
The AI Hub Gateway Solution Accelerator was deployed successfully in Azure Sweden Central after 21 hours and31 minutes, provisioning APIM, Azure OpenAI, Content Safety, Application Insights, private endpoints, and the usage processing Logic App.

Pitfall: Managed Identity Race Condition

You will likely see this error on first attempt:

BadRequest: The provided principal ID was not found in the AAD tenant(s)

This is a known race condition — the Managed Identity is created but has not yet propagated in Entra ID before the role assignment fires. Re-run azd up without any changes and it will succeed.

Validate the Hub

Once deployed, run:

azd env get-values | grep APIM

You will get your APIM gateway URL. Test it with a chat completion:

$headers = @{
"Content-Type" = "application/json"
"api-key" = "<YOUR_APIM_SUBSCRIPTION_KEY>"
}
$body = '{"messages":[{"role":"user","content":"Hello from the AI Hub Gateway!"}],"max_tokens":100}'
Invoke-RestMethod `
-Uri "https://<your-apim>.azure-api.net/openai/deployments/chat/chat/completions?api-version=2024-02-01" `
-Method POST -Headers $headers -Body $body
PowerShell output showing a successful chat completion response from the Microsoft Foundry Citadel APIM gateway in Azure Sweden Central, with content filter results, prompt filter results, and token usage confirmed.
Validating the Citadel Governance Hub by calling the APIM gateway endpoint via PowerShell, the response confirms gpt-4o-2024-11-20 routing, Content Safety filtering, PII redaction, and token usage tracking are all active.

A successful response with content_filter_results and prompt_filter_results confirms Content Safety and PII redaction are active. Token usage in the response confirms Cosmos DB is logging for cost attribution.

Part 2: Deploying a Citadel Platform Agent Spoke on Azure

The spoke is deployed from the AI Landing Zone Bicep repo. Download it as a ZIP (no GitHub account required):

https://github.com/Azure/bicep-ptn-aiml-landing-zone/archive/refs/heads/main.zip

Extract and navigate to the folder. Create a resource group for the spoke:

az group create --name rg-ai-spoke-dev --location swedencentral

Create a spoke.parameters.json file. Several things to know upfront:

The parameter schema is not the same as the Citadel README suggests. The actual template parameters differ from the example file. Key differences discovered in practice: aiFoundryLocation does not exist as a separate parameter; deployMcp, greenFieldDeployment, deployPostgres, and useCMK are not in this version of the template; and solutionStorageAccountName is simply storageAccountName.

The modelDeploymentList uses nested objects, not flat properties:

"modelDeploymentList": {
"value": [
{
"name": "chat",
"model": { "format": "OpenAI", "name": "gpt-4o", "version": "2024-11-20" },
"sku": { "name": "GlobalStandard", "capacity": 20 },
"canonical_name": "CHAT_DEPLOYMENT_NAME",
"apiVersion": "2025-04-01-preview"
},
{
"name": "text-embedding",
"model": { "format": "OpenAI", "name": "text-embedding-3-large", "version": "1" },
"sku": { "name": "Standard", "capacity": 10 },
"canonical_name": "EMBEDDING_DEPLOYMENT_NAME",
"apiVersion": "2025-04-01-preview"
}
]
}

containerAppsList cannot be an empty array. The template references containerApps[0] internally and will fail validation if the array is empty. Pass at least one placeholder entry.

Deploy:

az deployment group create `
--resource-group rg-ai-spoke-dev `
--template-file main.bicep `
--parameters @spoke.parameters.json

Pitfalls in the Spoke Deployment

AI Search Standard SKU capacity exhaustion. Sweden Central frequently runs out of AI Search Standard SKU capacity. You will see ResourcesForSkuUnavailable. This affects both the standalone Search Service and the AI Foundry Agent Service’s internal Search instance. Disable both:

"deploySearchService": { "value": false },
"deployAAfAgentSvc": { "value": false }

You can re-enable them later once capacity is available, or deploy Search in a different region.

Soft-deleted resources block redeployment. Azure retains soft-deleted Cognitive Services accounts, Key Vaults, and App Configuration stores for up to 90 days. If you delete a resource group and redeploy, the deployment will fail with FlagMustBeSetForRestore or NameUnavailable. Purge them explicitly before redeploying:

# List and purge soft-deleted resources
az keyvault list-deleted --subscription <sub-id> -o table
az keyvault purge --name <name> --location swedencentral
az appconfig list-deleted --subscription <sub-id> -o table
az appconfig purge --name <name> --location swedencentral --yes
az cognitiveservices account list-deleted --subscription <sub-id> -o table
az cognitiveservices account purge --name <name> --location swedencentral

Key Vault purges are slow — allow 2–5 minutes per vault.

Bastion subnet ID resolution fails with networkIsolation=false. When you disable network isolation, the template passes a relative subnet ID to Bastion instead of a fully qualified resource ID. Disable Bastion, Jump VM, and NAT Gateway for the dev spoke:

"deployBastion": { "value": false },
"deployJumpbox": { "value": false },
"deployVM": { "value": false },
"deployNatGateway": { "value": false }

Write parameters files without BOM. On Windows, Out-File -Encoding utf8 adds a Byte Order Mark that causes az deployment to fail with Unable to parse parameter. Use either:

$content | Out-File -FilePath "spoke.parameters.json" -Encoding utf8NoBOM
# or
[System.IO.File]::WriteAllText("spoke.parameters.json", $content, [System.Text.UTF8Encoding]::new($false))

Part 3: Wiring the Citadel Spoke to the Azure APIM Hub

Add the hub’s APIM gateway URL and subscription key to the spoke’s App Configuration:

az appconfig kv set `
--name <spoke-appconfig-name> `
--key "APIM_GATEWAY_URL" `
--label "ai-lz" `
--value "https://<your-apim>.azure-api.net/openai" `
--yes
az appconfig kv set `
--name <spoke-appconfig-name> `
--key "APIM_SUBSCRIPTION_KEY" `
--label "ai-lz" `
--value "<YOUR_APIM_KEY>" `
--yes

Note: az cognitiveservices account connection create with a YAML file for creating an APIM connection in AI Foundry has known bugs in the current CLI version and will throw NoneType or codec errors. Create this connection via the Azure AI Foundry portal UI instead.

Validate End-to-End

$headers = @{
"Content-Type" = "application/json"
"api-key" = "<YOUR_APIM_KEY>"
}
$body = '{"messages":[{"role":"user","content":"Hello from the Citadel spoke!"}],"max_tokens":50}'
Invoke-RestMethod `
-Uri "https://<your-apim>.azure-api.net/openai/deployments/chat/chat/completions?api-version=2024-02-01" `
-Method POST -Headers $headers -Body $body

A successful response with content_filter_results, prompt_filter_results, and usage confirms the full Citadel loop: spoke → APIM gateway → Azure OpenAI → governance telemetry.

PowerShell output showing a successful end-to-end chat completion from the Citadel agent spoke through the Azure APIM Governance Hub, confirming spoke to hub routing, content filter results, and token usage tracking in Sweden Central.
End-to-end validation of the Citadel hub-and-spoke setup: a request from the agent spoke routes through the APIM Governance Hub in Sweden Central, returning a successful gpt-4o response, with Content Safety filtering and token usage tracking confirmed.

What the Microsoft Foundry Citadel Platform Deploys

After following this guide, your rg-ai-hub-gateway-dev resource group contains:

  • APIM gateway with content safety, PII redaction, token rate limiting, and cost attribution policies
  • Azure OpenAI with gpt-4o and text-embedding-3-large
  • Cosmos DB for usage event logging
  • Logic App for usage processing
  • Application Insights for gateway telemetry

Your rg-ai-spoke-dev resource group contains:

  • AI Foundry account and project
  • gpt-4o and text-embedding-3-large deployments
  • Cosmos DB with a conversations container
  • Key Vault, App Configuration, Storage Account, Application Insights, Log Analytics

App Configuration is fully populated with canonical keys (CHAT_DEPLOYMENT_NAME, AI_FOUNDRY_PROJECT_ENDPOINT, COSMOS_DB_ENDPOINT, and more) ready for agent applications to consume.

This Is a Dev Setup — Here Is What Changes for Non-Prod and Production

The configuration above is a starting point, not a production blueprint. Key differences when moving up the environment stack:

APIM SKU. Developer SKU has no SLA and no VNet support. Switch to Premium SKU for non-prod and production. This significantly increases cost and deployment time but enables private networking, multi-region, and availability zones.

Network isolation. For production, set networkIsolation=true and wire the spoke VNet to your hub VNet via peering (hubIntegrationHubVnetResourceId). This requires coordinating private DNS zones across the hub and spoke. The template supports bringing existing DNS zones via the existingPrivateDnsZone* parameters.

AI Search. Re-enable deploySearchService and deployAAfAgentSvc for non-prod and production. If Sweden Central remains capacity-constrained on Standard SKU, deploy Search to a paired region (East US 2 works well) using the searchServiceLocation parameter.

Bastion and Jump VM. For production with networkIsolation=true, re-enable deployBastion and deployJumpbox so operators can access resources inside the private VNet without public endpoints.

Separate parameter files per environment. Maintain spoke.parameters.dev.json, spoke.parameters.nonprod.json, and spoke.parameters.prod.json with environment-specific values. Use a deployment pipeline (GitHub Actions or Azure DevOps) to apply them consistently.

Model versions. Pin specific model versions in parameters files and validate availability in your target region before each deployment. Azure OpenAI model lifecycle moves fast; versions retire on 18-month cycles, and regional availability varies.

Preview Caveats

Citadel is in active development. Several things you should expect to change:

The parameter schemas for both the hub and spoke accelerators will evolve. Parameters discovered missing or renamed in this guide will likely be reorganized again as the repos mature. Always check the actual main.bicep parameter definitions rather than relying on example files.

The az cognitiveservices account connection create CLI command for AI Foundry connections is incomplete at the time of writing. This will improve as the Foundry CLI surface area matures.

The citadel-v1 branch in the AI Hub Gateway repo is flagged as the recommended path for new deployments. By the time you read this, it may have become the default branch with a cleaner deployment experience.

Regional capacity for AI Search Standard SKU fluctuates. Sweden Central is a high-demand region for AI workloads plan for capacity constraints in any SKU beyond Basic for dev scenarios.

Conclusion

Citadel gives you a credible, opinionated starting point for enterprise AI governance on Azure APIM as the AI gateway, AI Foundry as the agent runtime, Cosmos DB for conversation state, and App Configuration as the configuration backbone. Getting it running today requires navigating several rough edges: parameter schema inconsistencies, soft-delete cascades, model version deprecations, regional capacity constraints, and Windows-specific tooling issues.

None of these are blockers. They are the expected friction of working with a platform in active preview. The underlying architecture is sound, and the pieces that do work, APIM governance policies, Content Safety integration, App Config population, and AI Foundry project wiring deliver real value immediately.

If you are building an AI platform for your organization, a Citadel dev setup is a reasonable first step. Treat it as a learning environment to understand the architecture, validate the tooling, and build the parameter files you will need for non-prod and production. Then evolve it deliberately: add network isolation, re-enable Search and Agent Services as capacity allows, and adopt the Citadel contracts (AI Access Contract, AI Publish Contract) to formalize the hub-spoke integration as your agent portfolio grows.

The governance-velocity paradox Citadel sets out to solve is real. Getting the foundation right now, while it is still in preview and the patterns are malleable, is the right time to start.

Final note: This post reflects a hands-on deployment performed in June 2026. Given the pace of change in this space, verify all CLI commands, parameter schemas, and model versions against current documentation before applying them in your own environment.

Azure API Management Load Balancing and Circuit Breaker for AI Backends

Part 5 of 7 in the “APIM for AI Workloads” series

Azure API Management load balancing for AI workloads solves a problem that every team hits once they move beyond a single Azure OpenAI deployment: PTU capacity is finite, PAYG is a safety net, and when things go wrong on one backend, the rest of your workload should not notice. In Part 1 of this series, I described PTU vs. PAYG as a routing problem. This post is where we solve it.

The combination of backend pools, priority-based routing, and circuit breaker rules in APIM gives you a resilient AI gateway that handles three distinct failure modes: PTU saturation (too many tokens consumed against reserved capacity), regional outages, and transient backend errors. None of these requires changes to calling applications. APIM absorbs the complexity and presents a single stable endpoint.

Azure API Management Load Balancing: Backend Pools for AI

APIM’s backend pool feature lets you define a named group of AI backends and route to them as a unit. You reference the pool in the set-backend-service policy by its pool ID. When a request arrives, APIM selects a backend from the pool based on priority and weight, tracks health state via the circuit breaker, and retries on the next available member if the selected backend fails.

For AI workloads, the standard pattern uses two tiers. The first tier is your PTU deployment reserved capacity in a primary region, assigned priority 1. The second tier is a PAYG deployment in a secondary region, assigned priority 2. APIM routes all traffic to the PTU backend as long as the PTU backend is healthy. When PTU returns a 429 (capacity exceeded) error or becomes unreachable, the circuit breaker trips, and APIM automatically fails over to the PAYG backend.

Azure API Management load balancing backend pool with PTU primary PAYG overflow and circuit breaker tripped on unavailable backend
Diagram 1: APIM backend pool with three members. APIM backend pool with three members. The PTU backend (priority 1) handles normal load, while the PAYG backend (priority 2) absorbs overflow. After repeated 429 responses, Backend #3 has tripped its circuit breaker and is bypassed until the probe succeeds.

Priority determines the preference order: lower numbers are preferred. Weight applies when multiple backends share the same priority, distributing load proportionally between them. A common pattern for multi-region PTU deployments is two PTU backends at priority 1, each with a different weight reflecting their provisioned capacity, and a shared PAYG backend at priority 2 as the common overflow.

Circuit Breaker Configuration for Azure API Management AI Backends

The circuit breaker is what makes the backend pool resilient rather than just load-balanced. Without it, APIM continues routing to a saturated or unavailable backend on every request, each one failing with a 429 or timeout before falling back. The circuit breaker short-circuits that path: after a configurable number of failures within a time window, it marks the backend as OPEN and stops sending traffic to it entirely.

Azure API Management circuit breaker state machine showing closed open and half-open states for AI backend failover
Diagram 2: Circuit breaker state machine. CLOSED is normal operation. Exceeding the failure threshold trips the breaker to OPEN, bypassing the backend. After tripDuration seconds, APIM sends a single probe request to test recovery. Success returns to CLOSED; failure reopens the circuit.

The three circuit breaker states map directly to operational behavior:

CLOSED is the normal state. All requests are routed to the backend. Failures APIM counts failures within the configured interval, and the counter resets at the end of each interval if the number of failures remains below the threshold.

After enough failures to exceed the threshold, the breaker trips to OPEN. In this state, APIM bypasses the backend entirely, and APIM routes to the next available pool member without attempting the failed backend again. The tripDuration timer starts counting down immediately.

Once tripDuration elapses, the breaker enters HALF-OPEN and sends a single probe request to test recovery. A successful response transitions the backend back to CLOSED. A failure resets the timer and keeps the circuit OPEN.

For Azure OpenAI specifically, 429 should always be in your failureCondition alongside 503 and 504. A 429 from a PTU endpoint indicates that the provisioned throughput ceiling has been reached and the backend is temporarily unable to serve requests. That is exactly the condition you want to trip the circuit and fail over to PAYG, rather than returning errors to the caller.

Sizing Circuit Breaker Parameters for AI Workloads

The right circuit breaker parameters depend on your traffic pattern and how quickly you need failover to activate. A few practical guidelines:

threshold: For AI workloads, 3 to 5 failures is a reasonable starting point. PTU endpoints return 429 consistently when saturated, so you don’t need a high threshold to detect the condition. Setting it too high means you absorb too many failed requests before failing over.

interval: 60 seconds works well for most workloads. This is the window over which failures are counted. Shorter intervals are more sensitive to transient errors, while longer ones suit bursty traffic patterns where a few failures in a short window are expected.

tripDuration: 30 seconds is a sensible default. PTU capacity refreshes on a per-minute basis, so a 30-second trip duration gives the backend time to recover before the probe fires. For deployments where PTU saturation is a known recurring pattern, a longer trip duration (60 to 120 seconds) reduces the frequency of failed probes.

Retry Policy and Agentic Workload Considerations

Backend pool failover and circuit breaking handle backend-level failures, but you may also want a retry policy in your APIM inbound pipeline for transient errors that do not warrant a full circuit trip. The retry policy can be scoped to specific status codes and configured with a backoff interval, giving you a two-level resilience model: retry for transient errors, circuit break for sustained failures.

For agentic workloads specifically, failover behavior needs careful thought. A conversational agent mid-session that silently switches from a PTU to a PAYG backend will not notice the change at the model API level. But agentic pipelines with multiple sequential tool calls are more sensitive: a mid-pipeline failover can introduce latency spikes that cause timeouts in orchestration layers such as Azure Logic Apps or Semantic Kernel.

The practical mitigation is to expose the remaining token budget via the token limit policy variable from Part 3 and have the orchestration layer monitor it to proactively slow down before circuit breaking kicks in. Prevention is cheaper than recovery when the workload is stateful.

What’s Next in This Azure API Management for AI Series

Part 6 covers semantic caching: how APIM uses an embeddings model and Azure Managed Redis to serve cached responses for semantically similar prompts, reducing token consumption and latency without any changes to calling applications.

New Pricing Plan and Enhanced Networking for Azure Container Apps in Preview

Microsoft recently announced a new pricing plan and enhanced networking for Azure Container Apps in public preview.

Azure Container Apps is a fully managed environment that enables developers to run microservices and containerized applications on a serverless platform. It is flexible and can execute application code packaged in any container without runtime or programming model restrictions.

Earlier Azure Container Apps had a consumption plan featuring a serverless architecture that allows applications to scale in and out on demand. Applications can scale to zero, and users only pay for running apps.

In addition to the consumption plan, Azure Container Apps now supports a dedicated plan, which guarantees single tenancy and specialized compute options, including memory-optimized choices. It runs in the same Azure Container Apps environment as the serverless Consumption plan and is referred to as the Consumption + Dedicated plan structure. This structure is in preview.

Mike Morton, a Senior Program Manager at Microsoft, explains in a Tech Community blog post the benefit of the new plan:

It allows apps or microservice components that may have different resource requirements depending on component purpose or development stack to run in the same Azure Container Apps environment. An Azure Container Apps environment provides an execution, isolation, and observability boundary that allows apps within it to easily call other apps in the environment, as well as provide a single place to view logs from all apps.

At the Azure Container Apps environment scope, compute options are workload profiles. The default workload profile for each environment is a serverless, general-purpose profile available as part of the Consumption plan. For the dedicated workload profile, users can select type and size, deploy multiple apps into the profile, use autoscaling to add and remove nodes and limit the scaling of the profile.

Source: https://techcommunity.microsoft.com/t5/apps-on-azure-blog/azure-container-apps-announces-new-pricing-plan-and-enhanced/ba-p/3790723

With Container Apps, one architect has another compute option in Azure besides App Service and Virtual Machines. Edwin Michiels, a Tech Customer Success Manager at Microsoft, answered in a LinkedIn post the difference between Azure Container Apps and Azure Apps Service, which offer similar capabilities:

In terms of cost, Azure App Service has a pricing model based on the number of instances and resources used, while Azure Container Instances and Azure Kubernetes Service are billed based on the number of containers and nodes used, respectively. For small to medium-sized APIs, Azure App Service may be a more cost-effective option, while for larger or more complex APIs, Azure Container Instances or Azure Kubernetes Service may offer more flexibility and cost savings.

The Consumption + Dedicated plan structure also includes optimized network architecture and security features that offer reduced subnet size requirements with a new /27 minimum, support for Azure Container Apps environments on subnets with locked-down network security groups and user-defined routes (UDR), and support on subnets configured with Azure Firewall or third-party network appliances.

The new pricing plan and enhanced networking for Azure Container Apps are available in the North Central US, North Europe, West Europe, and East US regions. Billing for Consumption and Dedicated plans is detailed on the Azure Container Apps pricing page.

Lastly, the new price plan and network enhancements are discussed and demoed in the latest Azure Container Apps Community Standup.

My Experience with Microsoft Excel During IT Projects

Throughout my extensive career in IT, I often worked with Microsoft Excel. One of my first projects was to leverage Excel to create documentation for a telco’s site surveys. I built a solution with Visual Basic for Applications, a programming language for Excel, and all the other Microsoft Office programs like Word and PowerPoint. With VBA, I could generate multiple worksheets in a Workbook filled with static and dynamic data – from a user’s input or configuration file. Once populated with data and rendered, the Workbook was converted to a Portable Document Format (PDF).

Over the last couple of years, I have had other projects involving Excel. In this post, I will dive into the details of implementations (use cases) concerning Excel Workbooks. One project involved processing Excel files in a Container running on an Azure Kubernetes Service (AKS) cluster, the other generating an Excel Workbook for reporting purposes, orchestrated by an Azure Logic App.

Use Case – Processing an Excel Workbook in a Container

The use case was as follows. In short, I was working on a project for a client a few years ago that required processing a standardized Excel template that their customers could provide for enrichment. The data in the excel file needed to end in a database for further processing (enrichment) so that it could be presented back to them.  The diagram below shows the process of a customer uploading an Excel file via an API. The API would store the Excel in an Azure storage container and trigger code inside a container responsible for processing (parsing the Excel to JSON). The second container had code persist the data in SQL Azure.

Use Case 1

The code snippet (as an example) responsible for processing the Excel file:

For creating the Excel Workbook and its sheet with data, I found the EPPlus library, a spreadsheet library for the .NET framework and .NET core. In the project, I imported the EPPlus NuGet package – specifically, I used the ExcelPackage class.

Now let’s move on to the second use case.

Use Case – Generating an Excel Report in Azure

In a recent project for another customer, I had to generate a report of products inside D365 that needed to be an Excel File (a workbook containing a worksheet with data). The file had to be written to an on-premises file share to allow the target system to consume it. The solution I built was using a Logic App to orchestrate the project of generating the Excel file.

Below you see a diagram visualizing the steps from triggering a package in D365 until the writing of the Excel file in a file share on-premises.

Use Case 2

The steps are:

  1. Logic App triggering a package in D365 (schedule trigger).
  2. Executing the package to retrieve and export data to a SQL Azure Database.
  3. Query by the same Logic App that triggered the package to retrieve the data from the SQL Azure Database.
  4. Passing the data to (the result of the query) to an Azure Function, which will create an Excel Workbook with one sheet containing the data in a given format. The function will write the Excel to an Azure Storage container.
  5. Subsequently, the Logic App will download and write the file to the on-premises file share (leveraging the On-Premises Data Gateway – ODPGW).

The sequence diagram below shows the flow (orchestration) of the process.

Sequence diagram

And below is a part of the Logic App workflow definition resembling the sequence diagram above.

The code snippet (as an example) in the Azure Function responsible for creating the Excel file:

For the creation of the Excel Workbook and sheet with data, I used NPOI – an open-source project which can help you read/write XLS, DOC, and PPT file extensions. In Visual Studio, I imported NPOI NuGet Package. The package covers most of the features of Excel like styling, formatting, data formulas, extracting images, etc. In addition, it does not require the presence of Microsoft Office. Furthermore, I used the StorageAccountClass to write the Excel file.

Conclusion

Microsoft Excel is a popular product available for decades and used by millions of people ranging from businesses heavily relying on Excel to home users for basic administration. Moreover, in IT, Excel is used in many scenarios such as project planning, environment overviews, project member administration, reporting, etc. As said earlier, I have encountered Microsoft Excel various times in my career and built solutions involving the product. The two use-cases are examples of that.

In the first example, I faced a challenge finding a library that supported .NET Core 2.0. I found EPPlus, which did the job for us after experimenting with it first. In the second example, the cost and simplicity were the benefits of using the NPOI library. There were constraints in the project to use solutions with a cost (subscription-based or one-off). Furthermore, the solution proved to be stable enough to generate the report.

Note that the libraries I found are not the only ones available to work with Excel. For instance, SpreadsheetGear, and others, which are listed here. In Logic Apps, you can find connectors that can do the job for you, such as CloudMersive (API you connect to convert, for instance, CSV to Excel).

I do feel with code you have the most flexibility when it comes to dealing with Excel. A standard, of-the-shelve can do the job for you, however, cost (licensing) might be involved or other considerations. What you choose in your scenarios depends on the given context and requirements.