Deserialize a JsonResult from C# - c#
I access a REST API with this code :
public async Task<IActionResult> NetExplorerAPI(string AdresseAPI, object Requete, RestSharp.Method Methode)
{
var client = new RestClient(AdresseAPI);
var request = new RestRequest();
request.Method = RestSharp.Method.Post;
request.AddJsonBody(Requete);
request.AddHeader("Accept", "application/json");
//request.AddHeader("Authorization", "Bearer a844024a4e744182aeaa62dd6347b9049f9ba35650339d2b9362e1bf03a92ac0");
//IRestResponse response = await client.ExecuteAsync(request);
RestResponse response = await client.ExecuteAsync(request);
JsonResult jr = new JsonResult(response);
return (jr);
}
I want to deserialize the JsonResult to get the token in a string :
{ "token": "med6RRIikrZ-2tua9jUa6pVZubnPvhqSH6wHvtkH42TNfJGXOaI-GioUKPvfbhP7XiGG6UgjCzUnJt87kwsljQBAKEb" }
But When I serialize the JsonResult I get a lot of items I don't need to :
string s = JsonConvert.SerializeObject(jr);
{"ContentType":null,"SerializerSettings":null,"StatusCode":null,"Value":{"ContentType":null,"SerializerSettings":null,"StatusCode":null,"Value":{"Request":{"AlwaysMultipartFormData":false,"MultipartFormQuoteParameters":false,"FormBoundary":null,"Parameters":[{"DataFormat":0,"ContentEncoding":null,"Name":"","Value":{"user":"sylvain.krier#protonmail.com","password":"S#r#line2004"},"Type":3,"Encode":false,"ContentType":"application/json"},{"Name":"Accept","Value":"application/json","Type":2,"Encode":false,"ContentType":null}],"Files":[],"Method":1,"Timeout":0,"Resource":"","RequestFormat":0,"RootElement":null,"OnBeforeDeserialization":null,"OnBeforeRequest":null,"OnAfterRequest":null,"Attempts":1,"CompletionOption":0,"ResponseWriter":null,"AdvancedResponseWriter":null},"ContentType":"application/json","ContentLength":103,"ContentEncoding":[],**"Content":"{\"token\":\"wlK4LIRpOxqKOwJ2Hs554l5-WI--IrqHW7TECZ3YtdS-RpzDuQGaQeLI0qjo8NzaSPhCUYaarBcXstrI5sPlXkwCmk9\"}"**,"StatusCode":200,"IsSuccessful":true,"StatusDescription":"Ok","RawBytes":"eyJ0b2tlbiI6IndsSzRMSVJwT3hxS093SjJIczU1NGw1LVdJLS1JcnFIVzdURUNaM1l0ZFMtUnB6RHVRR2FRZUxJMHFqbzhOemFTUGhDVVlhYXJCY1hzdHJJNXNQbFhrd0NtazkifQ==","ResponseUri":"https://patrimoine-click.netexplorer.pro/api/auth","Server":"Apache","Cookies":[],"Headers":[{"Name":"Date","Value":"Tue, 19 Jul 2022 06:40:36 GMT","Type":2,"Encode":false,"ContentType":null},{"Name":"Server","Value":"Apache","Type":2,"Encode":false,"ContentType":null},{"Name":"Pragma","Value":"no-cache","Type":2,"Encode":false,"ContentType":null},{"Name":"Cache-Control","Value":"no-store, must-revalidate, no-cache","Type":2,"Encode":false,"ContentType":null},{"Name":"X-NetExplorer-Version","Value":"7.4.4.12","Type":2,"Encode":false,"ContentType":null},{"Name":"Access-Control-Allow-Origin","Value":"*","Type":2,"Encode":false,"ContentType":null},{"Name":"X-UA-Compatible","Value":"IE=edge,chrome=1","Type":2,"Encode":false,"ContentType":null},{"Name":"Connection","Value":"close","Type":2,"Encode":false,"ContentType":null},{"Name":"X-Content-Type-Options","Value":"nosniff","Type":2,"Encode":false,"ContentType":null},{"Name":"Transfer-Encoding","Value":"chunked","Type":2,"Encode":false,"ContentType":null}],"ContentHeaders":[{"Name":"Expires","Value":"Thu, 19 Nov 1981 08:52:00 GMT","Type":2,"Encode":false,"ContentType":null},{"Name":"Content-Type","Value":"application/json","Type":2,"Encode":false,"ContentType":null},{"Name":"Content-Length","Value":"103","Type":2,"Encode":false,"ContentType":null}],"ResponseStatus":1,"ErrorMessage":null,"ErrorException":null,"Version":"1.1","RootElement":null}}}
I don't know how to get the "content" item.
From RestSharp's official QuickStart:
When using typed ExecuteAsync<T>, you get an instance of RestResponse<T> back, which is identical to RestResponse but also contains the T Data property with the deserialized response.
None of ExecuteAsync overloads throw if the remote server returns an error. You can inspect the response and find the status code, error message, and, potentially, an exception.
Extensions like GetAsync<T> will not return the whole RestResponse<T> but just a deserialized response. These extensions will throw an exception if the remote server returns an error. The exception will tell you what status code was returned by the server.
It looks like you have to choices:
Use client.ExecuteAsync and then response.Data
Use client.GetAsync<T>
For client.GetAsync you'll need a new type. For exmaple
public class MyTokenClass { public string token {get; set;} }
and then var t = await client.GetAsync<MyTokenClass>().
I think this is what you looking for let me know if you need something specific.
string theToken = JObject.Parse(response.Content)["token"].ToString();
When you get a Response object from ExecuteAsync, response is already deserialized into c# Response class, but Content is not. In this case Content contains a json string. You can parse the string to get a token (or deserialize it if you create a custom class)
This code will return { "token": "med6RRIikrZ-2tua9jUa6p...} as an ActionResult
string token = (string)JObject.Parse(response.Content)["token"];
return Ok( new { token = token});
You need to return JsonResult with the Content property of RestResponse:
return new JsonResult(response.Content);
Related
Sending a Post Request to register a new user to a Web API, but receiving 400 : BadRequest
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 }
Receiving json as string always null
With an endpoint like this: [HttpPost("[action]")] public async Task<ActionResult> Import([FromBody]string request) { var list = JsonConvert.DeserializeObject<List<RequestQuote>>(request); return NoContent(); } request always seems to be null. It worked for a little while earlier today but not sure what changed. Here is the client side where I do the call. var json = JsonConvert.SerializeObject(payload); var data = new StringContent(json, Encoding.UTF8, "application/json"); var response = client.PostAsJsonAsync($"{endpoint}/api/v1.0/BatchImport/Import", data); Payload is a List Even when using Import([FromBody] List<RequestQuote> request) I get the same issue.
There is a bug in the code, the data is serialized twice, the second time when you use PostAsJsonAsync. Try this var json = JsonConvert.SerializeObject(payload); var data = new StringContent(json, Encoding.UTF8, "application/json"); var response = await client.PostAsync($"{endpoint}/api/v1.0/BatchImport/Import", data); if (response.IsSuccessStatusCode) { var stringData = await response.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject<object>(stringData); } and action should be public async Task<ActionResult> Import([FromBody] List<RequestQuote> request)
If your controller has the [ApiController] attribute, you can put the data type you want to parse as the parameter of the method. I believe what is happening is that your program is trying to parse the JSON to a string type, which isn't what you want. You can try the code below, which should achieve what you're looking for. [HttpPost("[action]")] public async Task<ActionResult> Import([FromBody]List<RequestQuote> list) { // The parsed object should now be available here as "list" return NoContent(); } Alternatively, this post suggests pulling the body of the request directly. Either solution should be valid.
Adding Comment to Fortify Issue via REST API results in Content Encoding Error
I'm trying to add a comment to an issue inside Fortify. When I POST what I think is the correct JSON, I receive the response "{"message":"Content was incorrectly formatted (expected application/json; charset=utf-8).","responseCode":400,"errorCode":-20209}" However, if I use Fiddler to examine the message I'm POSTing and receiving the appropriate headers appear to be in place. What secondary issue could be causing this exception to be thrown? Fortify v18.10.0187 .NET v4.6.2 Newtonsoft.Json v9.0.0 public static string PostCommentIssue(FortifyComment fc) { var content = JsonConvert.SerializeObject(fc); var postUri = String.Format(Configuration.FortifyCommentsUri, fc.data.issueId); return WebServiceHelper.PostMessage(postUri, content); } public static string PostMessage(string url, string content) { HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, url); requestMessage.Headers.Add("Authorization", Configuration.FortifyAuthorization.ToHeader()); requestMessage.Content = new StringContent(content, Encoding.UTF8, JsonMediaTypeFormatter.DefaultMediaType.MediaType); HttpResponseMessage hrm = HttpClient.SendAsync(requestMessage).Result; hrm.EnsureSuccessStatusCode(); HttpContent hc = hrm.Content; return hc.ReadAsStringAsync().Result; } FortifyComment is just an object with the basic elements of a comment in it. It's based on the Fortify response given on a query (thus the inner data element). Using FortifyComment fc = new FortifyComment(); fc.data.issueId = defect.id; fc.data.comment = String.Format("TFS #{0}.", tfsNumber); FortifyHelper.PostCommentIssue(fc); I receive the 400 error. Screenshot of Fiddler intercept:
RestSharp "Error getting response stream (ReadAsync): ReceiveFailure Value cannot be null. Parameter name: src"
Hello all am trying to do a login to my xamarin api using RestSharp, the API ought to return status code 200 OK if the authentication works and status code 415 if the authentication fails(wrong password) and other codes depending on what the case scenario, but instead i get a status code 0 on all other case asides when the authentication pass(status code 200 ok), the source code below is how i implement //payload am sending to the api RequestPayload res = new RequestPayload(); res.appid = appid; res.data = data; res.method = "Login"; //convert to json object var MySerializedObject = JsonConvert.SerializeObject(res); string APIUrl = ""http://142.168.20.15:8021/RouteTask"; //create client RestClient client = new RestClient(APIUrl); //create request RestRequest request = new RestRequest(Method.POST); // set request headeer request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); //request.AddJsonBody(MySerializedObject); --i have also tried this request.AddParameter("application/json", MySerializedObject, ParameterType.RequestBody); request.JsonSerializer.ContentType = "application/json; charset=utf-8"; request.AddParameter("RequestSource", "Web", "application/json", ParameterType.QueryString); client.Timeout = 2000000; var response = client.Execute(request); // where the issue appears //RestResponse response = client.Execute(request); // i have tried this //IRestResponse response = client.Execute(request); // i have tried this if (response.IsSuccessful) { //use response data } on all scenerio it comes back with a StatusCode: 0, Content-Type: , Content-Length: 0) and errorMessage "Error getting response stream (ReadAsync): ReceiveFailure Value cannot be null. Parameter name: src" screenshot below indicate when the api call fails Response receieved when the authentication is valid
I was finally able to find a workaround for this. Bear with the long-winded response. The tags mention Xamarin, which is what I am working in as well - specifically with iOS. I think it may actually be a bug with Mono, but I didn't take it that far to confirm. The problem lies with the default way of copying the response buffer. In the RestSharp code, this is done by an extension method in MiscExtensions.cs called ReadAsBytes. It appears that with certain response buffers, the call to the Stream.Read method is failing. When this happens, the exception causes RestSharp to "shortcut" the rest of the processing on the response, hence the status code never gets filled in since it happens after the call to ReadAsBytes. The good news is RestSharp does give a way to replace this call to ReadAsBytes with one of your own. This is done via the ResponseWriter property on the IRestRequest object. If it has a function defined, it will bypass the ReadAsBytes call and call the function you gave it instead. The problem is, this is defined as an Action and you don't get a copy of the full response object, so it's somewhat useless. Instead you have to use the AdvancedResponseWriter property. This one includes both the response object and the response stream. But you still have to set the ResponseWriter property or it won't bypass the default handler and you'll still get the error. Ok, so how do you make this work? I ended up implementing it as a wrapper to RestClient so I wouldn't have to implement the code all over the place. Here's the basic setup: public class MyRestClient : RestClient { public MyRestClient(string baseUrl) : base(baseUrl) { } public override IRestResponse Execute(IRestRequest request) { request.ResponseWriter = s => { }; request.AdvancedResponseWriter = (input, response) => response.RawBytes = ReadAsBytes(input); return base.Execute(request); } private static byte[] ReadAsBytes(Stream input) { var buffer = new byte[16 * 1024]; using (var ms = new MemoryStream()) { int read; try { while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } return ms.ToArray(); } catch (WebException ex) { return Encoding.UTF8.GetBytes(ex.Message); } }; } } The ReadAsBytes method is actually just a copy/paste of the RestSharp ReadAsBytes method with the addition of a try/catch. If it fails, it returns the exception reason in to the response buffer. This may or may not be what you want, so modify as needed. You may also need to override other methods for Execute, but in my case this is the only one we're using so it was enough. So far this seems to be doing the trick for me. Perhaps if someone got ambitious they could trace it all the way in to Mono to try and see what it doesn't like about the stream, but I don't have the time for it at the moment. Good luck!
OK so after toying around with RestSharp for a bit, i realize just as #steve_In_Co mentioned earlier there were compatibility issues with MONO (we presume this is a bug) so i did it in a basic way using the .Net HTTP library and it works for me, so in case someone is still looking for a way out, find the working .net http implementation code below. //payload am sending to the api RequestPayload res = new RequestPayload(); res.appid = appid; res.data = data; res.method = "Login"; //convert to json object var MySerializedObject = JsonConvert.SerializeObject(res); string APIUrl = ""http://142.168.20.15:8021/RouteTask"; //create basic .net http client HttpClient client = new HttpClient(); client.BaseAddress = new Uri(APIUrl); // this was required in the header of my request, // you may not need this, or you may need to adjust parameter //("RequestSource","Web") or you own custom headers client.DefaultRequestHeaders.Add("RequestSource", "Web"); // this class is custom, you can leave it out connectionService = new ConnectionService(); //check for internet connection on users device before making the call if (connectionService.IsConnected) { //make the call to the api HttpResponseMessage response = await client.PostAsJsonAsync(ApiConstants.APIDefault, res); if (response.IsSuccessStatusCode) { string o = response.Content.ReadAsStringAsync().Result; dynamic payload = JsonConvert.DeserializeObject(o); string msg = payload["valMessage"]; resp.a = true; resp.msg = payload["responseDescription"]; } else { string o = response.Content.ReadAsStringAsync().Result; dynamic payload = JsonConvert.DeserializeObject(o); resp.a = false; resp.msg = payload["response"]; } }
Post using HttpClient & Read HttpResponseMessage status
I am posting to an API using HttpClient and getting back the HttpResponseMessage. I am reading the status code from the reply but I it's always 200 Posting: var json = JsonConvert.SerializeObject(loginDto); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); var client = new HttpClient(); var response = await client.PostAsync("http://localhost:57770/api/Account/Login", stringContent); I am replying from API the HttpResponseMessage: return new HttpResponseMessage(HttpStatusCode.Unauthorized); But when I read the response, it's always 200 How can I achieve this?
Asp.Net Core no longer recognizes HttpResponseMessage as part of the pipeline. This means it will be treated like any other returned model and serialized as content. Hence the 200 OK status. The API controller action should return IActionResult derived result. [HttpPost] public IActionResult SomeAction(...) { //... return StatusCode((int)HttpStatusCode.Unauthorized); //401 //... } Or just use return Unauthorized(); which is derived from StatusCodeResult and is used a short hand to replace the code shown above. Reference ControllerBase.Unauthorized.