json string not being parsed correctly - c#

I'm working with a Rest Api. I send the username and password when the user clicks on login from an MVC App but I keep getting back error
400 Bad Request
Now I've debugged through the code and realized the string being parsed to the api is as follows
"{\"username\":\"email#somedomain.com\",\"password\":\"mypassword\"}"
So I decided to remove the \ from the string as follows:
string jsonString = JsonString(model.Email, model.Password);
string data = jsonString.Replace(#"\", "");
But for whatever reason the back slashes are not being removed :/ The string should be parsed as:
{"username":"email#somedomain.com","password":"mypassword"}
Here is the full code:
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("myurl");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
string jsonString = JsonString(model.Email, model.Password);
string data = jsonString.Replace(#"\", "");
HttpContent content = new StringContent(data, Encoding.UTF8, "application/json");
HttpResponseMessage messge = client.PostAsync("api/Account/Login", content).Result;
if (messge.IsSuccessStatusCode)
{
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
And the JsonString method is as follows:
private string UserString(string us, string ps)
{
var json = new JavaScriptSerializer().Serialize(
new
{
username = us,
password = ps
});
return json;
}
api/Account/Login method looks like this
[AllowAnonymous]
[Route("Login")]
public async Task<IHttpActionResult> Login(UserModel userModel)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityUser result = await _repo.FindUser(userModel.UserName, userModel.Password);
return Ok();
}
And find FindUser method looks like this
public async Task<IdentityUser> FindUser(string userName, string password)
{
IdentityUser user = await _userManager.FindAsync(userName, password);
return user;
}

You cannot remove \ characters. It is escape character for special characters that cannot be normal part of strings, in this case " is character for begining and end of strings. When you need to use " inside string you have to insert \ before that. So that the result is \". See c# specs here. The problem causing 400 is probably somewhere else. Can you provide your api/Account/Login method?

you can probably strip out a lot of code here.
using (var httpClient = new HttpClient())
{
httpClient.PostAsJsonAsync("<your full url>", new UserModel { Email = "whatever", Password = "password" });
}
PostAsJsonAsync will handle serializing the model, and setting up the http call.
PostAsJsonAsync is part of the Web Api Client Nuget package.
I would also set a breakpoint in the Login method to find out exactly what model error is the Login method.

Related

Add a member to Microsoft Teams using Graph API and delegated permissions

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.

Error converting JSON response from backend to type with JsonConvert.DeserializeObject

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

Spotify authorization login call in wrong url

I am working on a simple web app to display my currently playing song. I have set up a Spotify account an received a clientId and client secret.
I try to request the initial token, for further communication with the spotify api.
I am displaying the received login html, i try to log in, but nothing happens, it just says "There went something wrong ..." above the login form. At this point i checked the spotify dashboard and whitlisted all the local callback urls, but i am still getting this message an nothing is happening.
I checked the browser dev tools and saw something odd (at least i belive its odd).
The login call redirects to "https://losthost:5001/api/login" which leads to a 404.
public async Task<IActionResult> Connect()
{
var client = new HttpClient();
var clientId = "clientId";
var redirectUrl = HttpUtility.UrlEncode("http://localhost:5000/Spotify/Callback/");
var url = $"client_Id={clientId}&response_type=code&redirect_uri={redirectUrl}";
var result = await client.GetAsync($"https://accounts.spotify.com/authorize?{url}");
if (result.Content.Headers.ContentType.MediaType == "text/html"){
var spotifyLoginHtml = await result.Content.ReadAsStringAsync();
return new ContentResult()
{
Content = spotifyLoginHtml,
ContentType = "text/html",
};
}
else
{
//var accessToken = await result.Content.ReadAsStringAsync();
//return RedirectToAction("DevicesSelection");
}
return View();
}
I think my problem is the wrong login call from the spotify login html, but i dont know why this happens or how to fix it.
Edit:
Added image with initial error (Uncaught in promise) and wrong api/login call
The redirect_uri :
The URI to redirect to after the user grants or denies permission. This URI needs to have been entered in the Redirect URI whitelist that you specified when you registered your application. The value of redirect_uri here must exactly match one of the values you entered when you registered your application, including upper or lowercase, terminating slashes, and such.
Spotify provides article available that covers the authentication and authorization setup and flow step-by-step.
So that if http://localhost:5000/Spotify/Callback/ is your redirect url , you should firstly add the url to Redirect URI whitelist in dashboard :
And in your application you should have route matches http://localhost:5000/Spotify/Callback/ to get the code via query string , and then use code to acquire access token for accessing Spotify APIs . Here is a code sample :
class SpotifyAuthentication
{
public string clientID = "xxxxxxxxxxxxxxxxxxxxx";
public string clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
public string redirectURL = "https://localhost:44363/callback";
}
public class HomeController : Controller
{
SpotifyAuthentication sAuth = new SpotifyAuthentication();
[HttpGet]
public ContentResult Get()
{
var qb = new QueryBuilder();
qb.Add("response_type", "code");
qb.Add("client_id", sAuth.clientID);
qb.Add("scope", "user-read-private user-read-email");
qb.Add("redirect_uri", sAuth.redirectURL);
return new ContentResult
{
ContentType = "text/html",
Content = #"
<!DOCTYPE html>
<html>
<head>
<meta charset=""utf-8"">
<title>Spotify Auth Example</title>
</head>
<body>
<button>Authenticate at Spotify</button>
</body>
</html>
"
};
}
[Route("/callback")]
public ContentResult Get(string code)
{
string responseString = "";
if (code.Length > 0)
{
using (HttpClient client = new HttpClient())
{
Console.WriteLine(Environment.NewLine + "Your basic bearer: " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(sAuth.clientID + ":" + sAuth.clientSecret)));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(sAuth.clientID + ":" + sAuth.clientSecret)));
FormUrlEncodedContent formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", sAuth.redirectURL),
new KeyValuePair<string, string>("grant_type", "authorization_code"),
});
var response = client.PostAsync("https://accounts.spotify.com/api/token", formContent).Result;
var responseContent = response.Content;
responseString = responseContent.ReadAsStringAsync().Result;
}
}
return new ContentResult
{
ContentType = "application/json",
Content = responseString
};
}
}
Code reference : https://github.com/bmsimons/dotnet-core-spotify-authentication and blog .
And of course you can use Spotify middleware , here is a code sample .

