Bit of Technology

  • Archive
  • About Me
    • Advertise
    • Disclaimer
  • Speaking
  • Contact

Part 5: Hosting an MCP Server in ASP.NET Core with Streamable HTTP

October 8, 2026 By Taiseer Joudeh Leave a Comment

This is the fifth part of Building MCP Servers in .NET for AI Agents. The topics we’ll cover are:

  • What is the Model Context Protocol? An Introduction for .NET Developers
  • Building Your First MCP Server in C#
  • MCP Tools, Resources and Prompts in .NET
  • Wiring MCP Tools to Azure SQL and External APIs
  • Hosting an MCP Server in ASP.NET Core with Streamable HTTP (This Post)
  • Building an MCP Client and AI Agent in .NET
  • Securing an MCP Server with Microsoft Entra ID
  • Deploying an MCP Server to Azure Container Apps
  • Connecting an MCP Server to Microsoft Foundry Agent Service
  • Observability, Cost Control and MCP Security

The source code for this tutorial is available on GitHub.

Hosting an MCP Server in ASP.NET Core with Streamable HTTP

Our server has worked for three parts, and it has one limitation we’ve never had to face. It only runs when VS Code starts it, on the same machine as VS Code, as a child process that nothing else can reach.

That was the right trade for learning. stdio needs no port, no hosting, no certificate and no security. It was the shortest path from nothing to a working server, and it kept the first three parts about the protocol rather than about infrastructure.

It’s also the end of the road. Part 7 puts Microsoft Entra ID in front of this server, and you can’t authenticate a pipe. Part 8 deploys it to Azure Container Apps, and you can’t deploy a process that only exists while an editor is open. Then Part 9 connects it to Microsoft Foundry, which runs in Azure and cannot see your laptop.

So in this post the server becomes a web application. The tools, resources and prompts don’t change at all, and that’s the part worth watching.

Why stdio runs out of road

stdio works by having the host launch your server as a child process. Requests arrive on standard input, responses go out on standard output. There’s no network, no port and no address.

Four things follow from that, and each one is both a feature and a wall.

  1. One client per process. The host owns the process it started. A second client means a second process, with its own memory, its own connection pool and its own copy of everything you cached. Ten people using your server means ten copies of it.
  2. One machine. Standard input and output don’t cross a network. The client has to be able to launch the executable, which means it has to be on the same box.
  3. A lifetime you don’t control. The server exists because the host wants it to. Close VS Code and it’s gone. Nothing can call it when you aren’t looking at it.
  4. No identity. There’s no request, so there’s nothing to carry a token and no place to put one. Every call is anonymous by construction, and the server cannot tell you apart from anyone else because there is nobody else.

None of that matters for a server that reads files on your disk. All of it matters for one that submits expense reports against a shared database.

There’s a fifth thing that’s easy to miss. With stdio, stdout is the protocol. That’s why Part 2 had this line, which always looked slightly odd:

C#
1
builder.Logging.AddConsole(options => options.LogToStandardErrorThreshold = LogLevel.Trace);

Every log line had to go to stderr, because anything written to stdout would be parsed as a protocol message and break the connection. One stray Console.WriteLine in a library you depend on was enough to take the server down. That constraint disappears in this post.

Isn’t this just a REST API?

If you’ve built ASP.NET Core APIs, the obvious question is why MCP needs a transport specification at all. You have HTTP, you have JSON, you have Minimal APIs. Why not GET /reports and be done?

Because the two solve different problems.

A REST API is designed for a client that was written against it. Somebody read your documentation, knew that GET /reports?employee=x exists, and wrote code that calls it. The knowledge of what to call lives in the client.

An MCP server is designed for a client that has never seen it before. The model discovers what’s available at runtime, reads the descriptions we spent Part 3 and Part 4 writing, and decides what to call. The knowledge of what to call lives in the server, in the descriptions.

