0

I'm trying to send a POST request to the Microsoft Graph API to make a Sharepoint tab. According to the docs, I need to POST an HTTP request to https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-id}/tabs using this format:

{
  "displayName": "SharePoint",
  "teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/2a527703-1f6f-4559-a332-d8a7d288cd88"
}

I'm trying to follow what was suggested in another StackOverflow question (How to make HTTP POST web request) using:

public static async Task CreateSharepointTab(string teamsID, string channelId)
{
    var responseString = await $"https://graph.microsoft.com/v1.0/teams/{teamsID}/channels/{channelId}/tabs"
        .PostUrlEncodedAsync(new { displayName = "Sharepoint tab", teamsApp @odata.bind = "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/2a527703-1f6f-4559-a332-d8a7d288cd88" })
        .ReceiveString();
}

So teamsApp@odata.bind as a property name returns an error because of the @ sign. How can I escape it/get around it and properly pass it to my POST request so it's accepted?

Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
fourOhFour
  • 77
  • 9

2 Answers2

1

Flur's PostUrlEncodedAsync() method will POST the object as application/x-www-form-urlencoded, not application/json (which is what Graph requires). You want to use PostJsonAsync() for this.

As for the property name, C# does not support @ as a property name. You will need to send it as a string (or a JObject as RB suggested).

var responseString = await $"https://graph.microsoft.com/v1.0/teams/{teamsID}/channels/{channelId}/tabs"
    .PostJsonAsync("{ \"displayName\" = \"Sharepoint tab\", \"teamsApp@odata.bind\" = \"https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/2a527703-1f6f-4559-a332-d8a7d288cd88\" }")
    .ReceiveString();

All that said, you should save yourself a lot of headaches and avoid hand-crafting HTTP calls to Graph by using the Microsoft Graph .NET SDK. It handles all of the orchestration and serialization bits for you.

Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
  • Thanks for that suggestion Marc! I actually have been using the Microsoft Graph Graphclient package like you suggested for my other requests - creating groups and teams. For those, the Graphclient has stuff like 'graphClient.Groups.Request().AddAsync(group)' but for adding tabs, the docs online mention only that HTTP request I entered above. I'm trying to go about adding tabs like this 'await graphClient.Teams[teamsID].Channels[channelId].Tabs.Request().AddAsync(content)', but that's messing up as my content seems to be in the wrong format. Any direction on this? – fourOhFour Mar 18 '20 at 18:23
  • I get a 'cannot convert from 'System.Net.Http.StringContent' to 'Microsoft.Graph.TeamsTab' error. – fourOhFour Mar 18 '20 at 18:25
0

One simple approach is to just not use the fancy extension methods and construct more of the request yourself.

For example

var body = new JObject(); // JSON.Net is pulled into your application via Flurl anyway.
body["displayName"] = "SharePoint";
body["teamsApp@odata.bind"] = "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/2a527703-1f6f-4559-a332-d8a7d288cd88";

// Construct the content yourself. Make sure you set the correct content type: 
// It's probably "application/x-www-form-urlencoded"
var content = new StringContent(
    body.ToString(), 
    Encoding.UTF8,
    "application/x-www-form-urlencoded");

// Now do a simple POST.
var result = await "http://example.org".PostAsync(content);

You might need to use a tool like Fiddler to capture a good HTTP request and make sure you are not missing any important headers or similar, but you won't go far wrong this way.

RB.
  • 36,301
  • 12
  • 91
  • 131