Web API json responds faulty json [duplicate]

I am trying to fix an ASP.NET WebAPI method where a Json response is required. However it's returning a string instead.
Initially it was returing XML format, but I've added this line to the mvc code in App_Start\WebApiConfig.cs in order to return Json by default.
config.Formatters.Remove(config.Formatters.XmlFormatter);
We've updated the c# method as follows to use NewtonSoft:
public string Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
string resp = DynAggrClientAPI.openSession(userid, pwd);
JsonSerializer ser = new JsonSerializer();
string jsonresp = JsonConvert.SerializeObject(resp);
return resp;
}
The resp var is coming back as a string type:
"{status:\"SUCCESS\",data:[\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\"]}"
and jsonresp var looks like this :
"\"{status:\\\"SUCCESS\\\",data:[\\\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\\\"]}\""
and in Chrome's F12 dev tools, the data object is :
""{status:\"SUCCESS\",data:[\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\"]}""
and in Console tools, the result of angular.fromJson(data) :
"{status:"SUCCESS",data:["4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d"]}"
I would appreciate some advice on how to properly return the Json object, and NOT in any string type.
UPDATE
By intercepting the resp var, and using Mr. Chu's suggestion below, I can successfully achieve a nice clean Json object on the client.
The key is that resp needs to contains double quotes around both key:value pairs:
public HttpResponseMessage Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
string resp = DynAggrClientAPI.openSession(userid, pwd);
resp = "{\"status\":\"SUCCESS\",\"data\":[\"194f66366a6dee8738428bf1d730691a9babb77920ec9dfa06cf\"]}"; // TEST !!!!!
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(resp, System.Text.Encoding.UTF8, "application/json");
return response;
}
in Chrome console, the response is :
Object {status: "SUCCESS", data: Array[1]}
data: Array[1]
status: "SUCCESS"
__proto__: Object
resp is already a JSON string, but it is not valid JSON (the keys are not wrapped in quotes ("). If it is returned to angular, the JavaScript JSON.parse() method is unable to deserialize it. However, you can use JSON.NET in deserialize it to a JObject and serialize it again into valid JSON and create your own HttpResponseMessage...
public HttpResponseMessage Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
var jObject = JObject.Parse(resp);
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(jObject.ToString(), Encoding.UTF8, "application/json");
return response;
}
Or you can just return the JObject and have Web API serialize it for you...
public JObject Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
var jObject = JObject.Parse(resp);
return jObject;
}
In either case, the Web API call should return this JSON, which is now valid...
{
"status": "SUCCESS",
"data": [
"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d"
]
}
In the angular code, you'd have to dig out the session id which is stored in an array called data...
userService.openUserSession(rzEnvJson).then(function (response) {
var sessionResponse = response.data; // or simply response, depending if this is a promise returned from $http
$rootScope.rgSessionVars.sessionID = sessionResponse.data[0];
});
The key to what is going on here is in the comment made by Mike Cheel; serialization is happening twice, once in the OP's code and once by Asp.Net WebAPI. That is why a string is returned instead of a Json object.
I was encountering the exact same thing. Here is a hello world example showing the problem. I first did something like this:
[Route("getall")]
public string GetAllItems()
{
var result = new
{
x = "hello",
y = "world"
};
return JsonConvert.SerializeObject(result);
}
I then tried to so something like this, thinking that I needed to return IHttpActionResult to resolve this:
[Route("getall")]
public IHttpActionResult GetAllItems()
{
var result = new
{
x = "hello",
y = "world"
};
return Ok(JsonConvert.SerializeObject(result));
}
Both these controller actions gave me a string rather than the Json object that I was wanting; so I go this:
"{\"x\":\"hello\",\"y\":\"world\"}"
Finally I saw the comment by Mike and realized that I needed to return the .Net object directly and just let WebAPI handle the serialization. So instead of returning this:
return Ok(JsonConvert.SerializeObject(result));
return this:
return Ok(result);
Then I got the result that I was expecting:
{"x":"hello","y":"world"}
I don't see what this has to do with AngularJS, but your problem is simple. Your data object is JSON encoded. So you could almost certainly access data.JsonRequestBehavior and it would be 1. But your Data field inside it is AGAIN JSON-encoded. You need to decode it before trying to use it - it's just a string when you get to this callback:
var myData = angular.fromJson(data.Data);
console.log(myData.data);
Note that your data.Data object is itself another wrapper - an array. You almost certainly want myData.data[0] to go into that sessionID field...
These other solutions weren't working for me, but I was able to get something like this to work:
[HttpGet]
public async Task Get(CancellationToken cancellationToken)
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
await using (Stream contentStream = await DynAggrClientAPI.openSessionStreamAsync(userid, pwd, cancellationToken))
{
Response.StatusCode = (int)HttpStatusCode.OK;
Response.ContentType = "application/json";
await contentStream.CopyToAsync(Response.Body, cancellationToken);
}
}
I had a similar problem (raw json in string, like resp) and this worked fine for me in .Net 6. I haven't checked previous versions.
[HttpGet]
public IActionResult Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
return Content(resp, "application/json"):
}

