Using a timeout callback in async requests - c#

I asked this question before but I'm going to complete the question with a solution proposed and make another question.
I'm using this class to make an async WebRequest:
class HttpSocket
{
public static void MakeRequest(Uri uri, Action<RequestCallbackState> responseCallback)
{
WebRequest request = WebRequest.Create(uri);
request.Proxy = null;
Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, 1000, true);
asyncTask.ContinueWith(task =>
{
WebResponse response = task.Result;
Stream responseStream = response.GetResponseStream();
responseCallback(new RequestCallbackState(response.GetResponseStream()));
responseStream.Close();
response.Close();
});
}
private static void TimeoutCallback(object state, bool timedOut)
{
Console.WriteLine("Timeout: " + timedOut);
if (timedOut)
{
Console.WriteLine("Timeout");
WebRequest request = (WebRequest)state;
if (state != null)
{
request.Abort();
}
}
}
}
And i'm testing the class with this code:
class Program
{
static void Main(string[] args)
{
// Making a request to a nonexistent domain.
HttpSocket.MakeRequest(new Uri("http://www.google.comhklhlñ"), callbackState =>
{
if (callbackState.Exception != null)
throw callbackState.Exception;
Console.WriteLine(GetResponseText(callbackState.ResponseStream));
});
Thread.Sleep(100000);
}
public static string GetResponseText(Stream responseStream)
{
using (var reader = new StreamReader(responseStream))
{
return reader.ReadToEnd();
}
}
}
Once executed, the callback is reached immediately, showing "Timeout: false" and there aren't more throws, so the timeout isn't working.
This is a solution proposed in the original thread but, as you could see, the code works for him.
What I'm doing wrong?
EDIT: Other classes used by the code:
class RequestCallbackState
{
public Stream ResponseStream { get; private set; }
public Exception Exception { get; private set; }
public RequestCallbackState(Stream responseStream)
{
ResponseStream = responseStream;
}
public RequestCallbackState(Exception exception)
{
Exception = exception;
}
}
class RequestState
{
public byte[] RequestBytes { get; set; }
public WebRequest Request { get; set; }
public Action<RequestCallbackState> ResponseCallback { get; set; }
}

This approach works. I would recommend switching this to explicitly handle exceptions (including your timeout, but also bad domain names, etc) slightly differently. In this case, I've split this into a separate continuation.
In addition, in order to make this very explicit, I've shorted the timeout time, put a "real" but slow domain in, as well as added an explicit timeout state you can see:
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
class HttpSocket
{
private const int TimeoutLength = 100;
public static void MakeRequest(Uri uri, Action<RequestCallbackState> responseCallback)
{
WebRequest request = WebRequest.Create(uri);
request.Proxy = null;
Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, TimeoutLength, true);
asyncTask.ContinueWith(task =>
{
WebResponse response = task.Result;
Stream responseStream = response.GetResponseStream();
responseCallback(new RequestCallbackState(response.GetResponseStream()));
responseStream.Close();
response.Close();
}, TaskContinuationOptions.NotOnFaulted);
// Handle errors
asyncTask.ContinueWith(task =>
{
var exception = task.Exception;
var webException = exception.InnerException;
// Track whether you cancelled or not... up to you...
responseCallback(new RequestCallbackState(exception.InnerException, webException.Message.Contains("The request was canceled.")));
}, TaskContinuationOptions.OnlyOnFaulted);
}
private static void TimeoutCallback(object state, bool timedOut)
{
Console.WriteLine("Timeout: " + timedOut);
if (timedOut)
{
Console.WriteLine("Timeout");
WebRequest request = (WebRequest)state;
if (state != null)
{
request.Abort();
}
}
}
}
class RequestCallbackState
{
public Stream ResponseStream { get; private set; }
public Exception Exception { get; private set; }
public bool RequestTimedOut { get; private set; }
public RequestCallbackState(Stream responseStream)
{
ResponseStream = responseStream;
}
public RequestCallbackState(Exception exception, bool timedOut = false)
{
Exception = exception;
RequestTimedOut = timedOut;
}
}
class RequestState
{
public byte[] RequestBytes { get; set; }
public WebRequest Request { get; set; }
public Action<RequestCallbackState> ResponseCallback { get; set; }
}
class Program
{
static void Main(string[] args)
{
// Making a request to a nonexistent domain.
HttpSocket.MakeRequest(new Uri("http://www.tanzaniatouristboard.com/"), callbackState =>
{
if (callbackState.RequestTimedOut)
{
Console.WriteLine("Timed out!");
}
else if (callbackState.Exception != null)
throw callbackState.Exception;
else
Console.WriteLine(GetResponseText(callbackState.ResponseStream));
});
Thread.Sleep(100000);
}
public static string GetResponseText(Stream responseStream)
{
using (var reader = new StreamReader(responseStream))
{
return reader.ReadToEnd();
}
}
}
This will run, and show a timeout appropriately.