That difference produces requirements a REST API doesn’t have:

  1. Discovery is part of the protocol. tools/list is not an endpoint we wrote. It’s a method every MCP server answers the same way, which is what lets a client connect to a server nobody told it about.
  2. One endpoint, many methods. MCP is JSON-RPC. Tools, resources and prompts all arrive at the same URL, distinguished by a method field in the body rather than by a route.
  3. A response can be more than one message. A tool that takes thirty seconds can report progress while it runs. HTTP’s one request, one response shape doesn’t cover that on its own.

That third requirement is what shapes the transport, and it explains the design choice that surprises people most.

What Streamable HTTP is

MCP defines two transports. stdio is one, and Streamable HTTP is the other. It is one endpoint, and in our case that endpoint is /mcp.

Client to server, a POST. Every message the client wants to send is a POST to that URL with a JSON-RPC body. Listing tools, calling one, reading a resource, fetching a prompt, all of it. The method in the body decides what happens.

Server to client, a stream. Here’s the surprise. The response to that POST does not come back as application/json. It comes back as text/event-stream, the same Server Sent Events format the browser EventSource API uses. Even a single reply arrives framed:

C#
1
2
3
4
5
HTTP/1.1 200 OK
Content-Type: text/event-stream
 
event: message
data: {"result":{"tools":[ ... ]},"id":1,"jsonrpc":"2.0"}

The framing is there because of the third requirement above. One POST can produce a progress notification, then another, then a result. SSE gives the server a way to write several messages down one open response. When there’s only one message to send you still get the framing, because the client shouldn’t have to handle two different response shapes.

A GET opens a channel the other way. A server that keeps sessions can have things to say when the client hasn’t asked anything. A GET on the endpoint opens an SSE stream for that purpose. We’ll see in a moment why ours returns a 405 instead.

Sessions, where they exist, live in a header. Mcp-Session-Id comes back from the server on the first response and the client repeats it on every subsequent request. It’s the MCP equivalent of a cookie.

Note: there’s an older HTTP transport in MCP with two separate endpoints, one for POST and one for SSE. You’ll find it in samples and blog posts. It’s superseded, and the C# SDK marks it obsolete with a pointed warning that it has no request backpressure and should only be used with completely trusted clients. Don’t start a new server there.

The initialize handshake, and why it’s going away

Every MCP conversation used to start the same way. The client sends initialize with the protocol version it speaks. The server replies with its own version and a capabilities object saying which of tools, resources, prompts and logging it supports. Only after that exchange can the client list anything.

I sent that request asking for the current protocol revision, and got this back:

C#
1
2
3
4
{"error":{"code":-32022,
  "message":"Protocol version '2026-07-28' is not available through the initialize handshake.",
  "data":{"supported":["2024-11-05","2025-03-26","2025-06-18","2025-11-25"],
          "requested":"2026-07-28"}}}

Ask for 2025-11-25 and the handshake works exactly as it always did:

C#
1
2
3
{"result":{"protocolVersion":"2025-11-25",
  "capabilities":{"logging":{},"prompts":{},"resources":{},"tools":{}},
  "serverInfo":{"name":"BitOfTech.Expenses.Mcp","version":"1.0.0.0"}}}

So the handshake hasn’t been removed from the SDK. It’s been removed from the current revision of the protocol. Two specification changes did it. SEP-2575 replaced initialize with a method called server/discover, and SEP-2567 removed the Mcp-Session-Id header. Under 2026-07-28 every request carries its own protocol version, in the MCP-Protocol-Version header on HTTP and in a _meta field on every transport.

A client doesn’t have to choose between the two worlds. The C# SDK client prefers 2026-07-28, probes the server with server/discover, and falls back to the initialize handshake when that probe fails. You get the newest revision against a new server and the old one against an old server, and you write nothing either way.

I checked the other half of that directly rather than taking the error message’s word for it. I asked a freshly started server for tools/list with no initialize first, and got all five tools back.

If you’ve been reading MCP material written in the last year, this is the single biggest thing that’s changed under it. Nearly every explanation of MCP opens with the handshake. It’s worth knowing that the newest revision doesn’t have one before you go looking for why your client isn’t doing it.

