Restsharp Doesn't Deserialize Enumeration - c#

I'm trying to call an external RESTful API in my application and I've been using restsharp for it which has been great so far so but I think I've ran into a problem.
I'm calling an API which normally returns XML documents like this:
<res>
<resultCode>100</resultCode>
<resultText>OK</resultText>
<messageId>52788198</messageId>
<sessionId>TEST</sessionId>
<operatorCode>22802</operatorCode>
</res>
This is my code:
internal class SubmitMessageResponse
{
public ResultCode resultCode { get; set; }
public string resultText { get; set; }
public string messageId; { get; set; }
public string sessionId; { get; set; }
public string operatorCode; { get; set; }
}
public SubmitMessageResponse SendWelcomeSMS(string subscriptionId, string msisdn)
{
var request = new RestRequest(Method.GET);
request.AddQueryParameter("command", "submitMessage")
.AddQueryParameter("username", _Config.User)
.AddQueryParameter("password", _Config.Password)
.AddQueryParameter("msisdn", "00" + _Club.CountryCode + msisdn)
.AddQueryParameter("businessNumber", _Club.SubscribeShortCode)
.AddQueryParameter("content", _Club.WelcomeMessage)
.AddQueryParameter("price", "0")
.AddQueryParameter("sessionId", subscriptionId)
.AddQueryParameter("label", "W")
.AddQueryParameter("keyword", _Club.SubscribeKeyword)
.AddQueryParameter("operatorCode", "test");
return SendGetRequest<SubmitMessageResponse>(request);
}
private T SendGetRequest<T>(RestRequest request) where T : new()
{
try
{
var client = new RestClient(this._BaseUrl);
client.Timeout = 10000;
_Logger.DebugFormat("{0} Request: {1}", "submitMessage", client.BuildUri(request));
var data = client.Execute<T>(request);
_Logger.DebugFormat("{0} Response: {1}", "submitMessage", Newtonsoft.Json.JsonConvert.SerializeObject(data.Content));
return data.Data;
} catch(Exception e)
{
_Logger.Error(e);
}
return default(T);
}
Where ResultCode is an enumeration including all known values that this API returns:
internal enum ResultCode
{
Ok = 100,
AuthorizationInProgress = 150,
PaymentAuthInProcess = 150,
InvalidOperatorCode = 201,
...
}
The problem is that normally this would work correctly but I'm unable to deserialize the enum from the XML:
var response = apiHelper.SendWelcomeSMS(client.ExternalData, client.Number);
Logger.Debug(Newtonsoft.Json.JsonConvert.SerializeObject(response));
My log:
{"messageId":"52788292","sessionId":"TEST","operatorCode":"22802","**resultCode**":0,"resultText":"OK"}
But I also log the response and it works fine:
submitMessage Response: "<res>\r\n\t<**resultCode**>**100**</**resultCode**>\r\n\t<resultText>OK</resultText>\r\n\t<messageId>52788292</messageId>\r\n\t<sessionId>TEST</sessionId>\r\n\t<operatorCode>22802</operatorCode>\r\n</res>\r\n"
Any advice is appreciated.

Related

Parse REST api response for different possible classes in C#