Use 2 different classes:
class RequestCallbackException : Exception
{
public RequestCallbackException(Stream responseStream, Exception exception) : base(exception)
{
}
}
and
class RequestCallbackStream
{
public Stream ResponseStream { get; private set; }
public RequestCallbackState(Stream responseStream)
{
ResponseStream = responseStream;
}
}
You will notice that sometimes GetResponseStream() returns null, which immediately raise an exception in
asyncTask.ContinueWith() -->
GetResponseText(callbackState.ResponseStream)-->
using (var reader = new StreamReader(responseStream)) // responseStream is null
{
}

Related

Json request on asp.net core 3.1

I trie to pass my item Reach_DeclarationBc
public class Reach_DeclarationBc
{
public int ArticleId { get; set; }
public DateTime DateDeclaration { get; set; }
}
I use this code for call my api
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:3001/");
Reach_DeclarationBc reach_DeclarationBc = new Reach_DeclarationBc
{
ArticleId = 129,
DateDeclaration = DateTime.Now
};
Reach_DeclarationBc result = await client.PostJsonAsync<Reach_DeclarationBc>("http://localhost:3009/reach", reach_DeclarationBc);
But a this line this give me an error
Reach_DeclarationBc result = await client.PostJsonAsync<Reach_DeclarationBc>("http://localhost:3009/reach", reach_DeclarationBc);
The error is : "TypeLoadException: Could not load type 'Microsoft.JSInterop.Json' from assembly 'Microsoft.JSInterop, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'."
The using in my class is
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Projet_Airbus.Data;
using Projet_Airbus.Models;
using Projet_Airbus.Models.Declaration;
using Microsoft.AspNetCore.Blazor;
using System.Net.Http;
For solve i tri to use asp.net core 3.1 but this not work
This is how I usually do it.
I inject a singleton HttpClient and logger with a dependency injector like Ninject.
I make a generic SendAsync which can handle PUT/DELETE/POST/GET.
I make ApiResponse class that contains the properties I'm interested in.
I create a Request class (InitRequest) that I use for the request.
I create a Response class (InitResponse) that I use for the response.
I have TimeOutInMs to set the time out for the api call.
I have a logger that logs error.
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;
using Newtonsoft.Json;
public class HomeController : Controller
{
private readonly WebApi _webApi;
//Inject singleton httpclient and logger
public HomeController(HttpClient httpClient, ILogger logger)
{
_webApi = new WebApi(httpClient, logger);
_webApi.BaseAddress = "https://www.webapi.com/";
_webApi.TimeOutInMs = 2000;
}
public async Task<ActionResult> Index()
{
//You might want to move the web api call to a service class
var method = "init";
var request = new InitRequest
{
Id = 1,
Name = "Bob"
};
var response = await _webApi.SendAsync<InitResponse>(method, request, HttpMethod.Post);
if (response.StatusCode == HttpStatusCode.OK)
{
var viewModel = response.Data.ToIndexViewModel();
}
else
{
//Handle Error
}
return View(viewModel);
}
}
public class IndexViewModel
{
public string Name { get; set; }
public string Address { get; set; }
}
public static class ModelMapper
{
public static IndexViewModel ToIndexViewModel(this InitResponse response)
{
return new IndexViewModel
{
Name = response.Name,
Address = response.Address
};
}
}
public class InitRequest
{
public int Id { get; set; }
public string Name { get; set; }
}
public class InitResponse
{
public string Name { get; set; }
public string Address { get; set; }
}
public class WebApi
{
private readonly HttpClient _httpClient;
private readonly ILogger _logger;
public Uri BaseAddress { get; set; }
public int TimeOutInMs { get; set; }
public WebApi(HttpClient httpClient, ILogger logger)
{
_logger = logger ?? throw new Exception($"Missing constructor ceference - {nameof(logger)} can not be null!");
_httpClient = httpClient ?? throw new Exception($"Missing constructor ceference - {nameof(httpClient)} can not be null!");
}
public async Task<ApiResponse<TOut>> SendAsync<TOut>(string method, object param, HttpMethod httpMethod)
{
if (string.IsNullOrWhiteSpace(BaseAddress.ToString()))
throw new Exception($"{nameof(BaseAddress)} can not be null or empty.");
if (string.IsNullOrWhiteSpace(method))
throw new Exception($"{nameof(method)} can not be null or empty.");
var paramListForLog = JsonConvert.SerializeObject(param);
//Set timeout
if (TimeOutInMs <= 0)
{
TimeOutInMs = (int)TimeSpan.FromSeconds(100.0).TotalMilliseconds;
}
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromMilliseconds(TimeOutInMs));
var cancellationToken = cts.Token;
var url = new Uri($"{BaseAddress}{method}", UriKind.Absolute);
try
{
HttpResponseMessage response;
using (var request = new HttpRequestMessage(httpMethod, url))
{
//Add content
if (param != null)
{
var content = JsonConvert.SerializeObject(param);
request.Content = new StringContent(content, Encoding.UTF8, "application/json");
}
//Add headers
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_logger.Info($"Calling {httpMethod} for {url}", paramListForLog);
//Send the request
response = await _httpClient.SendAsync(request, cancellationToken);
}
//If success
if (response.IsSuccessStatusCode)
{
_logger.Info($"Successfully called {httpMethod} for {url}", paramListForLog);
var data = await response.Content.ReadAsAsync<TOut>(cancellationToken);
return new ApiResponse<TOut>
{
StatusCode = response.StatusCode,
Data = data
};
}
//If failure
var error = await response.Content.ReadAsStringAsync();
_logger.Error($"An error occured calling {httpMethod} for {url}. Error was {error}", paramListForLog);
return new ApiResponse<TOut>
{
StatusCode = response.StatusCode,
Message = error
};
}
//If timeout
catch (OperationCanceledException ex)
{
var message = cancellationToken.IsCancellationRequested ?
$"Request timed out after {TimeOutInMs} ms occured calling {httpMethod} for {url}. Error was: {ex.Message}" :
$"An error occured calling {httpMethod} for {url}. Error was: {ex.Message}";
var webEx = new Exception(message, ex);
_logger.Error(webEx, webEx.Message, paramListForLog);
return new ApiResponse<TOut>
{
StatusCode = HttpStatusCode.RequestTimeout,
Message = message
};
}
//If unknown error
catch (Exception ex)
{
var webEx = new Exception($"An error occured calling {httpMethod} for {url}. Error was: {ex.Message}", ex);
_logger.Error(webEx, webEx.Message, paramListForLog);
throw webEx;
}
}
}
public interface ILogger
{
void Info(string message, string param);
void Error(string message, string param);
void Error(Exception e, string message, string param);
}
public class ApiResponse<T>
{
public HttpStatusCode StatusCode { get; set; }
public string Message { get; set; }
public T Data { get; set; }
}