We come back to this in Part 6, where we can watch our own client run that probe.

Stateless by default, and what that costs

The C# SDK has three session modes. Stateless is the default. The other two exist for compatibility, and the compiler says so if you reach for them:

C#
1
2
3
4
'HttpServerTransportOptions.IdleTimeout' is obsolete: 'Stateful Streamable HTTP mode is a
back-compat-only escape hatch for 2025-11-25 protocol revision clients and earlier. Set
HttpServerTransportOptions.SessionMode = HttpServerSessionMode.Stateless (the default as
of the 2026-07-28 protocol revision) for new code.'

What state are we talking about? In stateful mode the server keeps a live session object per client. That session holds the negotiated protocol version, the client’s capabilities, any subscriptions the client has taken out on resources, and the open SSE stream for pushing messages. It sits in memory in one process.

That’s the problem. It sits in memory in one process. If your server runs on three replicas behind a load balancer, every request from that client has to land on the replica holding its session. That’s session affinity, and it’s the thing that makes scaling a stateful service annoying. Lose the replica and you lose the session.

Stateless keeps nothing. Every POST carries everything needed to answer it, the server answers it, and nothing is remembered. No session id comes back, because there’s nothing to identify.

What you get is a server that scales sideways with no thought at all. Part 8 runs this on Azure Container Apps with more than one replica, no sticky sessions, no distributed cache and no configuration to make any of that work. It’s the single biggest reason the deployment post is short.

What you give up is real, and it’s better shown than described. A GET on the endpoint gets you:

C#
1
405 Method Not Allowed

No session means no stream, and no stream means the server can’t start a conversation. If you need server-initiated messages, the stateful modes are there, and you’ll be arranging affinity in your load balancer to use them.

For a server like ours, which answers questions and writes rows, stateless is the right answer and it’s free.

Important note: this section and the previous one are the same decision seen twice. A server running in stateful mode refuses the 2026-07-28 revision, because that revision has no sessions to hand out. Staying stateless is what makes the newest protocol revision available to the clients that connect to you.

It’s a normal ASP.NET Core endpoint

One thing that isn’t obvious from the MCP documentation, and matters a lot for the rest of this series.

app.MapMcp("/mcp") registers ordinary ASP.NET Core endpoints. They show up in the routing table like anything else. You can see it in the server’s own log:

C#
1
2
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'MCP Streamable HTTP | HTTP: POST /mcp/'

Everything you already know applies to it:

  1. Middleware runs. Authentication, authorisation, CORS, rate limiting, response compression. The pipeline is the pipeline.
  2. Logging is normal logging. Microsoft.AspNetCore.Hosting.Diagnostics logs every request to the MCP endpoint the same way it logs any other.
  3. Dependency injection is normal DI. Your tool classes are resolved per request.
  4. You can map other endpoints beside it. Anything else the application needs to serve is one more MapGet.

That’s why Part 7 is a shorter post than you might expect. Putting Entra ID in front of an MCP server is mostly putting Entra ID in front of an ASP.NET Core endpoint.

Making the change

Four files change, one is new, and none of them are in Tools, Resources or Prompts.

Step 1: Add the HTTP package

The MCP packages are split deliberately. ModelContextProtocol is the core plus hosting, and it has no idea ASP.NET Core exists, which is what let our console server stay small. The HTTP transport lives in its own package, so now we add it.

C#
1
2
3
cd src/BitOfTech.Expenses.Mcp
 
dotnet add package ModelContextProtocol.AspNetCore --version 2.2.0

It takes a dependency on ModelContextProtocol at exactly the same version, so the two always move together. That’s worth knowing when you upgrade.

Step 2: Flip the project to the web SDK

This is the line that turns a console application into a web application. It does more than it looks like, because changing the SDK brings in the ASP.NET Core shared framework, and a few things we were referencing by hand are already in there.

The whole csproj afterwards:

XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Project Sdk="Microsoft.NET.Sdk.Web">
 
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.12" PrivateAssets="all" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.12" />
    <PackageReference Include="ModelContextProtocol" Version="2.2.0" />
    <PackageReference Include="ModelContextProtocol.AspNetCore" Version="2.2.0" />
  </ItemGroup>
 
  <ItemGroup>
    <Content Include="Resources\policy.md" CopyToOutputDirectory="PreserveNewest" />
  </ItemGroup>
 
</Project>

Four things removed, and each for its own reason:

  1. <OutputType>Exe</OutputType> is implied by the web SDK, so it’s noise.
  2. Microsoft.Extensions.Hosting is in the ASP.NET Core shared framework.
  3. Microsoft.Extensions.Http is too, so the Frankfurter client from Part 4 keeps working with one less package reference.
  4. The appsettings.json content line had to go, and this one will bite you if you miss it. The web SDK already includes **/*.json as content, so leaving ours in gives you a duplicate item error at build time.

Step 3: Rewrite Program.cs

Two calls do the actual work. WithHttpTransport() registers the transport and MapMcp puts it on a route. Everything else in this file you’ve seen in Part 4, and I’ve kept it in the same order so the difference is easy to spot.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using BitOfTech.Expenses.Mcp.Data;
using BitOfTech.Expenses.Mcp.Services;
using Microsoft.EntityFrameworkCore;
 
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // The working directory belongs to whoever started us, so appsettings.json has to be
    // read from the folder the binary is in rather than the current directory.
    ContentRootPath = AppContext.BaseDirectory
});
 
builder.Services.AddDbContext<ExpensesDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("ExpensesDb")));
 
builder.Services.AddHttpClient<FrankfurterClient>(client =>
{
    client.BaseAddress = new Uri("https://api.frankfurter.dev/");
    client.Timeout = TimeSpan.FromSeconds(10);
});
 
builder.Services
    .AddMcpServer()
    .WithHttpTransport()
    .WithToolsFromAssembly()
    .WithResourcesFromAssembly()
    .WithPromptsFromAssembly();
 
var app = builder.Build();
 
app.MapMcp("/mcp");
 
app.Run();

What we have done here is the following:

  1. Host.CreateApplicationBuilder became WebApplication.CreateBuilder. Same configuration system, same dependency injection, now with Kestrel underneath.
  2. WithStdioServerTransport() became WithHttpTransport(). That is the entire transport change.
  3. app.MapMcp("/mcp") mounts the endpoint. I’m using /mcp rather than the root, so the root stays free for anything else you want to map there.
  4. The three ...FromAssembly() calls are untouched. Your tools have no idea any of this happened.
  5. ContentRootPath survives from Part 4, moved onto WebApplicationOptions. You still can’t assume the working directory. dotnet run --project src/... sets it to wherever you typed the command, which is usually the repository root.

And one deletion worth pausing on. This line is gone:

C#
1
2
// stdout carries the MCP protocol itself, so every log line must go to stderr.
builder.Logging.AddConsole(options => options.LogToStandardErrorThreshold = LogLevel.Trace);

stdout isn’t the protocol any more, so logging goes back to being ordinary logging. That constraint shaped every part of the server until now, and it’s just gone.

Note: Part 4 made a point of the fact that each tool call gets its own dependency injection scope, which is what makes a scoped DbContext safe. That still holds here, for a simpler reason. In stateless mode every tool call is its own HTTP request, and ASP.NET Core creates a scope per request. I checked it the same way as last time and got four distinct DbContext instances from four calls.

Step 4: Pin the port

The server needs a predictable address, because the next step puts that address in a configuration file. Add Properties/launchSettings.json:

C#
1
2
3
4
5
6
7
8
9
10
11
12
{
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Two things about this file.

  1. It’s development only. It isn’t published and it isn’t used in a container. In Part 8 the container listens on whatever port it’s given.
  2. localhost is deliberate. Bind to 0.0.0.0 and your unauthenticated expense server is reachable by anything on the same network.

Step 5: Point VS Code at the endpoint

.vscode/mcp.json gets shorter, and the change is bigger than the line count suggests. VS Code is no longer launching anything. It’s connecting to something you run.

C#
1
2
3
4
5
6
7
8
{
  "servers": {
    "bitoftech-expenses": {
      "type": "http",
      "url": "http://localhost:5000/mcp"
    }
  }
}

Important note: your development loop is different from here on. Start the server yourself, in a terminal you keep open:

C#
1
dotnet run --project src/BitOfTech.Expenses.Mcp

Then reload the server from MCP: List Servers. If it isn’t running, VS Code has nothing to connect to and will say so.

That’s an extra thing to remember, and two things in exchange.

  1. You can see what’s happening. Every request to /mcp is logged in your terminal as it arrives. Debugging stdio meant fishing exceptions out of a VS Code output channel.
  2. The file lock problem from Part 4 is gone. Nothing starts the server behind your back, so nothing holds the executable open while you’re trying to build. You stop it, you build it, you start it.

Step 6: Watch the protocol

The server is now a normal HTTP endpoint, so you can talk to it with curl. Do this once even if you never do it again, because everything in Parts 6 through 9 sits on top of what you’re about to see.

C#
1
2
3
4
curl.exe -i http://localhost:5000/mcp `
  -H "Content-Type: application/json" `
  -H "Accept: application/json, text/event-stream" `
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Note: that’s PowerShell 7, where the JSON goes inside single quotes and needs no escaping. On Windows PowerShell 5.1 the argument passing rules are different and you’ll need to escape the inner double quotes. I use curl.exe rather than curl so PowerShell doesn’t route it to its own alias.

The reply, trimmed:

C#
1
2
3
4
5
HTTP/1.1 200 OK
Content-Type: text/event-stream
 
event: message
data: {"result":{"tools":[{"name":"search_expense_reports", ... }]},"id":1,"jsonrpc":"2.0"}

Three things in that exchange, all of which we predicted above and none of which you have to take on trust:

  1. There was no initialize. We asked a cold server for its tool list and it answered.
  2. There’s no Mcp-Session-Id in the response headers. Nothing to identify, because nothing is being kept.
  3. The content type is text/event-stream. The framing is there whether or not we need it.

Now drop text/event-stream from that Accept header and run it again:

C#
1
2
{"error":{"code":-32000,
  "message":"Not Acceptable: Client must accept both application/json and text/event-stream"}}

That’s a 406, and it’s the error you’re most likely to hit while writing your first client by hand. The transport insists you can handle both shapes before it will talk to you. It’s a good error message, but only if you know what it’s telling you.

Step 7: Check that nothing else broke

This is the largest structural change in the series, so it’s worth proving rather than assuming that Parts 2, 3 and 4 still work.

C#
1
2
3
4
curl.exe -s http://localhost:5000/mcp `
  -H "Content-Type: application/json" `
  -H "Accept: application/json, text/event-stream" `
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_expense_reports","arguments":{"employeeName":"Sara"}}}'

Both of Sara’s reports come back, out of Azure SQL, over HTTP. Swap the method for resources/list, resources/read, prompts/list or prompts/get and they all answer too.

Then use it properly. Ask Copilot the same three tool question from Part 4 and watch the requests arrive in your terminal while it answers.

What didn’t change

Worth listing, because it’s the argument for MCP being a protocol rather than a library.

  1. No tool changed. Not a parameter, not a description, not a line of validation.
  2. No resource or prompt changed. The policy resource and the report template both answer over HTTP without knowing anything happened.
  3. The database code didn’t change. ExpensesDbContext is registered the same way and used the same way.
  4. The contracts didn’t change. The shapes we designed in Part 4 to keep responses small are doing the same job.

Everything that makes this server useful was written against MCP, not against stdio. That’s the whole point, and it’s why it was worth spending three parts on the protocol before touching hosting.

One thing to be clear about

This endpoint has no authentication. None at all.

Anyone who can reach port 5000 can list your tools and call them, and that includes submit_expense_report, which writes to your database and cannot be undone. On localhost that’s contained. It would not be, anywhere else.

That’s why Part 7 comes before Part 8 in this series. We put Entra ID in front of the server first and deploy it second. Publishing an open endpoint that can spend money and promising to secure it in a later post isn’t something I’m willing to write.

One more thing, because it’s specific to running a server on your own machine. Your machine is not a private space. Anything on it can call this endpoint, including code you didn’t write, and that’s why the MCP specification tells you to validate the Host header on incoming requests. We come back to it in Part 10.

Summary

The transport change was two method calls and an SDK attribute. Everything that makes this server worth connecting to carried over untouched, which is the best argument I can make for MCP being a protocol rather than a framework.

Two things I’d take away. The first is that stateless is the default now, the stateful modes are compatibility, and that decision is why Part 8 scales without you doing anything. The second is that the initialize handshake, which every MCP explanation opens with, isn’t part of the current revision. If you’re reading older material and wondering why your client doesn’t do it, that’s why.

In Part 6 we stop borrowing somebody else’s client. We build a .NET agent that connects to this endpoint, gets the tool list, hands it to a model, and runs the call loop itself. That’s where the descriptions we’ve been writing since Part 2 stop being something we hope works and start being something we can watch.

The source code for this tutorial is available on GitHub.

Follow me on X @TJoudeh and on LinkedIn

References:

  • Model Context Protocol specification
  • MCP C# SDK on GitHub
  • Minimal APIs in ASP.NET Core
  • The ASP.NET Core host
  • Use multiple environments in ASP.NET Core

Filed Under: AI, Azure, MCP Tagged With: .NET 10, AI Agents, ASP.NET Core, Kestrel, MCP, Model Context Protocol, Streamable HTTP

Part 4: Wiring MCP Tools to Azure SQL and External APIs

October 6, 2026 By Taiseer Joudeh Leave a Comment

This is the fourth part of Building MCP Servers in .NET for AI Agents. The topics we'll cover are: What is the Model Context Protocol? An Introduction for .NET Developers Building Your First MCP Server in C# MCP Tools, Resources and … [Continue reading]

Filed Under: AI, Azure, MCP Tagged With: .NET, AI Agents, Azure CLI, Azure SQL, C#, EF Core, Entra ID, MCP, Model Context Protocol

Part 3: MCP Tools, Resources and Prompts in .NET

October 2, 2026 By Taiseer Joudeh Leave a Comment

This is the third part of Building MCP Servers in .NET for AI Agents. The topics we'll cover are: What is the Model Context Protocol? An Introduction for .NET Developers Building Your First MCP Server in C# MCP Tools, Resources and Prompts … [Continue reading]

Filed Under: AI, MCP Tagged With: .NET, AI Agents, C#, GitHub Copilot, MCP, Model Context Protocol, tool design, VS Code

Part 2: Building Your First MCP Server in C#

October 2, 2026 By Taiseer Joudeh Leave a Comment

This is the second part of Building MCP Servers in .NET for AI Agents. The topics we'll cover are: What is the Model Context Protocol? An Introduction for .NET Developers Building Your First MCP Server in C# (This Post) MCP Tools, … [Continue reading]

Filed Under: AI, MCP Tagged With: .NET, .NET 10, AI Agents, C#, Claude Desktop, GitHub Copilot, MCP, Model Context Protocol, stdio, VS Code

Part 1: What is the Model Context Protocol? An Introduction for .NET Developers

October 2, 2026 By Taiseer Joudeh Leave a Comment

This is the first part of Building MCP Servers in .NET for AI Agents. The topics we'll cover are: What is the Model Context Protocol? An Introduction for .NET Developers (This Post) Building Your First MCP Server in C# MCP Tools, Resources … [Continue reading]

Filed Under: AI, MCP Tagged With: .NET, AI Agents, C#, GitHub Copilot, MCP, Model Context Protocol, VS Code

Invoking Dapr Services in Azure Container Apps using gRPC – Part 2

November 9, 2022 By Taiseer Joudeh Leave a Comment

aca-dapr-grpc-featuredimage

In the previous post, I covered how to deploy a gRPC service to Azure Container App, and how to create a simple minimal Web API deployed to Azure Container Apps which acts as a gRPC client consuming the gRPC Service, In this post, I'll cover the 2 … [Continue reading]

Filed Under: ASP.NET 6, Azure Container Apps, Dapr, Microservices, Microservices Tagged With: grpc, Microservice

gRPC Communication In Azure Container Apps – Part 1

November 7, 2022 By Taiseer Joudeh 2 Comments

grpc-aca-featured

In the previous post, we have seen how two Azure Container Apps can communicate with each other synchronously without and with Dapr using service-to-service invocation and services discovery using HTTP protocol. In this post, I will cover how 2 … [Continue reading]

Filed Under: ASP.NET 6, Azure Container Apps, Microservices Tagged With: grpc, Microservice

Azure Container Apps Volume Mounts using Azure Files – Part 12

October 16, 2022 By Taiseer Joudeh 3 Comments

Container Apps Azure Files

This is the twelfth part of Building Microservice Applications with Azure Container Apps and Dapr. The topics we’ll cover are: Tutorial for building Microservice Applications with Azure Container Apps and Dapr - Part 1 Deploy backend API … [Continue reading]

Filed Under: ASP.NET 6, Azure Container Apps, Bicep, Microservices Tagged With: Azure Files, Azure Storage

Deploy Meilisearch into Azure Container Apps

October 9, 2022 By Taiseer Joudeh 1 Comment

meilisearch-azure container apps

Last week I was working on a proof of concept solution which includes a service responsible to provide a simple front-facing search component for a hardware tools website. During the research, I stumbled upon various options and I wanted to try … [Continue reading]

Filed Under: ASP.NET 6, Azure Container Apps, Bicep, Microservices Tagged With: ARM, Azure Files, IaC, Meilisearch

Monitor Microservices App using Azure Managed Grafana

September 29, 2022 By Taiseer Joudeh Leave a Comment

Grafana Featured Image

This post is inspired by the amazing article Monitoring Azure Container Apps With Azure Managed Grafana written by Paul Yu. In his post, Paul walks us through provisioning Azure Managed Grafana instance and Container Apps using Terraform AzAPI … [Continue reading]

Filed Under: ASP.NET 6, Azure Container Apps, Dapr, Managed Grafana, Microservices Tagged With: Grafana, KEDA

  • 1
  • 2
  • 3
  • …
  • 7
  • Next Page »

About Taiseer

Husband, Father, Consultant @ MSFT, Life Time Learner... Read More…

Buy me a coffeeBuy me a coffee

Recent Posts

  • Part 5: Hosting an MCP Server in ASP.NET Core with Streamable HTTP
  • Part 4: Wiring MCP Tools to Azure SQL and External APIs
  • Part 3: MCP Tools, Resources and Prompts in .NET
  • Part 2: Building Your First MCP Server in C#
  • Part 1: What is the Model Context Protocol? An Introduction for .NET Developers

Blog Archives

Recent Posts

  • Part 5: Hosting an MCP Server in ASP.NET Core with Streamable HTTP
  • Part 4: Wiring MCP Tools to Azure SQL and External APIs
  • Part 3: MCP Tools, Resources and Prompts in .NET
  • Part 2: Building Your First MCP Server in C#
  • Part 1: What is the Model Context Protocol? An Introduction for .NET Developers

Tags

.NET AI Agents AJAX AngularJS API API Versioning ASP.NET ASP.NET 6 Authentication Autherization Server Azure Azure Active Directory B2C Azure AD B2C Azure Container Apps Azure Storage C# Code First Dapr Dependency Injection Entity Framework Foursquare API GitHub Copilot jQuery JSON JSON Web Tokens JWT MCP Microservice Model Context Protocol Ninject OAuth OData Redis Resource Server REST RESTful Single Page Applications SPA Token Authentication Tutorial VS Code Web API Web API 2 Web API Security Web Service

Search

Copyright © 2026 · eleven40 Pro Theme on Genesis Framework · WordPress · Log in