I'm working with a REST API, that returns 2 different kinds of XML responses for the same request.
For example if I ask for a ticket using some ticket number, say 12345 to this API, it either returns:
The ticket:
Or says that it doesn't have the ticket:
(I couldn't format my XML for some reason so just pasted the screenshot.)
Note that the status code comes to be Ok in both the cases. I'm aware that it's a bad api design but we can't change anything about it.
With some help from this JSON2Csharp website, I came up with these classes to represent the response:
The Ticket class:
[XmlRoot(ElementName = "Tickets")]
public class TicketsResponse
{
public List<Ticket> Tickets { get; set; } = new List<Ticket>();
public bool HasTickets() => Tickets.Any();
}
[XmlRoot(ElementName = "Ticket")]
public class Ticket
{
[XmlElement(ElementName = "Field1", IsNullable = true)]
public string Field1 { get; set; }
public bool ShouldSerializeField1() { return Field1 != null; }
[XmlElement(ElementName = "TicketNumber")]
public int TicketNumber { get; set; }
[XmlElement(ElementName = "SomeOtherDetails")]
public SomeOtherDetails SomeOtherDetails { get; set; }
[XmlElement(ElementName = "Accessorials")]
public object Accessorials { get; set; }
}
[XmlRoot(ElementName = "SomeOtherDetails")]
public class SomeOtherDetails
{
[XmlElement(ElementName = "SomeOtherField1", IsNullable = true)]
public string SomeOtherField1 { get; set; }
public bool ShouldSerializeSomeOtherField1() { return SomeOtherField1 != null; }
}
The Error class:
[XmlRoot(ElementName = "response")]
public class ErrorResponse
{
public byte requestId { get; set; }
public byte errorCode { get; set; }
public string errorDesc { get; set; }
public ErrorResponseBody body { get; set; }
public bool HasErrors()
{
var hasTopLevelError = errorCode != 0;
var hasErrorBody = body?.errors?.Any() ?? false;
if (hasTopLevelError || hasErrorBody)
{
return true;
}
return false;
}
public string ErrorMessage()
{
var hasTopLevelError = errorCode != 0;
var hasErrorBody = body?.errors?.Any() ?? false;
if (hasTopLevelError)
{
return errorDesc;
}
else if (hasErrorBody)
{
return string.Join(", ", body.errors.Select(e => e.errorDescription));
}
return null;
}
}
[XmlRoot(ElementName = "body")]
public class ErrorResponseBody
{
[XmlElement("errors")]
public List<Error> errors { get; set; }
}
[XmlRoot(ElementName = "Error")]
public class Error
{
public byte errorId { get; set; }
public string errorDescription { get; set; }
public string errorObjectId { get; set; }
}
I then call the API using a TicketNumber that exists.
I'm using RestSharp for calling the api:
public async void SendRequestAndReceiveResponse()
{
var restClient = new RestClient("https://someapiaddress.net");
var requestXMLBody = "<request><request_id>1</request_id><operation>retrieve</operation><method /><entity>ticket</entity><user>someuser</user><password>somepassword</password><body><ticket><TicketNumber>12345</TicketNumber></ticket></body></request>";
var request = new RestRequest("somexmlwebservice!process.action", Method.POST);
request.AddParameter("xmlRequest", requestXMLBody, "text/xml", ParameterType.QueryString);
var response = await restClient.ExecuteAsync<TicketsResponse>(request);
// Do other stuffs with this response...
}
Now this works very well. Because I know my response will have the ticket and that will correctly deserialize to TicketsResponse object.
But if I call the API using a TicketNumber that doesn't exist, I simply get TicketsResponse object that has an empty list of Tickets because this time I'm getting error response. The status code comes to be OK in this case too.
What I want to do here is that I want to capture the error message from the error response. (Response of either Ticket or Error applies to bunch of other processes as well, so it's important to grab this information in a single call.)
And if I knew this ticket doesn't exist, I could simply call the API this way and capture the errors. But that's not ideal nor even a good idea:
var response = await restClient.ExecuteAsync<ErrorResponse>(request);
So I thought of combining TicketsResponse and ErrorResponse, like this:
[XmlRoot]
public class CombinedResponse
{
[XmlElement(ElementName = "Tickets")]
public TicketsResponse Data { get; set; }
[XmlElement(ElementName = "response")]
public ErrorResponse NonData { get; set; }
}
And get the response using that class:
var response = await restClient.ExecuteAsync<CombinedResponse>(request);
The Status code comes OK (when it returns either data or error message) and I get my correct response in response.Content, but the deserialization doesn't work, so my response.Data will show 2 fields Data and NonData both as null. Ideally I should have gotten either my Ticket data or Error data in response.Data.
So my question is:
Is it possible to make this work using a single class for deserialization?
I have spent too much time on this so any help is appreciated.
Also please look at my model classes and suggest if there's better way of doing things.
This is how I solved this issue.
I'm posting here so others may find it helpful.
If there's a better way of doing this, please advise.
I created a method to call the API and deserialize the response to multiple types:
public async Task<(T1, T2)> SendRequestAndReceiveResponse<T1, T2>(RestRequest request)
{
// This can be done in the constructor so we don't instantiate new client for every request.
var restClient = new RestClient("https://someapiaddress.net");
// Get response:
var response = await restClient.ExecuteAsync(request);
// Log request and response here if you want.
if (response.ErrorException != null)
{
var message = $"An error occured during this request. Check request response entries for more details.";
var newException = new Exception(message, response.ErrorException);
throw newException;
}
else
{
var xmlDeserilizer = new RestSharp.Deserializers.XmlDeserializer();
var data = xmlDeserilizer.Deserialize<T1>(response);
var nonData = xmlDeserilizer.Deserialize<T2>(response);
return (data, nonData);
}
}
And used it, by sending the types I need:
public async Task<IEnumerable<Ticket>> FetchTickets()
{
var xmlRequestBody = "<request><request_id>1</request_id><operation>retrieve</operation><method /><entity>ticket</entity><user>someuser</user><password>somepassword</password><body><ticket><TicketNumber>12345</TicketNumber></ticket></body></request>";
var request = new RestRequest("somexmlwebservice!process.action", Method.POST);
request.AddParameter("xmlRequest", xmlRequestBody, "text/xml", ParameterType.QueryString);
var apiCallResult = await SendRequestAndReceiveResponse<TicketsResponse, ErrorResponse>(request);
if (apiCallResult.Item1 != null && apiCallResult.Item1.HasTickets())
{
// Do something with the tickets...
}
else if (apiCallResult.Item2 != null && apiCallResult.Item2.HasErrors())
{
// Do something with the errors...
}
// And so on...
}
My complete solution. If you just need the answer, please take a look at the accepted answer.
This is more like a documentation of the whole process for anyone who deals with RestSharp and XML.
Request:
To form a request body that looks like this, we need few classes like below:
[XmlRoot(ElementName = "request")]
[XmlInclude(typeof(RequestBodyWithTicketNumberOnly))] // To make sure 'body' can be serialized to RequestBodyWithTicketNumberOnly
public class TicketRequestBase
{
public byte request_id { get; set; }
public string operation { get; set; }
public string method { get; set; }
public string entity { get; set; }
public string user { get; set; }
public string password { get; set; }
// body can have different shapes, so not giving it any specific class name.
public object body { get; set; }
}
[XmlRoot(ElementName = "body")]
public class RequestBodyWithTicketNumberOnly
{
public TicketWithTicketNumberOnly ticket { get; set; }
}
[XmlRoot(ElementName = "ticket")]
public class TicketWithTicketNumberOnly
{
public string TicketNumber { get; set; }
}
A method to convert C# objects into XML strings, like so:
public static string ToXml<T>(T obj)
{
var settings = new XmlWriterSettings
{
Indent = false,
OmitXmlDeclaration = true,
NewLineHandling = NewLineHandling.None,
NewLineOnAttributes = false
};
var objType = obj.GetType();
var serializer = new XmlSerializer(objType);
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, obj, emptyNamespaces);
return stream.ToString();
}
}
A method to return request body as XML string:
public static string GetTicketFetchRequestBody(string ticketNumber)
{
if (ticketNumber== null) throw new ArgumentNullException(nameof(ticketNumber));
var singleTicketRequest = new TicketRequestBase()
{
request_id = 1,
operation = "retrieve",
method = string.Empty,
entity = "ticket",
user = "sauser",
password = "sapassword",
body = new RequestBodyWithTicketNumberOnly() { ticket = new TicketWithTicketNumberOnly { TicketNumber = ticketNumber} }
};
return ToXml(singleTicketRequest);
}
Response:
All the classes for the response are already documented in this question. Please take a look at them.
The top level method that gets the Ticket:
public static async Task<IEnumerable<Ticket>> FetchTickets()
{
var xmlRequestBody = GetTicketFetchRequestBody("12345");
var request = new RestRequest("somexmlwebservice!process.action", Method.POST);
request.AddParameter("xmlRequest", xmlRequestBody, "text/xml", ParameterType.QueryString);
var apiCallResult = await SendRequestAndReceiveResponse<TicketsResponse, ErrorResponse>(request);
if (apiCallResult.Item1 != null && apiCallResult.Item1.HasTickets())
{
// Do something with the tickets...
}
else if (apiCallResult.Item2 != null && apiCallResult.Item2.HasErrors())
{
// Do something with the errors...
}
// And so on...
}
The method that actually calls the API uses Proxy, logs requests and responses, and executes request using Polly retry policy:
public async Task<(T1, T2)> SendRequestAndReceiveResponse<T1, T2>(RestRequest request, bool useProxy = true)
{
// This can be done in the constructor so we don't instantiate new client for every request.
var restClient = new RestClient("https://someapiaddress.net");
if (useProxy) // This variable can even be initialized in the constructor of this RestClient
{
var proxy = GetWebProxy();
restClient.Proxy = proxy;
}
// Request Logging Part:
var requestAsJSONString = GetRequestForLogging(request, restClient);
// Log it using your logging provider.
// Response Part:
var response = await ExecuteAsyncWithPolicy(request, restClient);
// Response Logging Part:
var responseAsString = response.Content;
// Log it using your logging provider.
if (response.ErrorException != null)
{
var message = $"An error occured during this request. Check request response entries for more details.";
var newException = new Exception(message, response.ErrorException);
throw newException;
}
else
{
var xmlDeserilizer = new RestSharp.Deserializers.XmlDeserializer();
var data = xmlDeserilizer.Deserialize<T1>(response);
var nonData = xmlDeserilizer.Deserialize<T2>(response);
return (data, nonData);
}
}
Create Web proxy like so:
private static WebProxy GetWebProxy()
{
var proxyUrl = "http://proxy.companyname.com:9090/";
return new WebProxy()
{
Address = new Uri(proxyUrl),
BypassProxyOnLocal = false,
//UseDefaultCredentials = true, // This uses: Credentials = CredentialCache.DefaultCredentials
//*** These creds are given to the proxy server, not the web server ***
Credentials = CredentialCache.DefaultNetworkCredentials
//Credentials = new NetworkCredential("proxyUserName", "proxyPassword")
};
}
Create the request string with all the parameters like so:
private string GetRequestForLogging(IRestRequest request, IRestClient client)
{
var serializer = new JsonSerializer();
var requestToLog = new
{
// This will generate the actual Uri used in the request
RequestUri = client.BuildUri(request),
// Parameters are custom anonymous objects in order to have the parameter type as a nice string
// otherwise it will just show the enum value
parameters = request.Parameters.Select(parameter => new
{
name = parameter.Name,
value = parameter.Value,
type = parameter.Type.ToString()
}),
// ToString() here to have the method as a nice string otherwise it will just show the enum value
method = request.Method.ToString()
};
return serializer.Serialize(requestToLog);
}
Polly retry policy:
private AsyncPolicy<IRestResponse> GetRetryPolicy()
{
var policy = Polly.Policy.HandleResult<IRestResponse>((response) =>
{
return response.ResponseStatus != ResponseStatus.Completed;
})
//.Or<SomeKindOfCustomException>()
.RetryAsync();
return policy;
}
Call the API using the retry policy:
private async Task<IRestResponse> ExecuteAsyncWithPolicy(IRestRequest request, IRestClient restClient)
{
var policy = GetRetryPolicy();
var policyResult = await policy.ExecuteAndCaptureAsync(async () => await restClient.ExecuteAsync(request));
return (policyResult.Outcome == OutcomeType.Successful) ? policyResult.Result : new RestResponse
{
Request = request,
ErrorException = policyResult.FinalException
};
}
Hope this was helpful.