C# sync function to async

How I can change this function to async with Framework 4.6.1? The DGV has a lot of data and blocks the rest of the processes.
DGV is updated every 30 seconds with timer.
any other solution do not block the next process until this is finnished?
I may have something wrong, I am starting in the world of programming and I have many things to learn.
private void FillTimes()
{
var strResponse = CallJson($"RESTAPI URL");
if (strResponse != null)
{
var jResult = JsonConvert.DeserializeObject<JsonResults>(strResponse);
BindingSource bsResults = new BindingSource();
bsResults.DataSource = jResult.Results;
if (bsResults.DataSource != null)
{
DgvOnline.DataSource = bsResults.DataSource;
}
}
}
CallJson
private string CallJson(string strURL)
{
RestTiming rJson = new RestTiming();
rJson.endPoint = strURL;
rJson.token = apiToken;
string strResponse = string.Empty;
strResponse = rJson.makeRequest();
return strResponse;
}
ResTiming
using System;
using System.IO;
using System.Net;
using System.Windows.Forms;
namespace Timing
{
public enum httpVerb
{
GET,
POST,
PUT,
DELETE
}
class RestTiming
{
public string endPoint { get; set; }
public string token { get; set; }
public httpVerb httpMethod { get; set; }
public string userName { get; set; }
public string userPassword { get; set; }
public string postJSON { get; set; }
public RestTiming()
{
endPoint = string.Empty;
token = string.Empty;
}
public string makeRequest()
{
if (InternetAvailable())
{
string strResponseValue = string.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
request.Method = httpMethod.ToString();
request.ContentType = "application/json";
request.Accept = "application/json";
request.Headers.Add("Authorization", token);
request.UserAgent = #"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36";
if ((request.Method == "POST" || request.Method == "PUT") && postJSON != string.Empty)
{
using (StreamWriter swJSONPayload = new StreamWriter(request.GetRequestStream()))
{
swJSONPayload.Write(postJSON);
swJSONPayload.Close();
}
}
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
// Process the response stream... (could be JSON, XML or HTML etc...)
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream))
{
strResponseValue = reader.ReadToEnd();
}// End of StreamReader
}
}// End of using ResponseStream
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null)
{
var resp = (HttpWebResponse)ex.Response;
if (resp.StatusCode == HttpStatusCode.Unauthorized)
{
MessageBox.Show("Unauthorized", "Unauthorized", MessageBoxButtons.OK, MessageBoxIcon.Stop);
Environment.Exit(1);
}
}
}
return strResponseValue;
}
else
{
return null;
}
}
private static Boolean InternetAvailable()
{
try
{
using (WebClient client = new WebClient())
{
using (client.OpenRead("http://www.google.com/"))
{
return true;
}
}
}
catch
{
return false;
}
}
}
}
Thanks
I'm not going to weigh in on whether your code should be async or not.
If you want the synchronous work to happen in a background thread, you can execute it using Task.Run as follows:
private async Task FillTimes()
{
return Task.Run(() => {
{
var strResponse = CallJson($"RESTAPI URL");
if (strResponse != null)
{
var jResult = JsonConvert.DeserializeObject<JsonResults>(strResponse);
BindingSource bsResults = new BindingSource();
bsResults.DataSource = jResult.Results;
if (bsResults.DataSource != null)
{
DgvOnline.DataSource = bsResults.DataSource;
}
}
}
}
Update
If CallJson is IO Bound work then you could make that async, also you would append the Async suffix to the the method name to be consistent. Your resulting method would look like this.
private async Task FillTimes()
{
var strResponse = await CallJsonAsync($"RESTAPI URL");
if (strResponse != null)
{
var jResult = JsonConvert.DeserializeObject<JsonResults>(strResponse);
BindingSource bsResults = new BindingSource();
bsResults.DataSource = jResult.Results;
if (bsResults.DataSource != null)
{
DgvOnline.DataSource = bsResults.DataSource;
}
}
}
And your async method would look like this
private async Task<responseType> CallJsonAsync(<something>)
{
...
await SomethingAsync(...);
...
return something;
}
Original
How I can change this function to async with Framework 4.6.1
There is no obvious IO Bound work, and no method that would lend itself towards an async call (that i can see).
So to answer the question, "How I can change this function to async?", the answer is you shouldn't, let it be synchronous.
If this does not update the UI, you could call this method from a Task, and await that
Updated
class RestTiming
{
public string endPoint { get; set; }
public string token { get; set; }
public httpVerb httpMethod { get; set; }
public string userName { get; set; }
public string userPassword { get; set; }
public string postJSON { get; set; }
public RestTiming()
{
endPoint = string.Empty;
token = string.Empty;
}
public async Task<string> makeRequest() //1. Changed to async and return type
{
if (InternetAvailable())
{
string strResponseValue = string.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
request.Method = httpMethod.ToString();
request.ContentType = "application/json";
request.Accept = "application/json";
request.Headers.Add("Authorization", token);
request.UserAgent = #"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36";
if ((request.Method == "POST" || request.Method == "PUT") && postJSON != string.Empty)
{
using (StreamWriter swJSONPayload = new StreamWriter(await request.GetRequestStreamAsync())) //2. changed to asynchronous call
{
swJSONPayload.Write(postJSON);
swJSONPayload.Close();
}
}
WebResponse response = null; //(a) updated
try
{
response =await request.GetResponseAsync();
// Process the response stream... (could be JSON, XML or HTML etc...)
using (Stream responseStream =response.GetResponseStream()) //(b) updated
{
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream))
{
strResponseValue = await reader.ReadToEndAsync(); // (c) updated
}// End of StreamReader
}
}// End of using ResponseStream
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null)
{
var resp = (HttpWebResponse)ex.Response;
if (resp.StatusCode == HttpStatusCode.Unauthorized)
{
MessageBox.Show("Unauthorized", "Unauthorized", MessageBoxButtons.OK, MessageBoxIcon.Stop);
Environment.Exit(1);
}
}
}
return strResponseValue;
}
else
{
return null;
}
}
private static Boolean InternetAvailable()
{
try
{
using (WebClient client = new WebClient())
{
using (client.OpenRead("http://www.google.com/"))
{
return true;
}
}
}
Changes in the second method
private async Task<string> CallJson(string strURL) //1. Changed to async and return type
{
RestTiming rJson = new RestTiming();
rJson.endPoint = strURL;
rJson.token = apiToken;
string strResponse = string.Empty;
strResponse =await rJson.makeRequest(); //2. made asynchronous
return strResponse;
}
The change in the first method
private async Task FillTimes() // 1. Make async and change return type
{
var strResponse =await CallJson($"RESTAPI URL"); // 2. add await to make asynchronous
...
}
Please let me know if this helps.
Additionally, check this link (Getting the Response of a Asynchronous HttpWebRequest)

WebException rethrow

Here is the following code:
public static string Post(string requestUriString, string s)
{
var request = (HttpWebRequest)WebRequest.Create(requestUriString);
var data = Encoding.ASCII.GetBytes(s);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
try
{
var response = (HttpWebResponse)request.GetResponse();
return new StreamReader(response.GetResponseStream()).ReadToEnd();
}
catch (WebException webException)
{
Console.WriteLine(webException);
throw;
}
}
When the program throws an exception, the try / catch block works correctly.
However when I try to rethrow the exception, the program crashes.
It should crash as you don't handle exception re-throw, you need to try catch in Main() method as below.
static void Main(string[] args)
{
try
{
Post("https://stackoverflow.com/", "test");
}
catch (Exception)
{
// Handle exception re-throw,
}
}
Do something like this:
class Program {
static void Main(string[] args) {
var response = Post(...);
if(response.Status == "success") {
//ok
} else {
//request failed
}
}
public static string Post(string requestUriString, string s) {
var request = (HttpWebRequest)WebRequest.Create(requestUriString);
var data = Encoding.ASCII.GetBytes(s);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream()) {
stream.Write(data, 0, data.Length);
}
try {
var response = (HttpWebResponse)request.GetResponse();
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
return new Response("success", body);
} catch (WebException webException) {
Console.WriteLine(webException);
return new Response("failed", "");
}
}
class Response {
public string Status { get; private set; }
public string Body { get; private set; }
public Response(string status, string response) {
Status = status;
Body = response;
}
}
}
Depending on your needs & app size you could make the status an enum based on the http response code(200/404/500...) etc and add some more handling because the sample I posted isn't something you should use for something bigger or production critical.
You mentioned it's a console app, if it's just something that does a single request and nothing else this should do the job just fine.
Problem solved with this code :
using System.Net;
using System.Text;
using System.IO;
using System;
namespace Botnet
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine(Post("http://www.example.com/recepticle.aspx", "thing1=hello&thing2=world"));
}
catch (WebException webException)
{
Console.WriteLine(webException);
}
finally
{
Console.ReadLine();
}
}
public static string Post(string requestUriString, string s)
{
var request = (HttpWebRequest)WebRequest.Create(requestUriString);
var data = Encoding.ASCII.GetBytes(s);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
try
{
var response = (HttpWebResponse)request.GetResponse();
return new StreamReader(response.GetResponseStream()).ReadToEnd();
}
catch (WebException webException)
{
Console.WriteLine(webException);
throw;
}
}
}
}
Hi I will modify previous answer a little bit.
class Response<T> {
public HttpStatusCode Status { get; private set; }
public T Body { get; private set; }
public bool Success { get; private set; }
public string Reason {get; private set; }
public Response(T body) {
Success = true;
Body = body;
HttpStatusCode = HttpStatusCode.OK
}
public Response(string reason)
{
Reason = reason;
Success = false;
Status = HttpStatusCode.BadRequest;
}
public Response( string reason, HttpStatusCode status)
{
Reason = reason;
Status = status;
Success = false;
}
}
This is more generic solution.

