I am trying to check if the response from the API GET method is Null. The response is like
{
"#odata.context": "https://dev.com/data/$metadata#Customers",
"value": []
}
I need to check if the value array is null or not and do the necessary steps below is what I tried
public class deserializeData
{
public String #odata_context {get;set;} // in json: #odata.context
public List<Value> value {get;set;}
}
public class getDataFromExternalSystem{
public string getDataFrom(){
.......
Http http1 = new Http();
HttpRequest req1 = new HttpRequest();
req1.setEndpoint(endPoint);
req1.setMethod('GET');
req1.setHeader('Authorization','Bearer '+atoken);
HttpResponse res1 = http1.send(req1);
System.debug('Response Body=========' + res1.getBody());
deserializeData dsData = (deserializeData)JSON.deserialize(res1.getbody(),deserializeData.class);
if(dsData.value.size = null) {
......
}
else{
......
}}
But I get below error like
#odata_context is not a legal identifier in Apex. # is used to introduce annotations.
If you're using JSON2Apex, which appears to be the case, you'll need to change the name of the property to something legal for Apex (like odata_context), and make the corresponding change in the parser method. E.g., where JSON2Apex generates
if (text == '#odata.context') {
#odata_context = parser.getText();
you'll need to replace that identifier with the new one you choose.
Related
How can I get value of request_id from the JSON inside my ASP.NET Core controller ?
{
"request_id": "5nRJwCgt95yfmq9qVPrzei16568823342584",
"number": "90001000000",
"price": 0.028
}
I need to assign value of request_id to string ReqID.
My controller code is as follows
public async Task<ActionResult> RequestAuthenticate()
{
var client = new RestClient("https://api.mysmsprovider.com/v1/verify");
var request = new RestRequest("",Method.Post);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "api_secret=123M&api_key=84545&code_length=4&from=NBL&to=90000001", ParameterType.RequestBody);
RestResponse response = client.Execute(request);
return Ok(response.Content);
}
ASP.NET MVC already handles this. Put the model as a param to the action method.
For example, create a model the includes the data you are interested in receiving with properties matching the JSON fields:
public class MyData {
public string request_id {get;set;}
}
And the controller
public class MyController {
public Result MyActionMethod(MyData myData) {
// now myData.request_id contains 5nRJwCgt95yfmq9qVPrzei16568823342584
// you can use it/assign it to whatever you want
var ReqID = myData.request_id;
}
}
Edit:
If you already have the JSON as a string, you can manually deserialize it into an object as follows:
var myData = Newtonsoft.Json.JsonConvert.DeserializeObject<MyData>(json);
// now myData.request_id will be the value you expect.
var ReqID = myData.request_id;
you have to parse response.Content
using Newtonsoft.Json;
string ReqID= JObject.Parse(response.Content)["request_id"].ToString();
Input JSON:
{ "name": "gerry" }
Action method:
{ public ActionResult GenerateQrCode([FromBody] string name }
Problem:
The simple-type args are null
ModelState: Invalid
The built-in json deserializer can't handle the input in this form
I've tried:
ConfigureServices() -> services.AddControllersWithViews().AddNewtonsoftJson(); to switch to NewtonSoft, which I know/love
I've set a break-point into the non-NewtonSoft built-in MS SystemTextJsonInputFormatter.ctor() just to check, if it's still used: yes, it is, I'm not sure why, when I'm calling the above .AddNewtonsoftJson()
The situation:
The client POSTs all the input params as one JSON string document, which is UTF8 w/out BOM
The string comes in at the server-side and is nicely readable with new System.IO.StreamReader(Request.Body).ReadToEnd() from inside the immediate window
I need a way ASP.NET Core deserializes this, as it was able under the .NET4.X for many years w/out any issue
I wouldn't like to add [FromBody] and similar opt-in signatures all over the server actions/args
You pass the name as json but accept as a string so it will be null, you can use an InputFormatter like:
public class RawJsonBodyInputFormatter : InputFormatter
{
public RawJsonBodyInputFormatter()
{
this.SupportedMediaTypes.Add("application/json");
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
using (var reader = new StreamReader(request.Body))
{
var content = await reader.ReadToEndAsync();
return await InputFormatterResult.SuccessAsync(content);
}
}
protected override bool CanReadType(Type type)
{
return type == typeof(string);
}
}
In startup.cs:
services
.AddMvc(options =>
{
options.InputFormatters.Insert(0, new RawJsonBodyInputFormatter());
});
And then you can get the row string
To deserilize it, you can check this, use Newtonsoft and make the string to a Model
[HttpPost]
public IActionResult GenerateQrCode([FromBody] string name)
{
object o = JsonConvert.DeserializeObject(name);
MyModel my = JsonConvert.DeserializeObject<MyModel>(o.ToString());
return View();
}
I have a C# Asp.Net MVC (5.2.7) app with support for WebApi 2.x targeting .Net 4.5.1.
I am experimenting with F# and I added an F# library project to the solution. The web app references the F# library.
Now, I want to be able to have the C# WebApi controller return F# objects and also save F# objects. I have trouble serializing a F# record with an Option field. Here is the code:
C# WebApi controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using FsLib;
namespace TestWebApp.Controllers
{
[Route("api/v1/Test")]
public class TestController : ApiController
{
// GET api/<controller>
public IHttpActionResult Get()
{
return Json(Test.getPersons);
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
[AllowAnonymous]
// POST api/<controller>
public IHttpActionResult Post([FromBody] Test.Person value)
{
return Json(Test.doSomethingCrazy(value));
}
// PUT api/<controller>/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
}
FsLib.fs:
namespace FsLib
open System.Web.Mvc
open Option
open Newtonsoft.Json
module Test =
[<CLIMutable>]
//[<JsonConverter(typeof<Newtonsoft.Json.Converters.IdiomaticDuConverter>)>]
type Person = {
Name: string;
Age: int;
[<JsonConverter(typeof<Newtonsoft.Json.FSharp.OptionConverter>)>]
Children: Option<int> }
let getPersons = [{Name="Scorpion King";Age=30; Children = Some 3} ; {Name = "Popeye"; Age = 40; Children = None}] |> List.toSeq
let doSomethingCrazy (person: Person) = {
Name = person.Name.ToUpper();
Age = person.Age + 2 ;
Children = if person.Children.IsNone then Some 1 else person.Children |> Option.map (fun v -> v + 1); }
let deserializePerson (str:string) = JsonConvert.DeserializeObject<Person>(str)
Here is the OptionConverter:
namespace Newtonsoft.Json.FSharp
open System
open System.Collections.Generic
open Microsoft.FSharp.Reflection
open Newtonsoft.Json
open Newtonsoft.Json.Converters
/// Converts F# Option values to JSON
type OptionConverter() =
inherit JsonConverter()
override x.CanConvert(t) =
t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<option<_>>
override x.WriteJson(writer, value, serializer) =
let value =
if value = null then null
else
let _,fields = FSharpValue.GetUnionFields(value, value.GetType())
fields.[0]
serializer.Serialize(writer, value)
override x.ReadJson(reader, t, existingValue, serializer) =
let innerType = t.GetGenericArguments().[0]
let innerType =
if innerType.IsValueType then typedefof<Nullable<_>>.MakeGenericType([|innerType|])
else innerType
let value = serializer.Deserialize(reader, innerType)
let cases = FSharpType.GetUnionCases(t)
if value = null then FSharpValue.MakeUnion(cases.[0], [||])
else FSharpValue.MakeUnion(cases.[1], [|value|])
I want to serialize the Option field to the value, if it is not None and to null if it is None. And vice-versa, null -> None, value -> Some value.
The serialization works fine:
[
{
"Name": "Scorpion King",
"Age": 30,
"Children": 3
},
{
"Name": "Popeye",
"Age": 40,
"Children": null
}
]
However, when I post to the url, Person parameter is serialized to null and the ReadJson method is not invoked. I used Postman (the chrome app) to post by selecting the Body -> x-www-form-urlencoded. I set up three parameters: Name=Blob,Age=103,Children=2.
In WebApiConfig.cs I have:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.FSharp.OptionConverter());
However, if I just have this and remove the JsonConverter attribute from the Children field, it doesn't seem to have any effect.
This what gets sent to the server:
POST /api/v1/Test HTTP/1.1
Host: localhost:8249
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: b831e048-2317-2580-c62f-a00312e9103b
Name=Blob&Age=103&Children=2
So, I don't know what's wrong, why the deserializer converts the object to null. If I remove the option field it works fine. Also if I remove the Children field from the payload it works fine as well. I do not understand why the ReadJson method of the OptionCoverter is not invoked.
Any ideas?
Thanks
An update: In the comments it was rightly pointed I did not post a application/json payload. I did it and the serialization still doesn't work properly.
Update 2:
After more testing, this works:
public IHttpActionResult Post(/*[FromBody]Test.Person value */)
{
HttpContent requestContent = Request.Content;
string jsonContent = requestContent.ReadAsStringAsync().Result;
var value = Test.deserializePerson(jsonContent);
return Json(Test.doSomethingCrazy(value));
}
The following is the Linqpad code I used for testing the request (I didn't use postman):
var baseAddress = "http://localhost:49286/api/v1/Test";
var http = (HttpWebRequest) WebRequest.Create(new Uri(baseAddress));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
string parsedContent = "{\"Name\":\"Blob\",\"Age\":100,\"Children\":2}";
ASCIIEncoding encoding = new ASCIIEncoding();
Byte[] bytes = encoding.GetBytes(parsedContent);
Stream newStream = http.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
var response = http.GetResponse();
var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
var content = sr.ReadToEnd();
content.Dump();
Update 3:
This works just fine - i.e. I used a C# class:
public IHttpActionResult Post(/*[FromBody]Test.Person*/ Person2 value)
{
// HttpContent requestContent = Request.Content;
// string jsonContent = requestContent.ReadAsStringAsync().Result;
//
// var value = Test.deserializePerson(jsonContent);
value.Children = value.Children.HasValue ? value.Children.Value + 1 : 1;
return Json(value);//Json(Test.doSomethingCrazy(value));
}
public class Person2
{
public string Name { get; set; }
public int Age { get; set; }
public int? Children { get; set; }
}
I found a fix, based on this post: https://stackoverflow.com/a/26036775/832783.
I added in my WebApiConfig Register method this line:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver();
I still have to investigate what's happening here.
Update 1:
It turns out that calling Json(...) in the ApiController method creates a new JsonSerializerSettings object instead of using the default set in the global.asax. What this means is that any converters added there don't have any effect on the serialization to json when the Json() result is used.
Just to throw another option in, if you're willing to upgrade the framework version you could use the new System.Text.Json APIs which should be nice and fast, and the FSharp.SystemTextJson package gives you a custom converter with support for records, discriminated unions etc.
i have json string like this downbelow
{"0":{"in":"mmm","loc":"1234"},"1":{"in":"mmm","loc":"1234"}}
Now i need to parse them as like
in | loc
---------
mmm| 1234
mmm| 1234
So far i did
public with sharing class Search
{
public String strTag {get;set;}
public String strlocation {get;set;}
public String result {get;set;}
public PageReference find() {
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http http = new Http();
req.setEndpoint('http://test.3spire.net/index.php?in='+strTag+'&loc='+strlocation);
req.setMethod('GET');
//these parts of the POST you may want to customize
req.setCompressed(false);
req.setBody('key1=value1&key2=value2');
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
try {
res = http.send(req);
} catch(System.CalloutException e) {
system.debug('Callout error: '+ e);
result = ''+e;
}
Result results = (Result) JSON.deserialize(res.getBody(),ResultSet.class);
result = res.getBody();
system.debug(res.getBody());
return null;
}
public class ResultSet{
public List<Result> resultSet;
}
public class Result
{
public String ins;
public String loc;
}
}
But its returns
System.TypeException: Invalid conversion from runtime type Search.ResultSet to Search.Result
How can i solved this problem
Thanks in advance
You are calling JSON.deserialize(res.getBody(),ResultSet.class). The second parameter ResultSet is the Apex object type you want the result to be. But then you attempt to cast it to a type of Result instead.
Either do
Result results = JSON.deserialize(res.getBody(), Result.class);
or
ResultSet results = JSON.deserialize(res.getBody(), ResultSet.class);
In your case, based on the JSON it would seem you want the second option. However, your JSON doesn't quite match your ResultSet class either. Your JSON is a map, not a list. Also, there's a field mismatch between "in" and "ins". This JSON is what would match your ResultSet class:
{{"ins":"mmm","loc":"1234"},{"ins":"mmm","loc":"1234"}}
I have a method being posted to via AJAX with the following header:
public JsonResult GetDocuments(string searchTerm, SortRequest sort)
The SortRequest object is defined as follows:
[DataContract]
public class SortRequest
{
[DataMember(Name = "field")]
public string Field { get; set; }
[DataMember(Name = "dir")]
public string Direction { get; set; }
}
Because of legacy code, the JSON object has the property name "dir" which doesn't directly match the C# property name. We want to use Json.NET as the model binder for JSON requests because it is able to handle this, but the problem is that the JSON coming into the model binder looks like a single object with two top level properties, "searchTerm" and "sort". The deserialization process then tries to map that entire JSON string into each method parameter which obviously fails.
I have tried looking through the now open source .NET MVC code and have not yet been able to determine how the DefaultModelBinder class handles this gracefully. The only option I can see so far is to convert every JSON action to take in a single request parameter but this doesn't seem like a good solution as the DefaultModelBinder doesn't require this.
Edit for clarification:
The JSON request string looks something like this:
{
"searchTerm": "test",
"sort": {
"field": "name",
"dir": "asc"
}
}
We are overriding the DefaultModelBinder and only using Json.NET when the request is of type application/json. Here is the relevant code:
var request = controllerContext.HttpContext.Request;
request.InputStream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(request.InputStream))
{
var jsonString = reader.ReadToEnd();
result = JsonConvert.DeserializeObject(jsonString, bindingContext.ModelType);
}
The bindingContext.ModelType is going to be set to String and SortRequest for each parameter in the method, but since the above is a single JSON object, it doesn't map to either of those types and thus inside the method itself, everything is set to default values.
I think the JsonProperty attribute can be used for this as follows:
[DataContract]
public class SortRequest
{
[DataMember(Name = "field")]
[JsonProperty("field")]
public string Field { get; set; }
[DataMember(Name = "dir")]
[JsonProperty("dir")]
public string Direction { get; set; }
}
Update
Based upon the json add a binding prefix:
public JsonResult GetDocuments(string searchTerm, [Bind(Prefix="sort"] SortRequest sort)
I ended up going with a solution using the JToken.Parse method in the Json.NET library. Essentially what is happening is that we check the top level properties of the JSON object and see if there exists the current action parameter we are trying to bind to. Where this falls down is if there is overlap between the parameter name of the action and a property name of a single request being passed in. I think this is enough of an edge case to let slide as it would require only a single object be passed into an action that is expecting multiple.
Here is the modified BindModel method:
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
object result;
if (IsJSONRequest(controllerContext))
{
var request = controllerContext.HttpContext.Request;
request.InputStream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(request.InputStream))
{
var jsonString = reader.ReadToEnd();
// Only parse non-empty requests.
if (!String.IsNullOrWhiteSpace(jsonString))
{
// Parse the JSON into a generic key/value pair object.
var obj = JToken.Parse(jsonString);
// If the string parsed and there is a top level property of the same
// name as the parameter name we are looking for, use that property
// as the JSON object to de-serialize.
if (obj != null && obj.HasValues && obj[bindingContext.ModelName] != null)
{
jsonString = obj[bindingContext.ModelName].ToString();
}
}
result = JsonConvert.DeserializeObject(jsonString, bindingContext.ModelType);
}
}
else
{
result = base.BindModel(controllerContext, bindingContext);
}
return result;
}