How to Parse Json from UrI to list on Xamarin Android

I tried too many but no success
this is my method to get JSON string from web service Uri and deserialize it to list, and I want to use it on Xamarin Android App
public async void DownloadDataAsync()
{
string url = "http://myWebSite.com/jWebService.asmx/GetOffersJSON?storeID=2";
var httpClient = new HttpClient();
Task <string> downloadTask = httpClient.GetStringAsync(url);
string content = await downloadTask;
// de-serializing json response into list
JObject jsonResponse = JObject.Parse(content);
IList<JToken> results = jsonResponse["offs"].ToList();
foreach (JToken token in results)
{
offers poi = JsonConvert.DeserializeObject<offers>(token.ToString());
offs.Add(poi);
}
}
when I call DownloadDataAsync(); I get an error:
An unhandled exception occured.
what is the solution?
I've parameter on my web service method, who can I deal with it?
Here is my JSON Uri result:
This XML file does not appear to have any style information associated with
it. The document tree is shown below.
<string xmlns="http://tempuri.org/">[{"ItemID":20,"ItemBarcode":"111","ItemName":"hgh","ItemImage":"MegaOrders22017-04-14-08-34-27.jpg","ItemPrice":7.0000,"ItemNotes":"gffgdfj","OfferOn":true},{"ItemID":21,"ItemBarcode":"222","ItemName":"Nod","ItemImage":"MegaOrders22017-04-14-08-34-57.jpg","ItemPrice":4.0000,"ItemNotes":"kkkkkk","OfferOn":true},{"ItemID":22,"ItemBarcode":"333","ItemName":"kjkjkjkj","ItemImage":"MegaOrders22017-04-14-08-35-21.jpg","ItemPrice":6.0000,"ItemNotes":"hhhhggggg","OfferOn":true},{"ItemID":23,"ItemBarcode":"4444","ItemName":"oioioio","ItemImage":"MegaOrders22017-04-14-08-35-50.jpg","ItemPrice":5.0000,"ItemNotes":"hjhgfdfghj","OfferOn":true}]
</string>
the Class I used:
public class offers
{
public int ItemID { get; set; }
public string ItemBarcode { get; set; }
public string ItemName { get; set; }
public string ItemImage { get; set; }
public double ItemPrice { get; set; }
public string ItemNotes { get; set; }
public bool OfferOn { get; set; }
}
Please try this:
public async void DownloadDataAsync()
{
try
{
string url = "http://myWebSite.com/jWebService.asmx/GetOffersJSON?storeID=2";
var httpClient = new HttpClient();
var content = await httpClient.GetStringAsync(url);
// de-serializing json response into list, with filtering before
var startPosition = content.IndexOf('>') + 1;
var endPosition = content.LastIndexOf("</", StringComparison.Ordinal);
var filteredResponseCharArray = new char[endPosition - startPosition];
content.CopyTo(startPosition, filteredResponseCharArray, 0, endPosition - startPosition);
var listOfOffers = JsonConvert.DeserializeObject<List<offers>>(new string(filteredResponseCharArray));
}
catch (Exception error)
{
Debug.WriteLine(error);
throw;
}
}
You should change your web service to get a valid JSON response without XML structure.