invalid casting exception from datacontract json serializer

I am working on a project for Windows Phone 7.1 in Visual Studio 2010. I am trying to download JSON data and deserialize it into a list of objects. The following is the code I am using to build the web request and handle the response.
public class HttpGetTask<T>
{
public HttpGetTask(string url, Action<T> onPostExecute)
{
this.Url = url;
this.OnPostExecute = onPostExecute;
}
public void Execute()
{
MessageBox.Show("We are in the task Execute method");
if (this.OnPreExecute != null)
{
this.OnPreExecute();
}
// create the http request
HttpWebRequest httpWebRequest = WebRequest.CreateHttp(this.Url);
httpWebRequest.Method = "GET";
httpWebRequest.Accept = "application/json";
// get the response asynchronously
httpWebRequest.BeginGetResponse(OnGetResponseCompleted, httpWebRequest);
}
private void OnGetResponseCompleted(IAsyncResult ar)
{
MessageBox.Show("We are in the OnGetResponseCompleted Method");
var httpWebRequest = (HttpWebRequest)ar.AsyncState;
// get the response
HttpWebResponse response;
try
{
response = (HttpWebResponse)httpWebRequest.EndGetResponse(ar);
}
catch (WebException e)
{
this.InvokeOnErrorHandler("Unable to connect to the web page.");
return;
}
catch (Exception e)
{
this.InvokeOnErrorHandler(e.Message);
return;
}
if (response.StatusCode != HttpStatusCode.OK)
{
this.InvokeOnErrorHandler((int)response.StatusCode + " " + response.StatusDescription);
return;
}
// response stream
var stream = response.GetResponseStream();
// deserialize json
var jsonSerializer = new DataContractJsonSerializer(typeof(T));
var responseObject = (T)jsonSerializer.ReadObject(stream);
// call the virtual method
this.InvokeInUiThread(() => this.OnPostExecute(responseObject));
}
The following are the DataContract classes I am using.
[DataContract]
public class OwnersList
{
public List<Owner> Owners {get; set; }
}
[DataContract]
public class Owner
{
[DataMember(Name = "oid")]
public string Oid { get; set; }
[DataMember(Name = "fname")]
public string Fname { get; set; }
[DataMember(Name = "lname")]
public string Lname { get; set; }
}
The following is a sample of te JSON data I am trying to deserialize.
[{"oid":"1","fname":"John","lname":"Doe"},{"oid":"2","fname":"Mary","lname":"Smith"},{"oid":"3","fname":"Jimi","lname":"Hendrix"},{"oid":"4","fname":"Carole","lname":"King"},{"oid":"5","fname":"John","lname":"Winchester"},{"oid":"6","fname":"John","lname":"Hurt"},{"oid":"7","fname":"Rick","lname":"Grimes"},{"oid":"8","fname":"Haris","lname":"Okic"},{"oid":"9","fname":"Dino ","lname":"Okic"},{"oid":"10","fname":"Mirza","lname":"Cirkic"}]
When I run my app, I get an Invalid Casting Exception either when creating the serializer object, or on the jsonserializer.ReadObject(stream) line. Any ideas as to why this is happening?

How to check JArray is empty

I am calling an API through a HttpClient and getting a response like follows.
{
"result_set": []
}
I parsed the response in to a dynamic object.
dynamic dbResponseBody = await dbResponse.Content.ReadAsAsync<object>();
How to check the result_set is empty or not. Currently I am doing as follows but looking for a better way.
if (dbResponseBody.Result.result_set != "[]") {}
You can construct a model for your response if you know the type.
class Response
{
[JsonProperty("result_set")]
public List<string> ResultSet { get; set; }
}
If your items in your array model are more complex you can construct the following
class Response
{
[JsonProperty("result_set")]
public List<Items> ResultSet { get; set; }
}
class Items{
[JsonProperty("P1")]
public string P1 { get; set; }
[JsonProperty("P2")]
public int P2 { get; set; }
}
Then you can read your response as follows:
using (HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse)
{
if (response != null && response.StatusCode != HttpStatusCode.OK)
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
response.StatusCode,
response.StatusDescription));
if (response != null)
{
Stream responseStream = response.GetResponseStream();
Respose myResponse = GetResponseModel<Response>(responseStream);
}
else throw new Exception("My message");
Using Newtonsoft you can get the model back again
protected T GetResponseModel<T>(Stream respStream) where T : class
{
if (respStream != null)
{
var respStreamReader = new StreamReader(respStream);
Task<string> rspObj = respStreamReader.ReadToEndAsync();
rspObj.Wait();
Debug.WriteLine("Response: {0}", rspObj.Result);
T jsonResponse = JsonConvert.DeserializeObject<T>(rspObj.Result);
return jsonResponse;
}
return default(T);
}
At the end after this line you can check the properties of your model
Respose myResponse = GetResponseModel<Response>(responseStream);
if(myResponse.Result.Count == 0){.....}

Categories

Resources