Response is successful, i can view it in Visual Studio, but when i try to get returned data, its null.
This is API https://yoda-api.appspot.com/api/v1/yodish?text=I%20am%20yoda
And this is my code:
public class YodishModel
{
public string yodish { get; set; }
}
public class YodishResult
{
public YodishModel Result { get; set; }
}
public class YodishService : iService
{
public string GetText(string text)
{
Lazy<RestClient> client = new Lazy<RestClient>(() => new RestClient($"http://yoda-api.appspot.com/api/v1/yodish?text={text}"));
var request = new RestRequest();
var response = client.Value.Execute<YodishResult>(request);
if (response.IsSuccessful)
{
return response.Data.Result.yodish;
}
return null;
}
public string ToUrl(string text)
{
return HttpUtility.UrlEncode(text);
}
}
Response is successful, i can view the result, but Result is null (NullPointerException).
Also, is there a way to use parameters here instead of using string interpolation? 'text' is part of the URL which is officially not a paremeter.
In your case, you were deserializing using a mismatched object. This is what I did to fix it:
public class YodishModel
{
public string yodish { get; set; }
}
public class YodishService
{
public string GetText(string text)
{
Lazy<RestClient> client = new Lazy<RestClient>(() => new RestClient($"https://yoda-api.appspot.com/api/v1/"));
var request = new RestRequest($"yodish").AddQueryParameter("text", Uri.EscapeDataString(text), true);
var response = client.Value.Execute<YodishModel>(request);
if (response.IsSuccessful)
{
return Uri.UnescapeDataString(response.Data.yodish);
}
return null;
}
}
I also added the AddQueryParameter, as you mentioned.
Related
I am new to c# and I am willing to convert a Object into a class representing a User. I am retrieving the object from a http request to an API. My code is:
private async void getUser()
{
var requestURI = new HttpRequestMessage();
string url = "https:...";
requestURI.RequestUri = new Uri(url);
requestURI.Method = HttpMethod.Get;
requestURI.Headers.Add("Accept", "application/json");
HttpResponseMessage responseURI = await client.SendAsync(requestURI);
if (responseURI.StatusCode == HttpStatusCode.OK)
{
Debug.WriteLine("Get User OK");
var UserString = await responseURI.Content.ReadAsStringAsync();
Debug.WriteLine("User: " + UserString);
var UsersJson = JsonConvert.DeserializeObject(UsersString);
Debug.WriteLine(UserJson);
}
else
{
Debug.WriteLine("User GET request failed");
}
}
The output is:
{
"Username": "Alice",
"IP": "192.13.2.2",
"Levels": "1,2"
}
How do I create a class or a type to later deserealize this object into it? When the type/class is created, how do I deserealize the object into it?
Thanks in advice
You can use this website - https://json2csharp.com/ - to generate the C# classes.
In this case, the class would be as follows:
public class User
{
public string Username { get; set; }
public string IP { get; set; }
public string Levels { get; set; }
}
For deserialization to this class, you can use as follows:
var user = JsonConvert.DeserializeObject<User>(UsersString);
public class User
{
public string Username { get; set; }
public string IP { get; set; }
public string Levels { get; set; }
}
The you Deserialize an Object like this: Please have a look at this https://www.newtonsoft.com/json/help/html/SerializingJSON.htm
var user = JsonConvert.DeserializeObject<User>(json);
I am doing a search in which I am making an API call and get the XML response and SerializeXmlNode and DeserializeObject to my root object. Now the problem is when I tried to loop with foreach.
I get this error below:
foreach statement cannot operate on variables of type (Model.AccountLite) because does not contain public instance definition for 'getenumerator'
I have inspected this data = JsonConvert.DeserializeObject(json); and i can see the data.
I have tried to look at this previously asked question
Search API call
public static List<AccountLite> searchAccounts(string searchString)
{
List<AccountLite> result = new List<AccountLite>();
Root data = new Root();
string[] contains = searchString.Split(' ');
RestClient client = new RestClient(baseUrl);
foreach (string contain in contains)
{
if (contain.Length < 3) continue;
RestRequest request = new RestRequest($"/xx/xx/xx/xxx/xxx/account?xx=Lite&searchString={searchString}");
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
request.AddHeader("Authorization", "Basic " + encoded);
IRestResponse response = client.Execute(request);
string requestResponse = response.Content;
//Converting data from XML into Json and deserializet json object
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(requestResponse);
string json = JsonConvert.SerializeXmlNode(doc);
data = JsonConvert.DeserializeObject<Root>(json);
}
catch (Exception)
{
continue;
}
if (data?.SiebelMessageEnvelope?.ListOfAccountLite?.AccountLite == null)
continue;
//this line is the one showing error.
foreach (AccountLite item in data.SiebelMessageEnvelope.ListOfAccountLite.AccountLite)
{
bool containsBoth = true;
foreach (string contain2 in contains)
{
if (!item.Name.ToLower().Contains(contain2.ToLower()) && !item.Id.ToLower().Contains(contain2.ToLower()))
containsBoth = false;
}
if (containsBoth)
{
if (result.FirstOrDefault(i => i.Id == item.Id) == null)
{
result.Add(item);
}
}
}
}
return result;
}
Model
public class AccountLite
{
public string Id { get; set; }
public string AccountStatus { get; set; }
public string AccountTypeCode { get; set; }
public string Location { get; set; }
public string Name { get; set; }
public string SRIntegrationFlag { get; set; }
}
public class ListOfAccountLite
{
public AccountLite AccountLite { get; set; }
}
public class SiebelMessageEnvelope
{
[JsonProperty("#xmlns")]
public string Xmlns { get; set; }
public ListOfAccountLite ListOfAccountLite { get; set; }
}
public class Root
{
public SiebelMessageEnvelope SiebelMessageEnvelope { get; set; }
}
Json Object
{
"SiebelMessageEnvelope":{
"#xmlns":"",
"ListOfAccountLite":{
"AccountLite":{
"Id":"",
"AccountStatus":"",
"AccountTypeCode":"",
"Location":"",
"Name":"",
"SRIntegrationFlag":""
}
}
}
}
Your ListOfAccountLite just contains a single AccountLite. It doesn't make sense to foreach over a single object, where that object is not enumerable (meaning: implemented IEnumerable[<T>] or contains an explicit GetEnumerator() method).
There's only one object, so... just take it. Instead of
if (data?.SiebelMessageEnvelope?.ListOfAccountLite?.AccountLite == null)
continue;
foreach (AccountLite item in data.SiebelMessageEnvelope.ListOfAccountLite.AccountLite)
{
// ... do the thing
}
simply
var item = data?.SiebelMessageEnvelope?.ListOfAccountLite?.AccountLite;
if (item is null)
continue;
// ... do the thing
That said: you should probably investigate whether ListOfAccountLite in the JSON etc is meant to be an array rather than a single object.
I'm having some problem deserializeing a HttpResponseMessage into an object.
The problem is that when the object should have deserialized all fields are null, no exceptions are thrown.
HttpContent content = new StringContent(xml);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/xml");
HttpResponseMessage response = await client.PostAsync("URL", content).ConfigureAwait(false);
// Parse response
if (response.IsSuccessStatusCode)
{
XmlSerializer serializer = new XmlSerializer(typeof(ResponseObject));
Stream responseStream = await response.Content.ReadAsStreamAsync();
ResponseObject responseObject = serializer.Deserialize(responseStream) as ResponseObject;
//Possible example of wrong data
Console.WriteLine(responseObject.Message);
}
[XmlRoot("response")]
public class ResponseObject
{
[XmlElement("session")]
public string Session { get; set; }
[XmlElement("status")]
public string Status { get; set; }
[XmlElement("message")]
public string Message { get; set; }
}
Response message as a string
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>
<response>
<val n=\"session\">SESSION ID</val>
<val n=\"status\">201</val>
<val n=\"message\">Created</val>
</response>"
Have I missed something? I'm pretty new to serializing/deserializing.
Grateful for pointers.
Okay I solved it with the help of Eser and Biscuits in the comments.
I was trying to reuse code and did't really think about the response message having a different structure then the earlier project.
I changed my ResponseObject to this:
[XmlRoot("response")]
public abstract class ResponseObject
{
[XmlIgnore]
public bool Success { get; set; }
[XmlIgnore]
public string Session
{
get
{
var result = Values.FirstOrDefault(n => n.Name == "session");
return result.Value;
}
}
[XmlIgnore]
public string Status
{
get
{
var result = Values.FirstOrDefault(n => n.Name == "status");
return result.Value;
}
}
[XmlIgnore]
public string Message
{
get
{
var result = Values.FirstOrDefault(n => n.Name == "message");
return result.Value;
}
}
[XmlElement("val")]
public List<ResponseXmlWrapper<string>> Values;
}
public class ResponseXmlWrapper<T>
{
[XmlAttribute("n")]
[JsonProperty("n")]
public string Name { get; set; }
[XmlText]
[JsonProperty()]
public T Value { get; set; }
public ResponseXmlWrapper()
{
}
public ResponseXmlWrapper(string attributeName, T value)
{
Name = attributeName;
Value = value;
}
}
I don't know if this is an optimal solution but it works.
Im trying to deserialize an xml response from from Amazons simple db service.
The xml is like this.
<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
<ListDomainsResult>
<DomainName>Logging</DomainName>
<DomainName>teets</DomainName>
</ListDomainsResult>
<ResponseMetadata>
<RequestId>9d48122e-1ddf-8771-b771-b36599838ea0</RequestId>
<BoxUsage>0.0000071759</BoxUsage>
</ResponseMetadata>
</ListDomainsResponse>
And the object i'm trying to serialize into is this.
public class ListDomainsResponse : Response
{
public ListDomainsResult ListDomainsResult { get; set; }
}
public class ListDomainsResult
{
public List<String> DomainNames { get; set; }
public string NextToken { get; set; }
}
public class Response
{
public static string NameSpace = "http://sdb.amazonaws.com/doc/2009-04-15/";
public ResponseMetadata ResponseMetadata{ get; set; }
}
public class ResponseMetadata
{
public string RequestId { get ; set; }
public string BoxUsage { get; set; }
}
My problem is that the response metadata is getting deserialized correctly but the List of strings called DomainName is not being deserialized, it is empty each time.
Can someone see what i'm doing wrong.
Updated with more code
public async Task<Response> ListDomains (ListDomainsRequest request)
{
using (Client = new HttpClient ()) {
ListDomainsRequestMarshaller marshaller = new ListDomainsRequestMarshaller ();
marshaller.Configure (request);
HttpResponseMessage responseMessage = Client.GetAsync (marshaller.Marshal ()).Result;
ListDomainsResponseUnMarshaller unmarshaler = new ListDomainsResponseUnMarshaller (responseMessage);
return unmarshaler.Response;
}
}
public ListDomainsResponseUnMarshaller (HttpResponseMessage message)
{
XDocument doc = XDocument.Load (message.Content.ReadAsStreamAsync ().Result);
if (message.StatusCode.Equals (HttpStatusCode.OK)) {
Serializer = new XmlSerializer (typeof(ListDomainsResponse), Response.NameSpace);
Response = (ListDomainsResponse)Serializer.Deserialize (doc.CreateReader ());
Response.HttpStatusCode = message.StatusCode;
Response.ContentLength = (long)message.Content.Headers.ContentLength;
} else {
Serializer = new XmlSerializer (typeof(Response));
Response = (Response)Serializer.Deserialize (doc.CreateReader ());
Response.HttpStatusCode = message.StatusCode;
Response.ContentLength = (long)message.Content.Headers.ContentLength;
}
Serializer = null;
}
Adding Attributes helped
[System.Xml.Serialization.XmlTypeAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
[System.Xml.Serialization.XmlRootAttribute ("ListDomainsResponse", Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
public class ListDomainsResponse : Response
{
public ListDomainsResult ListDomainsResult { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
[System.Xml.Serialization.XmlRootAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
public class ListDomainsResult
{
[System.Xml.Serialization.XmlElementAttribute ("DomainName")]
public string[] DomainName { get; set; }
public string NextToken { get; set; }
}
How to connect to XML-RPC Api from c# ,
A client can interact with a Pandorabot by POST'ing to:
http://www.pandorabots.com/pandora/talk-xml
The form variables the client needs to POST are:
botid - see H.1 above.
input - what you want said to the bot.
custid - an ID to track the conversation with a particular customer. This variable is optional. If you don't send a value Pandorabots will return a custid attribute value in the element of the returned XML. Use this in subsequent POST's to continue a conversation.
How to call?
This should get you going:
public void Talk()
{
string xmlResult = null;
Result result = null; // Result declared at the end
string botId = "c49b63239e34d1"; // enter your botid
string talk = "Am I a human?";
string custId = null; // (or a value )
using (var wc = new WebClient())
{
var col = new NameValueCollection();
col.Add("botid", botId);
col.Add("input", talk);
if (!String.IsNullOrEmpty(custId))
{
col.Add("custid", custId);
}
byte[] xmlResultBytes = wc.UploadValues(
#"http://www.pandorabots.com/pandora/talk-xml",
"POST",
col);
xmlResult = UTF8Encoding.UTF8.GetString(xmlResultBytes);
result = Result.GetInstance(xmlResultBytes);
}
//raw result
Console.WriteLine(xmlResult);
// use the Result class
if (result.status == 0) // no error
{
Console.WriteLine("{0} -> {1}",
result.input, result.that);
}
else // error
{
Console.WriteLine("Error: {0} : {1}",
result.input, result.message);
}
}
[XmlRoot(ElementName="result")]
public class Result
{
static XmlSerializer ser = new XmlSerializer(typeof(Result) , "");
public Result()
{
}
public static Result GetInstance(byte[] bytes)
{
return (Result)ser.Deserialize(new MemoryStream(bytes));
}
[XmlAttribute]
public int status { get; set; }
[XmlAttribute]
public string botid { get; set; }
[XmlAttribute]
public string custid { get; set; }
[XmlElement]
public string input { get; set; }
[XmlElement]
public string that { get; set; }
[XmlElement]
public string message { get; set; }
}