How to read the contents of a json post with asp before processing the request?

What I want to do is extremely simple in php. I just want to read the contents of the post. It also extremely simple on sailsjs / node ... I just return the result from within the async function.
In c# asp the answer is eluding me. I want the function to read the contents of the post before it attempts to process the post.
Sometimes the following code works. Sometimes the reading of the json from the post happens too slowly and jsonText is read as "" so nothing is processed.
In all of the test runs the json is being sent in the body of the post.
What is the best way to return a httpResponse after making sure the contents of the post is read first?
public HttpResponseMessage Post()
{
string content;
try
{
string result = String.Empty;
Newtonsoft.Json.Linq.JObject jObject = null;
string jsonText = String.Empty;
var syncTask = new Task<string>( () => {
return Request.Content.ReadAsStringAsync().Result;
});
/* I'm expecting that this will finish */
syncTask.RunSynchronously();
jsonText = syncTask.Result;
/* before this line of code executes */
System.Net.Http.HttpResponseMessage response = new HttpResponseMessage();
if (jsonText == "")
{
result = "{\"error\":\"body is empty\"}";
response.StatusCode = System.Net.HttpStatusCode.InternalServerError;
}
else
{
jObject = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.Linq.JRaw.Parse(jsonText);
string ipAddress = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
jObject["ipAddress"] = ipAddress;
Models.JsonXML jsonXml = new JsonXML(jObject.ToString(Newtonsoft.Json.Formatting.None));
System.Xml.XmlDocument document = new System.Xml.XmlDocument();
document.LoadXml(jsonXml.xml);
result = ReferralsManager.ProcessReferral(document);
if (result == "")
{
result = "{}";
}
response.StatusCode = System.Net.HttpStatusCode.OK;
}
response.Content = new StringContent(result);
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
return response;
}
catch (Exception ex)
{
content = ErrorMessage.ServerException(Converter, ex);
return Request.ToResponseMessage(content);
}
finally
{
LogManager.GetCurrentClassLogger().Info(InfoMessage.FUNC_ENDS, "Process Referral");
}
}
The working modified code after the answer from #Mekap is
public class ProcessReferralAddressModel {
public ProcessReferralAddressModel() { }
public string address { get; set; }
public string name { get; set; }
}
public class ProcessReferralModel
{
public ProcessReferralModel()
{
}
public string uuid { get; set; }
public DateTime date { get; set; }
public ProcessReferralAddressModel from { get; set; }
public ProcessReferralAddressModel[] to { get; set; }
public string subject { get; set; }
public string text { get; set; }
public string html { get; set; }
}
/// <summary>
/// Process a referral.
/// </summary>
/// <param name="userid">The userid.</param>
/// <returns></returns>
public HttpResponseMessage Post([FromBody] ProcessReferralModel processReferralModel)
{
string content;
string jsonText = Newtonsoft.Json.JsonConvert.SerializeObject(processReferralModel) ;
try
{
string result = String.Empty;
Newtonsoft.Json.Linq.JObject jObject = null;
System.Net.Http.HttpResponseMessage response = new HttpResponseMessage();
if (jsonText == "" || jsonText == null )
{
result = "{\"error\":\"body is empty\"}";
response.StatusCode = System.Net.HttpStatusCode.InternalServerError;
}
else
{
jObject = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.Linq.JRaw.Parse(jsonText);
string ipAddress = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
jObject["ipAddress"] = ipAddress;
Models.JsonXML jsonXml = new JsonXML(jObject.ToString(Newtonsoft.Json.Formatting.None));
System.Xml.XmlDocument document = new System.Xml.XmlDocument();
document.LoadXml(jsonXml.xml);
result = ReferralsManager.ProcessReferral(document);
if (result == "")
{
result = "{}";
}
response.StatusCode = System.Net.HttpStatusCode.OK;
}
response.Content = new StringContent(result);
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
return response;
}
catch (Exception ex)
{
content = ErrorMessage.ServerException(Converter, ex);
return Request.ToResponseMessage(content);
}
finally
{
LogManager.GetCurrentClassLogger().Info(InfoMessage.FUNC_ENDS, "Process Referral");
}
}
The json you're fetching, for our example will look something like
{ "ID" : 3,
"StringCmd" : "ls -l"
}
For starters, we are going to write a small class who's representing our data in your web api
public class StringCmdModel
{
public StringCmdModel()
{
}
public int ID { get; set; }
public string StringCmd { get; set; }
}
Now, we just have to write our Entry point in our WebAPI :
[HttpPost]
public HttpResponseMessage PostFonction([FromBody] StringCmdModel NewEntry)
You don't have to check for the existence of the data inside the function. But you should still do proper checks on theirs values, in case you get bad formated json or malicious calls.
But, if you get a call with json that is not matching the StringCmdModel you gave in parameter from the body, this function will not be executed, and the server will throw on its own a 500 error.

