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){.....}
Related
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)
I am trying to return a JSON for the Web API I am building. The API returns the JSON with \ slashes that makes difficult for my other application to consume this API.
" {\"#odata.context\":\"https://science.com/odata/$metadata#EMPLOYEE\",\"value\":[{\"Id\":5000004,\"Name\":\"Account\"}]}"
But I am expecting a response like
{
"#odata.context": "https://science.com/odata/$metadata#EMPLOYEE",
"value": [
{
"Id": 5000004,
"Name": "Account"
}]}
Below is the code for my Web API
public async Task<string> GetEmployee(string instance)
{
.....
EmployeeDTO.RootObject returnObj = new EmployeeDTO.RootObject();
var responsedata = "";
try
{
using (var client_Core = new HttpClient())
{
....
string core_URL = BaseURL_Core+URL_instance;
var response = client_Core.GetAsync(core_URL).Result;
responsedata = await response.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
throw ex;
}
return responsedata;
}
I have also added the Content type in the WebAPIConfig file like below
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
But I am still getting the JSON with the slashes
responsedata = await response.Content.ReadAsStringAsync();
Above code returns string and you return the same response back. As the result, it is not well-formed JSON you expected.
If you want to return proper JSON, you'll need to convert string to JSON before returning it.
public async Task<Data> GetEmployee(string instance)
{
string responsedata = " {\"#odata.context\":\"https://science.com/odata/$metadata#EMPLOYEE\",\"value\":[{\"Id\":5000004,\"Name\":\"Account\"}]}";
return JsonConvert.DeserializeObject<Data>(responsedata);
}
public class Data
{
[JsonProperty("#odata.context")]
public string ODataContext { get; set; }
public Value[] Value { get; set; }
}
public class Value
{
public int Id { get; set; }
public string Name { get; set; }
}
I am working on a requirement where I need to create multiple issues in one go by Using the REST API. However, I start with uploading a single issue because I am new in API integration. I write few lines of code in c#. Here is my code:
static void Main(string[] args)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
JiraCreateIssueRequest jcir = new JiraCreateIssueRequest();
//////////////////////////////////////////////////////////////////
string sUsername = "aaa#xyz.com";
string sPassword = "TestPassword";
string uri = #"https://domain.atlassian.net/rest/api/2/issue";
Uri address = new Uri(uri);
HttpWebRequest request;
//HttpWebResponse response = null;
StreamReader sr;
string sData = null;
string returnXML = string.Empty;
if (address == null) { throw new ArgumentNullException("address"); }
//jcir.project.ID = 100;
//jcir.Summary = "This issue is created by JIRA REST Api";
//jcir.Description = "This issue is created by JIRA REST Api";
//jcir.IssueType.ID = 1;
sData = #"{""fields"":{""project"":{""key"": ""SITT""},""summary"": ""REST API Uploading"",""description"":""Creating an issue via REST API"",""issuetype"": {""name"": ""Test""}}}";
//sData = jcir.ToString();
try
{
// Create and initialize the web request
request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/json";
// Add the Authorization header to the web request
request.Credentials = new NetworkCredential(sUsername, sPassword);
//Write Data
if (sData != null)
{
byte[] byteData = UTF8Encoding.UTF8.GetBytes(sData);
// Set the content length in the request headers
request.ContentLength = byteData.Length;
// Write data
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
// Get response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
string str = reader.ReadToEnd();
}
}
}
catch (WebException wex)
{
// This exception will be raised if the server didn't return 200 - OK
// Try to retrieve more information about the error
if (wex.Response != null)
{
using (HttpWebResponse errorResponse = (HttpWebResponse)wex.Response)
{
try
{
string sError = string.Format("The server returned '{0}' with the status code {1} ({2:d}).",
errorResponse.StatusDescription, errorResponse.StatusCode,
errorResponse.StatusCode);
sr = new StreamReader(errorResponse.GetResponseStream(), Encoding.UTF8);
returnXML = sr.ReadToEnd();
}
finally
{
if (errorResponse != null) errorResponse.Close();
}
}
}
else
{
throw new Exception(wex.Message);
}
}
}
public class JiraCreateIssueRequest
{
protected JavaScriptSerializer jss = new JavaScriptSerializer();
public JiraProject project = new JiraProject();
public string Summary { get; set; }
public string Description { get; set; }
public JiraIssueType IssueType = new JiraIssueType();
public override string ToString()
{
return jss.Serialize(this);
}
}
public class JiraCreateIssueResponse
{
}
public class JiraProject
{
public int ID { get; set; }
//public string Key { get; set; }
}
public class JiraIssueType
{
public int ID { get; set; }
//public string Name { get; set; }
}
But when I am running the above code, I am getting the '400' error. I googled it and found that this usually this error comes when the URL or the Username/Password are incorrect. I cross checked both the things however its correct.
May I know why this error is coming or what will be the resolution of the problem?
Your password is not your login password, it's an API token that you get from here:
https://id.atlassian.com/manage/api-tokens
Generate a token, then use that as your password.
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?
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
{
}