C# JSON POST connect (Method not allowed)

I have problem with connect to JSON server.
In user-manual:
The Interface is implemented as a standard HTTP Service. Using the service requires an authentication through the “Login” method. A Session Id is returned on success which has to be passed on every function call unless otherwise stated.
The expected data format when sending or receiving data is JSON.
All data must be passed using POST.
The session Id is of type Guid
Example:
Login
Description: Used to authenticate a user.
Url: /Login
Signature: Guid Login(string id, string username, string password)
END OF MANUAL
I wrote this code:
var webAddr = "https://xxx/Login";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "{\"Login\":[{"
+ "\"id\" : 1213213,"
+ "\"username\" : asdasdasd,"
+ "\"password\" : \"adasdsadasd\","
+ "}]}";
streamWriter.Write(json);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
MessageBox.Show(result.ToString());
}
And message is: Method not allowed.
How can I send and recive data from this serwer?
You are formatting your JSON incorrectly. The JSON should look like this:
{"id":"1213213","username":"asdasdasd","password":"adasdsadasd"}
Notice: quotes around each name and value. And "Login" should not be part of the JSON.
However, the problem is really that you are doing this all manually. Instead, let .NET format the JSON for you and handle the HTTP request. To do this, create a structure for the arguments:
class Login
{
public string id { get; set; }
public string username { get; set; }
public string password { get; set; }
}
Use NuGet to add references to "Json.Net" and "Microsoft ASP.NET Web API Client Libraries." Now you can write this:
static async Task Login()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://www.censored.de/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromSeconds(30);
Login l = new Login() { id = "12345", password = "abcde", username = "safsdfasdf" };
var sTemp = JsonConvert.SerializeObject(l); // DEBUG: Just so I can see the JSON
var response = await client.PostAsJsonAsync("/censored/Service.svc/Login", l);
Guid g;
if (response.IsSuccessStatusCode)
{
g = await response.Content.ReadAsAsync<Guid>(); // This gives you the GUID
}
//DEBUG:
// var rawResponse = await response.Content.ReadAsStringAsync();
// Console.WriteLine(response);
}
}
Notice that I used "async" and "await" keywords. If you are not familiar with calling an async function, you can change the "await" line to this temporarily:
var response = await client.PostAsJsonAsync("/censored/Service.svc/Login", l).Result;
This results in a 400 Bad Request with this message.
{"ErrorMessage":"Die Anmeldedaten sind ungültig.","StackTrace":null}
Which Google tells me means that the credentials are wrong. I assume that is the response one would expect with this user/password combination.

Categories

Resources