While trying to upload video using daily motion API i got this error "The request was aborted: The request was canceled."

i am using daily motion API for uploading videos from my application but when try to upload more than 2 MB sized video i get this error "The request was aborted: The request was canceled." and this error invoked by this line of code var responseBytes = client.UploadFile(uploadUrl, fileToUpload);
and this is my code which i am using to upload video
public static void Main(MyVideo video)
{
var accessToken = GetAccessToken();
Authorize(accessToken);
var fileToUpload = video.Path;
var uploadUrl = GetFileUploadUrl(accessToken);
var response = GetFileUploadResponse(fileToUpload, accessToken, uploadUrl);
var uploadedResponse = PublishVideo(response, accessToken);
}
public class UploadResponse
{
public string format { get; set; }
public string acodec { get; set; }
public string vcodec { get; set; }
public int duration { get; set; }
public int bitrate { get; set; }
public string dimension { get; set; }
public string name { get; set; }
public int size { get; set; }
public string url { get; set; }
public string hash { get; set; }
public string seal { get; set; }
public override string ToString()
{
var flags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy;
System.Reflection.PropertyInfo[] infos = this.GetType().GetProperties(flags);
StringBuilder sb = new StringBuilder();
string typeName = this.GetType().Name;
sb.AppendLine(typeName);
sb.AppendLine(string.Empty.PadRight(typeName.Length + 5, '='));
foreach (var info in infos)
{
object value = info.GetValue(this, null);
sb.AppendFormat("{0}: {1}{2}", info.Name, value != null ? value : "null", Environment.NewLine);
}
return sb.ToString();
}
}
private static UploadResponse GetFileUploadResponse(string fileToUpload, string accessToken, string uploadUrl)
{
// ServicePointManager.DefaultConnectionLimit = 900000;
//HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(uploadUrl);
//wr.KeepAlive = false;
//wr.Timeout = System.Threading.Timeout.Infinite;
//wr.ProtocolVersion = HttpVersion.Version10;
var client = new WebClient();
client.Headers.Add("Authorization", "OAuth " + accessToken);
var responseBytes = client.UploadFile(uploadUrl, fileToUpload);
var responseString = Encoding.UTF8.GetString(responseBytes);
var response = JsonConvert.DeserializeObject<UploadResponse>(responseString);
return response;
}
and i have already tried al the possible solutionsu provided on Stackoverflow earlier also done with http execution time and we client time out but not working please someone help me

