“When a Teams webhook request is received” not working from C# HttpClient

I was recently trying to send a message from my application (an Azure Function) to a Teams channel.

The current recommended way (by Microsoft) to do this is via a “Teams Workflow”, which is layer over top of Microsoft Power Automate, which is a layer over Logic apps.

Here’s my Teams Workflow:

Here’s the same Teams Workflow in Power Automate:

Here’s a slightly different one, which I wrote as an Azure Logic App. Here the first step is “When a HTTP request is received”:

In both cases, I was able to trigger the Power Automate / Logic app fine from Postman, but when I tried from C# code using HttpClient.PostJsonAsync it failed.

The only difference I could see between the Postman request and the HttpClient request was that HttpClient was sending a transfer-encoding=chunked header.

I re-wrote my code to use PostAsync instead, and then it worked fine.


using HttpClient client = new();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var card = AdaptiveCard.ExceptionCard("parcel.changed.v1", "I800100081376", "dev", new InvalidOperationException());

var url = "https://prod-31.australiasoutheast.logic.azure.com:443/workflows/dda945b5337d48....";

// await client.PostAsJsonAsync(url, card); // this sends a transfer-encoding=chunked header, which Power Automate & Logic Apps doesn't handle

var json = JsonSerializer.Serialize(card);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
await client.PostAsync(url, content);

Windows Authentication with a .NET 6 typed HttpClient

Recently at a client’s site I had to write a new API which calls a downstream web API which was secured with Kerberos authentication, or something, I think. Not sure.

I dug up the code for an existing .NET Framework solution which calls the legacy service. The old code looks like this:

WebRequest myWebRequest = WebRequest.Create(serverUrl);

// Set 'Preauthenticate' property to true. Credentials will be sent with the request.
myWebRequest.PreAuthenticate = true;
myWebRequest.Credentials = new NetworkCredential(user, password);

using (WebResponse myWebResponse = myWebRequest.GetResponse())
using (Stream receiveStream = myWebResponse.GetResponseStream())
{
    byte[] data = Helper.ReadFully(receiveStream);

I didn’t know what a WebRequest’s NetworkCredential is – but a bit of Fiddler investigation revealed the following header is being sent:

Authorization: Negotiate TlRMTVNTUAADAAAA...

I wasn’t sure how to call this with .NET 6, and it’s not documented in the HttpClient documentation. Fortunately, I eventually found my way to good ol’ Rick Strahl, who has a solution at https://weblog.west-wind.com/posts/2021/Nov/27/NTLM-Windows-Authentication-Authentication-with-HttpClient

In my solution I’m using typed HttpClients which is different to Rick’s custom HttpClient factory implementation. My working solution looks like this:

builder.Services.AddHttpClient<ILegacyClient, LegacyClient>(
    client =>
    {
        client.DefaultRequestHeaders.UserAgent.ParseAdd("My great Api");
        client.BaseAddress = new Uri(builder.Configuration["Clients:Legacy:BaseUri"]);
    }).ConfigurePrimaryHttpMessageHandler(() =>
    {
        var username = builder.Configuration["Clients:Legacy:Username"];
        var password = builder.Configuration["Clients:Legacy:Password"];

        var credentials = new NetworkCredential(username, password);
        return new HttpClientHandler { Credentials = credentials, PreAuthenticate = true };
    });

Easy once you know how.