I am trying to simply add a member (who is already in the organization) to a specific Microsoft Team. The observerID is the id of the the member that I want to add and teamID is is the ID of the specific Team. I am using delegated permission with TeamMembers.ReadWrite.All enabled.
My code looks like this:
string json = $#"
{{
""#odata.type"": ""#microsoft.graph.aadUserConversationMember"",
""roles"": [""member""],
""user#odata.bind"": ""https://graph.microsoft.com/beta/users({observerID})""
}}";
var body = new StringContent(json, Encoding.UTF8, "application/json");
Console.WriteLine("Add observer");
return await protectedApiCallHelper.CallWebApiAsync(WebApiUrlTeams + teamID + "/members", accessToken, body);
public async Task<JObject> CallWebApiAsync(string webApiUrl, string accessToken, HttpContent content)
{
if (!string.IsNullOrEmpty(accessToken))
{
var defaultRequestHeaders = HttpClient.DefaultRequestHeaders;
if (defaultRequestHeaders.Accept == null || !defaultRequestHeaders.Accept.Any(m => m.MediaType == "application/json"))
{
HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
defaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
HttpResponseMessage response = await HttpClient.PostAsync(webApiUrl, content);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
JObject result = JsonConvert.DeserializeObject(json) as JObject;
return result;
}
}
return null;
}
My problem is that the http call fails with the status code 400; 'Bad Request'. I have tried again and again to find any issues with my call but I can't seem to find the problem. When I Console.WriteLine the json I use for the body it looks like this:
{
"odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": ["member"],
"user#odata.bind": "https://graph.microsoft.com/beta/users(d52c2663-1c41-401b-8015-1216f0e68960)"
}
And the url looks like: "https://graph.microsoft.com/beta/teams/a9f9ac33-fba5-4ce2-9515-8c498c70af85/members" and when I try the call through Postman it still returns a error code 400.
Does anyone have any insight on what might be wrong?
In fact, this error is very simple. Reporting 400 is usually a parameter error. Your json file is missing the special symbols # and ". I tested it locally and worked for me.
Related
Having issues with my code [ Throwing an Unhandled exception: System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (Bad Request) ] when trying to connect to WebApi
This is my first time working with await/async methods, but I am needing to return
string msgTask = await response.Content.ReadAsStringAsync(); return msgTask;
At first my Console.WriteLine(await response.Content.ReadAsStringAsync(); returned:
BadRequest {"error":"Password must be at least 8 characters, with at least 1 of each alpha, number and special characters"}
But then I inserted this check: response.EnsureSuccessStatusCode(); which Throws the System.Net.Http.HttpRequestException
Full [top-level styled] Code Below (I am only using Console.WriteLine() to help with debugging, final code will only have return msgTask;) :
HttpRequest.GetHttpResponse();
await WattTime.PostRequest.RegisterUser();
public class HttpRequest
{
public static HttpClient client = new();
public static void GetHttpResponse()
{
// GetRequestMethod to use later
}
}
namespace WattTime
{
class PostRequest : HttpRequest
{
public static async Task<string> RegisterUser()
{
string Url = "https://api2.watttime.org/v2/register";
Dictionary<string, string> parameters = new()
{
{"username", "TestUser" },
{"password", "Password#1" },
{"email", "testuser#yahoo.com" },
{"org", "XYZ" },
};
var jsonDictionary = JsonConvert.SerializeObject(parameters);
var content = new StringContent(jsonDictionary, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(Url, content);
response.EnsureSuccessStatusCode();
string msgTask = await response.Content.ReadAsStringAsync();
Console.WriteLine(msgTask);
return msgTask;
}
}
}
UPDATE I changed the format of data being sent to the API var data = #"{ ""username"": ""TestUser900"", ""password"": ""Summer$21"", ""email"": ""test65349#yahoo.com""}";
and added var postData = JsonConvert.SerializeObject(data); var postData2 = JsonConvert.DeserializeObject(postData);
If I use Console.WriteLine(await response.Content.ReadAsStringAsync()) I receive the Status and User Created, but if I use return response.StatusCode.ToString(); nothing returns
Looks like you need to change your test data. I tried to run your data in Online API testing tool and it returned the same error and later when I changed the json data it returned status 200 OK. Also I observed that every time you need to send unique data or its returning error.
Your issue may be the # symbol in your data. If sent in the URL it will need to be URL encoded. See this list of characters that need encoding https://www.w3schools.com/tags/ref_urlencode.asp
You can use HttpUtility.UrlEncode to do this on your jsonDictionary variable, HttpServerUtility and WebUtility classes also have this static method.
Change this response.EnsureSuccessStatusCode(); to this
if(response.IsSuccessStatusCode){
//Code here
}
I am working on this helper method that will call an API using the body section. I am passing in the url and data in the model. Then I SerializeObject the model, but I am not sure what to return I get the error message about the response.Content is not found.
public static async System.Threading.Tasks.Task<HttpResponse> HttpClientHandlerAsync(string url, object model)
{
var fullUrl = apiUrl + url;
var json = JsonConvert.SerializeObject(model);
var data = new StringContent(json, Encoding.UTF8, "application/json");
Client.DefaultRequestHeaders.Add("Accept", "*/*");
Client.DefaultRequestHeaders.Authorization
= new AuthenticationHeaderValue("Bearer", "token");
var response = await Client.PostAsync(fullUrl, data);
return response;
}
Add await in front of your
await Client.PostAsync(fullUrl, data);
Because you're trying to get content of Task
I am not sure what to return I get the error message about the response.Content is not found.
Set a breakpoint and hover over the response to see the status code. You could have a 500 server error, authentication error etc.
Furthermore
using (var client = new HttpClient())
Do not do this. It doesn't work the way you think it does, it will starve your connection pool and eventually throw an exception. You need to define the HttpClient somewhere and continue to reuse the same instance.
Further reading if you care https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
So I am having this weird problem with deserializing a response from my BackEnd, The request works fine and the BackEnd succesfully responds with a result.
This is the error I get:
'Error converting value "{"Succes":true,"AuthKey":"$2a$13..."}" to type 'FrontEnd.LoginUserResponse'. Path '', line 1, position 96.'
The code I am using to make the HTTP call and deserialize the string:
public async Task<bool> loginUser(LoginUserData login)
{
HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(login), Encoding.UTF8);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage responseMessage = await httpClient.PostAsync("http://ip/webBackEnd/api/user/login", httpContent);
string response2 = responseMessage.Content.ReadAsStringAsync().Result;
LoginUserResponse response = JsonConvert.DeserializeObject<LoginUserResponse>(response2);
if (response.Succes)
{
return true;
}
else { return false; }
}
I tried making a response2 to check the value and I have noticed it does something weird with 3 backslashes. This might be the reason why this is occuring.
This is response2 that visual studio shows when I click the magnifying glass:
"{\"Succes\":true,\"AuthKey\":\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\"}"
When I hover on visual studio:
https://imgur.com/a/jUyLz6d
This is the Class that it is converting to
public class LoginUserResponse
{
[JsonProperty("succes")]
public bool succes { get; set; }
[JsonProperty("authkey")]
public string authkey { get; set; }
}
The Backend code:
[HttpPost]
[Route("login")]
public string Login([FromBody]LogInData logInData)
{
IReadUser.LogInRequest request = new IReadUser.LogInRequest(logInData);
IReadUser.LogInResponse backResponse = readUser.logIn(request);
LogInResponse response = new LogInResponse();
response.succes = backResponse.Succes;
response.authkey = backResponse.AuthKey;
return JsonConvert.SerializeObject(response);
}
EDIT // SOLUTION
Ok so, the front-end was fine, it was my backend code sending a double serialised string. I used
return JsonConvert.SerializeObject(response);
When I also could have used
return response;
So if you every get an error like this, it's probably the backend doubling up on the serialization.
Thanks for all the help!
Couple of things:
1. you should await responseMessage.Content.ReadAsStringAsync():
public async Task<bool> loginUser(LoginUserData login)
{
var httpContent = new StringContent(JsonConvert.SerializeObject(login), Encoding.UTF8);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var responseMessage = await httpClient.PostAsync("http://ip/webBackEnd/api/user/login", httpContent);
var response2 = await responseMessage.Content.ReadAsStringAsync();
var response = JsonConvert.DeserializeObject<LoginUserResponse>(response2);
return response.Succes
}
And 2. Based on your image it looks like the response from your backing service is being serialized twice.
1:
"{\"Succes\":true,\"AuthKey\":\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\"}"
2:
"\"{\\\"Succes\\\":true,\\\"AuthKey\\\":\\\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\\\"}\""
now to deserialize you have to do it twice
var s = JsonConvert.DeserializeObject<string>(response2);
var response = JsonConvert.DeserializeObject<LoginUserResponse>(s);
Probably best to fix the service if that's actually what is happening
I have create gandi api code for create domain and for that i have write below code, but it show me 400 bad request error
public async System.Threading.Tasks.Task<JsonResult> InsertDomain(DomainDetails domainDetails)
{
HttpResponseMessage response = new HttpResponseMessage();
try
{
var url = "https://api.gandi.net/v5/domain/domains";
using ( var client = new HttpClient() )
{
var json = new JavaScriptSerializer().Serialize(domainDetails);
HttpContent HttpContent = new StringContent(json, Encoding.UTF8, "application/json");
var MyHttpClient = new HttpClient();
MyHttpClient.DefaultRequestHeaders.Add("authorization", GANDI_API_Key);
response = await MyHttpClient.PostAsync(url, HttpContent);
}
}
catch ( Exception ex )
{
throw;
}
return Json(new { result = response }, JsonRequestBehavior.AllowGet);
}
but when i try to pass same data using postman then it's working fine below code is my postman data
Body
{
"fqdn":"dedasdom1906.com",
"owner":
{
"city":"Paris",
"given":"Alice",
"family":"Doe",
"zip":"75001",
"country":"FR",
"streetaddr":"5 rue neuve",
"phone":"+33.123456789",
"state":"FR-J",
"type":"0",
"email":"alice#example.org"
}
}
Header
authorization : Apikey
Content-Type : application/json
I havent worked with this endpoint, but you are missing the return type.
the next thing i would try is to paste json string directly in the StringContent.
please paste the correct string content(rename the variable)
if none of this help you, please give more details.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
For the https://api.gandi.net/v5/domain/domains endpoint, use HTTP GET (HttpClient.GetAsync) to retrieve a list of your domains. Use HTTP POST (HttpClient.PostAsync) to create a new domain.
If you're trying to POST JSON, I would use the PostAsJsonAsync method, example here:
static async Task<Uri> CreateProductAsync(Product product)
{
HttpResponseMessage response = await client.PostAsJsonAsync(
"api/products", product);
...
Also note your auth header needs to start with "apikey" though it looks like you have that working. Curl example:
curl -X GET \
https://api.gandi.net/v5/domain/domains \
-H 'authorization: Apikey your-api-key'
https://api.gandi.net/docs/domains/
I am trying to understand the VSO git API. I have made Get requests succesfully like so:
using (var response = client.GetAsync(
uri).Result)
{
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
ResponseInfo.Text = JsonHelper.FormatJson(responseBody);
}
I do this after setting client.DefaultRequestHeaders for Basic Authentication and Mediatype to application/json.
For post requests, the VSO Documentation shows this:
I understand that the parameters are JSON. However, I'm not sure how to pass that into the post request in C#. I have tried the following:
string content = #"{
""refUpdates"": [
{
""name"": ""refs/heads/master"",
""oldObjectId"": ""*old object id*""
}
],
""commits"": [
{
""comment"": ""Test commit"",
""changes"": [
{
""changeType"": ""edit"",
""item"": {
""path"": ""/foo.txt""
},
""newContent"": {
""content"": ""test"",
""contentType"": ""rawtext""
}
}
]
}
]
}";
var stringToJson= new JavaScriptSerializer();
var JSONoutput = stringToJson.Deserialize<object>(content);
StringContent stringContent = new StringContent(JSONoutput.ToString(), Encoding.UTF8, "application/json");
and then I pass that in to
using (var response = client.PostAsync(uri, stringContent).Result)
{
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
I get a 400 Bad Request error. Am I passing in my parameters correctly? Essentially I am taking the string version of what the tutorial gave me, convert it to JSON, deserialize it, convert it to HTTPContent, and pass that into PostAsync. I can't think of another way to do it.
Thank you for your time!
Turns out I can just do
StringContent stringContent = new StringContent(content, Encoding.UTF8, "application/json");
The string version of the JSON object is enough for StringContent.