Error in reading json API

I am trying to fetch a list of products by accessing the API prodvided by the store. Following is my code
public class CKProductAPI
{
public List<ProductListNames> ProductList(string url)
{
List<ProductListNames> objProducts = new List<ProductListNames>();
try
{
var wc = new WebClient();
wc.Headers.Add("Fk-Affiliate-Id", ConfigurationManager.AppSettings["FK-AFFID"]);
wc.Headers.Add("Fk-Affiliate-Token", ConfigurationManager.AppSettings["FK-TKN"]);
string productFeedXml = wc.DownloadString(url);
JObject jObject = (JObject)JsonConvert.DeserializeObject(productFeedXml);
var jProductData = jObject["productInfoList"];
foreach (var item in jProductData)
{
string strproductId, strtitle, strimageUrls, strmaximumRetailPrice, strsellingPrice, strcurrency, strproductBrand, strproductUrl, strinStock;
try { strproductId = item["productBaseInfo"]["productIdentifier"]["productId"].ToString(); }
catch { strproductId = ""; }
try { strtitle = item["productBaseInfo"]["productAttributes"]["title"].ToString(); }
catch { strtitle = ""; }
try { strimageUrls = item["productBaseInfo"]["productAttributes"]["imageUrls"].ToString(); }
catch { strimageUrls = ""; }
try { strmaximumRetailPrice = item["productBaseInfo"]["productAttributes"]["maximumRetailPrice"].ToString(); }
catch { strmaximumRetailPrice = ""; }
try { strsellingPrice = item["productBaseInfo"]["productAttributes"]["sellingPrice"].ToString(); }
catch { strsellingPrice = ""; }
try { strcurrency = item["productBaseInfo"]["productAttributes"]["currency"].ToString(); }
catch { strcurrency = ""; }
try { strproductBrand = item["productBaseInfo"]["productAttributes"]["productBrand"].ToString(); }
catch { strproductBrand = ""; }
try { strproductUrl = item["productBaseInfo"]["productAttributes"]["productUrl"].ToString(); }
catch { strproductUrl = ""; }
try { strinStock = item["productBaseInfo"]["productAttributes"]["inStock"].ToString(); }
catch { strinStock = ""; }
objProducts.Add(new ProductListNames
{
productId = strproductId,
title = strtitle,
imageUrls = strimageUrls,
maximumRetailPrice = strmaximumRetailPrice,
sellingPrice = strsellingPrice,
currency = strcurrency,
productBrand = strproductBrand,
productUrl = strproductUrl,
inStock = strinStock
});
}
}
catch (Exception)
{
throw;
}
return objProducts;
}
public class ProductListNames
{
public string productId { get; set; }
public string title { get; set; }
public string imageUrls { get; set; }
public string maximumRetailPrice { get; set; }
public string sellingPrice { get; set; }
public string currency { get; set; }
public string productUrl { get; set; }
public string productBrand { get; set; }
public string inStock { get; set; }
public string size { get; set; }
}
}
I am getting the following error ::
Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
It seems you are getting xml response.
If adding ACCEPT header doesn't help (as refgor said) then you might need to serialize xml to json first then use it as JObject. This might help.
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
SO Post
You can then parse jsonText using JObject.Parse(jsonText)
It seems to be your source JSON string is invalid or is not actually a JSON string.
Please check HTTP request you are making, whether server delivers you JSON. HTTP service might respond differently based on Accept header you are adding to your HTTP request.
To make sure you are asking service about JSON, you can add Accept: application/JSON HTTP header to your request. Otherwise, server might decide by itself and respond with XML on your request.
If your server responds with JSON then it might help:
var wc = new WebClient();
client.Headers.Set("Accept", "application/json");
You can also check Content-Type of your response but then you need to use another method of WebClient, not a DownloadString

Categories