We have got a Odata response as below:
"{\r\n \"#odata.context\":\"http://localhost/ApplicationService/model/$metadata#Edm.String\",\"value\":\"{\\\"Messages\\\":[\\\"message 1\\\",\\\"message 2\\\",\\\"message 3\\\",\\\"message 4\\\"],\\\"IsValidEntity\\\":false}\"\r\n}"
Now say we have a class:
public class myValidationResult
{
public myValidationResult()
{
Messages = new List<string>();
}
public List<string> Messages { get; set; }
public bool IsValidEntity { get; set; }
}
This class used in MyOdataController class as below:
public class MyODataController : ODataController
{
[Authorize(Roles = "Admin")]
public async Task<IHttpActionResult> Post(T entity)
{
myValidationResult vResult = new myValidationResult();
vResult.Messages.Add("message 1");
vResult.Messages.Add("message 2");
vResult.Messages.Add("message 3");
vResult.Messages.Add("message 4");
vResult.IsValidEntity = false;
var strResult = JsonConvert.SerializeObject(vResult);
var resp = Content(HttpStatusCode.BadRequest, strResult );
return resp;
}
}
For the client Consuming this, we created below Class:
public class OData<T>
{
[JsonProperty("odata.context")]
public string Metadata { get; set; }
public T value { get; set; }
}
In the method where we call the Odata method & store response in 'msg':
var resp = msg.Result.Content.ReadAsStringAsync().Result;
resp is:
"{\r\n \"#odata.context\":\"http://localhost/ApplicationService/model/$metadata#Edm.String\",\"value\":\"{\\\"Messages\\\":[\\\"message 1\\\",\\\"message 2\\\",\\\"message 3\\\",\\\"message 4\\\"],\\\"IsValidEntity\\\":false}\"\r\n}"
var odatares = JsonConvert.DeserializeObject<OData<myValidationResult>>(resp);
But the above line giving error:
Can not convert value\":\"{\\\"Messages\\\":[\\\"message 1\\\",\\\"message 2\\\",\\\"message 3\\\",\\\"message 4\\\"],\\\"IsValidEntity\\\":false} to <.....namespace......>myValidationResult
Please suggest accordingly.
The OData response contains a string, not an instance of myValidationResult. Also, the response looks like it's missing some backslashes. (Are you sure the response shown is exactly what you received from the service?)
You can either fix the serialization of myValidationResult on the service:
// Don't serialize vResult yourself. OData will do it for you.
var resp = Content(HttpStatusCode.BadRequest, vResult );
Or deserialize in two steps as follows.
var data = "{\r\n \"#odata.context\":\"http://localhost/ApplicationService/model/$metadata#Edm.String\",\"value\":\"{\\\"Messages\\\":[\\\"message 1\\\",\\\"message 2\\\",\\\"message 3\\\",\\\"message 4\\\"],\\\"IsValidEntity\\\":false}\"\r\n}";
var outer = Newtonsoft.Json.JsonConvert.DeserializeObject<OData<string>>(data);
var inner = Newtonsoft.Json.JsonConvert.DeserializeObject<myValidationResult>(outer.value);
One more thing: The JsonProperty on OData<T> should be named #odata.context.
In my case the OData response did not contain a string but an object array which contains the data string as its first element. So in this case reading the data should look like this:
var outer = Newtonsoft.Json.JsonConvert.DeserializeObject<OData<object[]>>(data);
var inner = Newtonsoft.Json.JsonConvert.DeserializeObject<myValidationResult>(outer.value[0].ToString());
Related
I am pulling data from API. I am getting an error while deserializing. please help me.
error:
System.Text.Json.JsonException: '',' is invalid after a single JSON value. Expected end of data. Path: $ | LineNumber: 0 | BytePositionInLine: 128.'
data i pull:
{"firmano":128257,"adi":"- FATİH YILMAZ"},{"firmano":128446,"adi":"-MEHMET ÜSTÜN"}
my c# codes:
Index.cs :
var result = await Api<Company>.pullDataAsync("https://localhost:5001/api/PesinIskontolar/companyGet");
api.cs:
public class Api<T> where T : class
{
public async static Task<T> pullDataAsync(string url)
{
var client = new RestClient(url);
var request = new RestRequest(Method.GET);
IRestResponse response = await client.ExecuteAsync(request);
return Json_Convert<T>.deserializeProcess(apiFormat(response.Content));
}
public static string apiFormat(string response)
{
var result = response.Replace("\\", "").Replace("[","").Replace("]","");
return result.Substring(1, result.Length - 2);
}
}
Json_Convert.cs:
public class Json_Convert<T> where T : class
{
public static T deserializeProcess(string response)
{
return JsonSerializer.Deserialize<T>(response);
}
}
dal:
public string getCompany()
{
......
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
string data = JsonConvert.SerializeObject(dt);
baglanti.Close();
baglanti.Dispose();
return data;
}
api:
[HttpGet("companyGet")]
public IActionResult companyGet()
{
return Ok(_firmaServices.getCompany());
}
Since some friends said that there is a problem with the api, I added other codes.
company class:
public class Company
{
public int firmano { get; set; }
public string adi { get; set; }
}
Your JSON is invalid, should be:
[{"firmano":128257,"adi":"- FATİH YILMAZ"},{"firmano":128446,"adi":"-MEHMET ÜSTÜN"}]
instead of:
{"firmano":128257,"adi":"- FATİH YILMAZ"},{"firmano":128446,"adi":"-MEHMET ÜSTÜN"}
Also, instead of calling response.Content prior to deserialization, you need to call await response.Content.ReadAsStringAsync() method to actually read the returning json string from the server.
As you pulling a list of two companies, your deserialization should be deserializing to a list instead of a single object, so you need to delete the apiFormat method and call await Api<IEnumerable<Company>>.pullDataAsync instead of await Api<Company>.pullDataAsync
You should deserialize List< Company >, not just Company so use this code
var result = await Api<List<Company>>.pullDataAsync("https://localhost:5001/api/PesinIskontolar/companyGet");
and fix your generic code by removing apiFormat(response.Content), replace it by just content. it will prevent removing [] from your json, this is what causes an exception
public async static Task<T> pullDataAsync(string url)
{
var client = new RestClient(url);
var request = new RestRequest(Method.GET);
IRestResponse response = await client.ExecuteAsync(request);
return Json_Convert<T>.deserializeProcess(response.Content); //fix here!!!
}
and according to your response.Content, you company class should be changed
public partial class Company
{
[JsonPropertyName("firmano")]
public int firmano { get; set; }
[JsonPropertyName("Column1")]
public string adi { get; set; }
}
1.Try to use known class as Company instate of
2.Json converter does not like special characters like '(Some times People are using the ' char, to write a letter like è, and this can bracke the Json String). You can do like .Replace("'", "''")
3.Use encoding UTF8.
4.Control the API Site in Debug and see the Response creation..
5. before subtracting the end 2 chars check if the string has this chars. better do this operations after you get the response.
return result.Substring(1, result.Length - 2);
I have an API method that looks like this:
[HttpGet("top/{max}", Name = "GetTopLocations")]
public ActionResult<List<LocationDto>> GetTop(int max)
{
return _locationService.Get();
}
I have then generated client code class with NSwag via Swagger. I call this method in my Blazor WebAssembly code like this:
Locations = await MyProject.Client.GetTopLocationsAsync(10);
However, this generates an exception:
Error: 0 : Could not deserialize the response body stream as System.Collections.Generic.ICollection`1[[MyProject.LocationDto, MyProject.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
But if I call this method in my browser like this: http://localhost:50464/api/Locations/top/10
and then take that JSON string and test to Deserialize it like this:
string jsonStringCopiedFromBrowser = "...";
var thisWorks = JsonConvert.DeserializeObject<ICollection<LocationDto>>(jsonStringCopiedFromBrowser);
I cannot understand why it works when I deserialize it like in the last code but not from NSwag? Any tips on what I am doing wrong? I have not modified the NSwag generated code at all, its taken directly from the generated output.
NSwag Studio does not help with this kind of operation.
so you need to create a List mannunally.
I try and its work
here is the code below
public class Response<T>
{
public string Message { get; set; }
public string ValidatonError { get; set; }
public bool Success { get; set; }
public T Data { get; set; }
public IList<T> DataEnum { get; set; }
}
public async Task<Response<EmployeeDetailDTO>> GetEmployee(int ID)
{
Response<EmployeeDetailDTO> response;
try
{
var data = await client.EmployeeAllAsync(ID);
response = new Response<EmployeeDetailDTO>
{
DataEnum = data.ToList(),
Success = true
};
}
catch (ApiException e)
{
response = ConvertApiException<EmployeeDTO>(e);
}
return response;
}
Now extract the result on your Client Page
#foreach(var model in rl.ToArray())
{
<td>#model.Complaintname</td>
}
after a couple of hours, I use this method for solving the problem. NSwag Studio work if you send a single Record.
I need to wrap an api call with my own api to avoid CORS and so I can avoid exposing credentials to the client. Can anyone help me to figure out what I'm doing wrong?
This works in a webform but I don't know how to put its an api controller class.
When I try to return the objects with the code below it throws an error
Controller:
public class sampleController : ApiController
{
public IEnumerable<sample> GetSample()
{
string url = String.Format("sampleurl.json");
WebRequest requestObj = WebRequest.Create(url);
requestObj.Credentials = new NetworkCredentials("USER", "PW");
requestObj.Method = "GET";
HttpWebResponse responseObj = null;
responseObj = (HttpWebResponse)requestObj.GetResponse();
string str = null;
using (Stream stream = responseObj.GetResponseStream())
{
StreamReader sr = new StreamReader(stream);
str = sr.ReadToEnd();
sr.Close();
}
var ser = new System.Web.Script.Serialization.JavaScriptSerializer();
sample sampleList = (sample).ser.Deserializer(str, typeof(sample));
return sampleList.Root_Object;
}
}
Model:
public class sample
{
public List<Root_Object> Root_Object {get; set;}
}
public class Root_Object
{
public string listItemOne { get; set; }
public string listItemTwo { get; set; }
}
JSON
{
"Root_Object": [
{
"ListItemOne": "Value",
"ListItemTwo": "Value"
},
{
"ListItemOne": "Value",
"ListItemTwo": "Value"
},
{
"ListItemOne": "Value",
"ListItemTwo": "Value"
}
]
}
I expected to be able to return all objects from Root_Object. The return statement gives me an error of
"Cannot implicitly convert type 'System.Collections.Generic.IList<project.Models.Root_Object>' to 'System.Collections.Generic.IEnumerable<project.Models.sample>'. An explicit conversion exists(are you missing a cast?)"
Assuming the GetSample() method is supposed to be a pass-through API, meaning you don't intend to change the JSON format at all, then you need to make two changes:
Change the return type of your method from IEnumerable<sample> to sample
Change the method to return sampleList instead of sampleList.Root_Object.
If you're instead trying to "unwrap" the list of objects, then the other two answers are correct.
Should you not be returning IEnumerable<Root_Object> as the type? You currently have it as IEnumerable<sample>.
Your method requires a return type of IEnumerable<sample>, but you are returning sampleList.Root_Object, which is itself a list of Root_Object
I would like to store my Http status and them messages in json file, for example BadRequest status could have 2 different messages: 1. name could not be null , 2. name could not be empty and etc...
but unfortunatelly I can't solve it, because IHttpActionResult requires to return only status method, how can I add custom message in different case?
I am geeting error
Cannot implicitly convert type 'System.Net.Http.StringContent' to
'System.Web.Http.IHttpActionResult'. An explicit conversion exists
(are you missing a cast?)
Exceptions class:
public class ExceptionResponse
{
public HttpStatusCode ReturnCode { get; set; }
public string Message { get; set; }
}
post method:
[HttpPost]
public IHttpActionResult Post([FromBody] MyRequest myCaseRequest)
{
var myObj = new MyObjCase();
ExceptionResponse data = new ExceptionResponse()
{
Message = "Parameter cannont be null",
ReturnCode = HttpStatusCode.BadRequest
};
string json = JsonConvert.SerializeObject(data, Formatting.Indented);
var jsonCont = new StringContent(json, Encoding.UTF8, "application/json");
if (myObj.Name == null || myObj.Name == "")
// return BadRequest(); // Before
return jsonCont; // expecting for result
}
}
You can try to use HttpResponseMessage. Example here
CustomResponseMessage message = new CustomResponseMessage()
{
Message = "write a something"
};
Request.CreateResponse(HttpStatusCode.Ok,message);
//Custom Class
public class CustomResponseMessage
{
public string Message{ get; set; }
}
You can try this.
I have a call to a WebAPI with the following code:
var client = new HttpClient
{
BaseAddress = new Uri("http://localhost:8490/")
};
var jObject = new JObject();
jObject.Add("paramA", paramA);
jObject.Add("paramB", paramB);
JArray jArr = JArray.FromObject(paramsGenericArr);
jObject.Add("paramC", jArr);
var content = new StringContent(jObject.ToString(), Encoding.UTF8, "application/json");
var result = await client.PostAsync("api/path/tofunc", content).ConfigureAwait(false);
result.EnsureSuccessStatusCode();
The ParamsGeneric class is an abstract type with 2 derived classes:
[DataContract]
public class ParamsTypeA : ParamsGeneric
{
[DataMember]
public long itemC {get; set;}
public ParamsTypeA() :
base()
{}
}
[DataContract]
public class ParamsTypeB : ParamsGeneric
{
[DataMember]
public long itemD {get; set;}
public ParamsTypeB() :
base()
{}
}
[DataContract]
[KnownType(typeof(ParamsTypeA))]
[KnownType(typeof(ParamsTypeB))]
public abstract class ParamsGeneric
{
[DataMember]
public long itemA { get; set; }
[DataMember]
public long itemB {get; set;}
public ParamsGeneric()
{}
}
I suspect that I have a problem with the deserialization in the WebAPI:
public class ClientData
{
public string paramA { get; set; }
public string paramB { get; set; }
public ParamsGeneric[] paramC { get; set; }
}
[HttpPost]
[Route("api/path/tofunc")]
public async Task<bool> DoStuffAsync(ClientData clientData)
{
....
}
I have a problem with the paramsGenericArr/paramC (which is of type ParamsGeneric[], and holds items of type ParamsTypeA & ParamsTypeB)
The WebAPI receives a blank array (ParamsGeneric[0]), along with the other parameters.
Help will be appriciated.
UPDATE
Even if I try to pass a single ParamsGeneric object instead of an array, I receive null instead of the object.
SOLUTION
var serializer = new JsonSerializer();
serializer.TypeNameHandling = TypeNameHandling.Auto;
JArray jArr = JArray.FromObject(paramsGenericArr, serializer);
Did the trick.
While inheritance in messages / json is definitely possible, IMHO; it's just too much of a hassle :)
Anyway, you can actually let Newtonsoft.Json handle the inheritance for you, by setting TypeNameHandling
// Allow inheritance in json payload
JsonSerializerSettings serializerSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
serializerSettings.TypeNameHandling = TypeNameHandling.All;
.. or just
serializerSettings.TypeNameHandling = TypeNameHandling.Auto;
.. depending on your needs.
This is the easy fix, which will work fine if it's an internal API or if you can guarantee you will always be in control of the clients. If you have external clients, I would go the 'override default model binder'-approach such as what is posted here "Deserialising Json to derived types in Asp.Net Web API" - or very strongly consider avoiding inheritance in the model of the API.
Try to pass data to your API as below
Dictionary<string, string> param = new Dictionary<string, string>();
param.Add("paramA", paramA);
param.Add("paramB", paramB);
HttpClient client = new HttpClient();
HttpFormUrlEncodedContent contents = new HttpFormUrlEncodedContent(param);
var result = await client.PostAsync(new Uri("http://localhost:8490/api/path/tofunc")
, contents);
var reply = await result.Content.ReadAsStringAsync();
if (reply.IsSuccessStatusCode)
{
}
Hope this will help you.
[HttpPost]
[Route("api/path/tofunc")]
public async Task<bool> DoStuffAsync([FromBody]ClientData clientData)
{
....
}
Please keep [FromBody] in the web api method, so that model binder will map your body data to parameter i.e clientData.