I am writing a windows service to get some data from my database, then send it to my provider and get the response. I have some issues which make me simulate a console application to test my code.
Here is my code:
static async Task Main(string[] args)
{
send();
}
public static DataSet dataAccess()
{
DataSet ds = new DataSet();
ds.Tables.Add();
ds.Tables.Add();
ds.Tables[0].Columns.Add("id");
ds.Tables[0].Columns.Add("token");
ds.Tables[1].Columns.Add("token_id");
ds.Tables[1].Columns.Add("type");
ds.Tables[1].Columns.Add("value");
ds.Tables[0].Rows.Add("1", "token1");
ds.Tables[0].Rows.Add("2", "token2");
ds.Tables[1].Rows.Add("1", "t1", "v1");
ds.Tables[1].Rows.Add("1", "t1", "v2");
ds.Tables[1].Rows.Add("1", "t2", "v3");
ds.Tables[1].Rows.Add("2", "t2", "v4");
ds.Tables[1].Rows.Add("2", "t3", "v5");
ds.Tables[1].Rows.Add("2", "t3", "v6");
ds.Tables[1].Rows.Add("2", "t4", "v7");
ds.Relations.Add("rel_token", ds.Tables[0].Columns["id"], ds.Tables[1].Columns["token_id"]);
return ds;
}
private static async Task send()
{
DataSet ds;
DataTable dt;
while (true)
{
try
{
ds = dataAccess();
if (ds == null)
{
break;
}
List<Task> lst = new List<Task>();
foreach (DataRow dr in ds.Tables[0].Rows)
{
dt = dr.GetChildRows("rel_token").CopyToDataTable();
dt.Columns.Remove("token_id");
lst.Add(send_call((dr["token"]).ToString(), dt));
}
await Task.WhenAll(lst);
await Task.Delay(30000);
}
catch (HttpRequestException e)
{
string erMsg = e.Message;
}
}
}
private static HttpClient req { get; set; }
private static async Task send_call(string strToken, DataTable dt)
{
try
{
// DataTable to Json
string strJson = "";
foreach (DataRow dr in dt.Rows)
{
if (dt.Rows.IndexOf(dr) > 0)
{
strJson += ",";
}
strJson += "{";
foreach (DataColumn dc in dt.Columns)
{
if (dr.IsNull(dc))
{
continue;
}
if (dt.Columns.IndexOf(dc) > 0)
{
strJson += ",";
}
strJson += string.Format("\"{0}\":{1}{2}{1}",
dc.ColumnName,
dc.DataType == typeof(string) || dc.DataType == typeof(Guid) ? "\"" : null,
dc.DataType == typeof(bool) ? dr[dc].ToString().ToLower() : dr[dc]);
}
strJson += "}";
}
//
req.DefaultRequestHeaders.Add("token", strToken);
StringContent sc = new StringContent(strJson, Encoding.UTF8, "application/json");
HttpResponseMessage res = await req.PostAsync("my webhook url", sc);
string response = await res.Content.ReadAsStringAsync();
using (StreamWriter sw = new StreamWriter(#"C:\responseJson.txt", true, Encoding.UTF8))
{
sw.WriteLine(response);
}
}
catch (HttpRequestException e)
{
string strError = e.Message;
}
}
Code explanation:
I want to post each token child data separately which in each call,
header value is different.
Each time dataAccess() value is different, I just use a static data
for simulation.
Issues:
When I run the program I see no request in destination, so I start debugging and noticed the pointer will reach this line:
HttpResponseMessage res = await req.PostAsync("my webhook url", sc);
But the call wouldn't initiated and after that the pointer comes back at:
await Task.WhenAll(lst);
then comes to:
send();
And finished!
So the PostAsync method didn't work and due to that response didn't fill so the responseJson.txt didn't created.
Things I have tried:
Instead of send(); I used await send(); but I faced this error:
System.NullReferenceException: 'Object reference not set to an
instance of an object.
I have checked the strJson. The list converted to JSON properly.
I have checked my connection through another program, I could make
call to my webhook url.
Note: I had asked this question yesterday but because I explained it complicatedly I deleted that today and design a smaller one.
Create the HttpClient before trying to use it, by using the new keyword.
private static HttpClient req { get; set; } = new HttpClient();
public async Task Main()
{
await send();
}
Related
I have a .net core API service which is called from a angular client project.
When a user request a status of his payment, we will make call to this service api and this service will then call a payment gateway service to fetch the status of payment and the output result will return to the user.
When i try to integrate this i am facing this below error.
net::ERR_CONNECTION_RESET 200 (OK)
core.js:5967 ERROR Unknown Error
This above issue is not showing when i try to hit the service after putting one breakpoint. Its also returning the result.
This is how entire flow works
Client side call performs by user
this.dataservice.postFeed(method, JSON.stringify(this.initsearch)).subscribe(result => {
var response = result.body["data"];
console.log(response);
});
Server side code looks like
[HttpPost]
public async Task<IActionResult> Post([FromBody] ObjectModel searchValue)
{
ApiResponse<string> response = new ApiResponse<string>();
IBaseResult<string> result = await _adlerBo.GetPaymentStatus(searchValue);
response.Success = result.success;
response.Data = result.Data;
return Ok(response);
}
In BusinessObject.cs
public async Task<IBaseResult<string>> GetPaymentStatus(PaymentSearchModel requestModel){
string apiResponse = await PaymentStatusCheckUsingAPI(requestModel.orderid);
return apiResponse ;
}
private async Task<string> PaymentStatusCheckUsingAPI(string orderNumber)
{
string message = await PostPaymentRequestToGateway(statusApiUrl, authQueryUrlParam);
NameValueCollection param = await GetResponseMap(message);
string status = "";
string encResJson = "";
if (param != null && param.Count == 2)
{
for (int i = 0; i < param.Count; i++)
{
if ("status".Equals(param.Keys[i]))
{
status = param[i];
}
if ("enc_response".Equals(param.Keys[i]))
{
encResJson = param[i];
}
}
if (!"".Equals(status) && status.Equals("0"))
{
resJson = crypto.Decrypt(encResJson, workingKey);
}
else if (!"".Equals(status) && status.Equals("1"))
{
Console.WriteLine("failure response: " + encResJson);
}
}
return resJson;
}
private async Task<string> PostPaymentRequestToGateway(string queryUrl, string urlParam)
{
string message = "";
try
{
StreamWriter myWriter = null;// it will open a http connection with provided url
WebRequest objRequest = WebRequest.Create(queryUrl);//send data using objxmlhttp object
objRequest.Method = "POST";
//objRequest.ContentLength = TranRequest.Length;
objRequest.ContentType = "application/x-www-form-urlencoded";//to set content type
myWriter = new System.IO.StreamWriter(objRequest.GetRequestStream());
myWriter.Write(urlParam);//send data
myWriter.Close();//closed the myWriter object
// Getting Response
System.Net.HttpWebResponse objResponse = (System.Net.HttpWebResponse)objRequest.GetResponse();//receive the responce from objxmlhttp object
using (System.IO.StreamReader sr = new System.IO.StreamReader(objResponse.GetResponseStream()))
{
message = await sr.ReadToEndAsync();
//Response.Write(message);
}
}
catch (Exception exception)
{
Console.Write("Exception occured while connection." + exception);
}
return message;
}
private async Task<NameValueCollection> GetResponseMap(string message)
{
//await Task.Delay(2000); I did this with no Luck
NameValueCollection Params = new NameValueCollection();
if (message != null || !"".Equals(message))
{
string[] segments = message.Split('&');
foreach (string seg in segments)
{
string[] parts = seg.Split('=');
if (parts.Length > 0)
{
string Key = parts[0].Trim();
string Value = parts[1].Trim();
Params.Add(Key, Value);
}
}
}
return await Task.FromResult(Params);
}
Any idea how to fix this? Why its working when i put breakpoint and not otherwise.
Am i doing correct asynchronous implimentsion in my api?
I had this piece of code that initially worked fine. However, After adding it to a class where I store my methods that are reused, it keeps failing. The exception that is caught states that the CancellationTokenSource has been Disposed. Can someone point me in the right direction?
I have tried creating a new client and Adding CancellationToken.None to the PutAsync() method from HTTPClient Class but it still fails with the CancellationTokenSource Disposed exception.
public async void AddProduct(Product product)
{
string storeId = "";
try
{
var storeData = JObject.Parse(Connect.Json).SelectToken("store").ToString();
var stores = JsonConvert.DeserializeObject<List<Store>>(storeData);
var store = stores[0];
storeId = store.Id;
store.Products.Add(product);
ProdInfo info = new Info();
foreach(Product p in store.Products)
{
info.AddedProducts = + p.Id;
}
var content = JsonConvert.SerializeObject(info);
using (Connect.Client)
using (var response = await Connect.Client.PutAsync(_url + "/stores/" + storeId, new StringContent(content)))
{
var cont = response.Content;
string result = await cont.ReadAsStringAsync();
if ((int)response.StatusCode == 200)
{
this.JobResult = result;
//this.JobResult = "Store has been successfully updated";
}
else
{
this.JobResult = result;
//this.JobResult = "Store was not updated!";
}
}
}
catch (Exception ex)
{
//this.JobResult = "Store has not been updated due to an error.";
this.JobResult = ex.Message;
}
}
I was able to solve this by simple removing 'using(Connect.Client)' from all of my methods. As #sellotape stated, They were disposing of the HttpClient before I was able to use it again. Thank you all for your contributions.
I am working on bot technology, in one of my projet i wrote below lines of code
private async void DeliveryProgressReport(IDialogContext context, Activity message)
{
MessagesController.progressdetails = SQLDatabaseService.getinprogressdetails();
var progress = MessagesController.progressdetails;
if (progress.Count > 0)
{
try
{
Activity replyToConversation = message.CreateReply("**In Progress Report Details**");
replyToConversation.Recipient = message.From;
replyToConversation.Type = "message";
replyToConversation.Attachments = new List<Attachment>();
Dictionary<string, string> progresslist = new Dictionary<string, string>();
foreach (var progressreport in progress)
{
//Invoke the machine learning model for predicting the delivery status of delivery person
//var deliveryStatus= await InvokeRequestResponseServiceOfDeliveryPersonPredictionExp1();
//await Task.Delay(TimeSpan.FromSeconds(5));
var deliveryStatus = await InvokeRequestResponseServiceOfDeliveryPersonPredictionExp(progress[0].Name, progress[0].Mobile_Number);
progresslist.Add(progressreport.Name, progressreport.Mobile_Number);
List<CardImage> cardImages = new List<CardImage>();
cardImages.Add(new CardImage(url: progressreport.Photo_Url));
ThumbnailCard tlcard = new ThumbnailCard()
{
Title = "Name:" + progressreport.Name,
Subtitle = "Call:" + progressreport.Mobile_Number,
Images = cardImages,
Text = "Staus by Using Machine Learning Prediction:" + deliveryStatus
};
Attachment plAttachment = tlcard.ToAttachment();
replyToConversation.Attachments.Add(plAttachment);
}
replyToConversation.AttachmentLayout = AttachmentLayoutTypes.List;
await context.PostAsync(replyToConversation);
} catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
else
{
Activity replyToConversation = message.CreateReply("**There are no in progress deliveries are found**");
await context.PostAsync(replyToConversation);
}
}
private async Task<string> InvokeRequestResponseServiceOfDeliveryPersonPredictionExp(string name, string mobile_Number)
{
string status = "";
//Func<Stream, Task> copyStreamAsync = async stream =>
//{
//await Task.Factory.StartNew(async () =>
//{
//using (stream)
//using (var sourceStream = await sourceContent.Content.ReadAsStreamAsync())
//{
// await sourceStream.CopyToAsync(stream);
//}
//var client = new HttpClient();
using (var client = new HttpClient())
{
var scoreRequest = new
{
Inputs = new Dictionary<string, StringTable>() {
{
"input1",
new StringTable()
{
ColumnNames = new string[] {"Id", "Name", "Mobile_Number", "CourierCompany_Name", "Status", "EmailId"},
Values = new string[,] { { "", name, mobile_Number, "", "","" }, { "", name, mobile_Number, "", "", "" }, }
}
},
},
GlobalParameters = new Dictionary<string, string>()
{
}
};
const string apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx=="; // Replace this with the API key for the web service
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
client.BaseAddress = new Uri("My Request URL");
// WARNING: The 'await' statement below can result in a deadlock if you are calling this code from the UI thread of an ASP.Net application.
// One way to address this would be to call ConfigureAwait(false) so that the execution does not attempt to resume on the original context.
// For instance, replace code such as:
// result = await DoSomeTask()
// with the following:
// result = await DoSomeTask().ConfigureAwait(false)
//var status = await PostRequest(scoreRequest,client).ConfigureAwait(false);
HttpResponseMessage response = await client.PostAsJsonAsync("", scoreRequest);//.ConfigureAwait(false);
string correctLocation = "";
string wrongLocation = "";
string notReached = "";
string personMismatch = "";
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
var results = JsonConvert.DeserializeObject<RootObject>(result);
foreach (var value in results.Results.output1.value.Values)
{
status = value[8].ToString();
correctLocation = value[4].ToString();
notReached = value[5].ToString();
personMismatch = value[6].ToString();
wrongLocation = value[7].ToString();
}
Debug.WriteLine("Result: {0}", result);
return status;
}
else
{
Debug.WriteLine(string.Format("The request failed with status code: {0}", response.StatusCode));
// Print the headers - they include the requert ID and the timestamp, which are useful for debugging the failure
Debug.WriteLine(response.Headers.ToString());
string responseContent = await response.Content.ReadAsStringAsync();
Debug.WriteLine(responseContent);
return status;
}
};
// return status;
}
After executing this below line I got the exception like asynchronous module or handler completed while an asynchronous operation was still pending
await context.PostAsync(replyToConversation);
Before posting this question I had followed through this below links, but I didn't resolve it.
Async Void, ASP.Net, and Count of Outstanding Operations
Web Api + HttpClient: An asynchronous module or handler completed while an asynchronous operation was still pending
Please tell how to resolve this exception.
-Pradeep
Finally, I resolved the above exception when I am return Task instead of void in DeliveryProgressReport method. and also where ever I was called the await DeliveryProgressReport() method there also I return Task instead of void.
-Pradeep
I'm working in a project in which I want to add list<restaurant > in a web API method and return different types of mixed between restaurant and rest_location.
The relation between restaurant and rest_location is one to many.
When I run it, the error appears:
{"Message":"The requested resource does not support http method 'GET'."}
Server web API:
[HttpPost]
[Route("api/Restaurants/res_by_locat/{x}/{res_loc}")]
[ResponseType(typeof(Restaurant))]
[ResponseType(typeof(Rest_Location))]
public HttpResponseMessage GetResturantsBylocation([FromUri]int x,[FromBody] List<Rest_Location> res_loc)
{
List<Table> table = new List<Table>();
var lstitem = from t1 in res_loc
from t2 in db.Restaurants.Where(y => y.R_ID == t1.R_ID )
.DefaultIfEmpty()
select new { t1.L_Adress, t2.R_Name };
//foreach (var item in lstitem)
//{
// table.Add(item);
//}
if (lstitem == null || !lstitem.Any())
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
else return ControllerContext.Request.CreateResponse(HttpStatusCode.OK, new { lstitem });
}
Client:
protected void btn_ddl_Click(object sender, EventArgs e)
{
if (locationddl.SelectedValue == "0")
{
lbl_result.Text = "Chose a Location First ! ";
}
else
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:10566/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var fromddl = locationddl.SelectedItem.Text;
//lbl_result.Text = fromddl;
var response = client.GetAsync("api/Locations/getid_by_name/" + fromddl).Result;
// if (Page.IsValid)
{
if (response.IsSuccessStatusCode)
{
Location ll = response.Content.ReadAsAsync<Location>().Result;
int x = ll.L_ID;
lbl_msg.Text = x.ToString();
var response2_get_ids_Rests = client.GetAsync("api/Rest_Location/res_by_locat/" + x).Result;
if (response2_get_ids_Rests.IsSuccessStatusCode)
{
List<Rest_Location> rests_locations = response2_get_ids_Rests.Content.ReadAsAsync<List<Rest_Location>>().Result;
//var items= rests_locations.FirstOrDefault(rl => rl.L_ID == x);
// GridView2.DataSource = rests_locations;
// GridView2.DataBind();
HttpResponseMessage response3_get_resturants_by = client.PostAsJsonAsync("api/Restaurants/res_by_locat/" + x , rests_locations).Result;
if (response3_get_resturants_by.IsSuccessStatusCode)
{
var news= response3_get_resturants_by.Content.ReadAsAsync<List<Restaurant>>().Result;
GridView1.DataSource = news;
GridView1.DataBind();
lbl_msg.Text = "Search succesed";
}
else
{
lbl_test.Text = " not found ";
}
}
else
{
lbl_test.Text = " not found ";
}
}
}
}
catch (Exception ex)
{
lbl_msg.Text = "Couldn't Found Resaurants ! " + ex.ToString();
}
}
}
You endpoint has this attribute, [HttpPost], implying that it can only be accessed using POST
Your client is attempting to access the endpoint using GET.
You should use client.PostAsync method instead of GetAsync.
I'd like to ask about how to wait for multiple async http requests.
My code is like this :
public void Convert(XDocument input, out XDocument output)
{
var ns = input.Root.Name.Namespace;
foreach (var element in input.Root.Descendants(ns + "a"))
{
Uri uri = new Uri((string)element.Attribute("href"));
var wc = new WebClient();
wc.OpenReadCompleted += ((sender, e) =>
{
element.Attribute("href").Value = e.Result.ToString();
}
);
wc.OpenReadAsync(uri);
}
//I'd like to wait here until above async requests are all completed.
output = input;
}
Dose anyone know a solution for this?
There is an article by Scott Hanselman in which he describes how to do non blocking requests. Scrolling to the end of it, there is a public Task<bool> ValidateUrlAsync(string url) method.
You could modify it like this (could be more robust about response reading)
public Task<string> GetAsync(string url)
{
var tcs = new TaskCompletionSource<string>();
var request = (HttpWebRequest)WebRequest.Create(url);
try
{
request.BeginGetResponse(iar =>
{
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.EndGetResponse(iar);
using(var reader = new StreamReader(response.GetResponseStream()))
{
tcs.SetResult(reader.ReadToEnd());
}
}
catch(Exception exc) { tcs.SetException(exc); }
finally { if (response != null) response.Close(); }
}, null);
}
catch(Exception exc) { tcs.SetException(exc); }
return tsc.Task;
}
So with this in hand, you could then use it like this
var urls=new[]{"url1","url2"};
var tasks = urls.Select(GetAsync).ToArray();
var completed = Task.Factory.ContinueWhenAll(tasks,
completedTasks =>{
foreach(var result in completedTasks.Select(t=>t.Result))
{
Console.WriteLine(result);
}
});
completed.Wait();
//anything that follows gets executed after all urls have finished downloading
Hope this puts you in the right direction.
PS. this is probably as clear as it can get without using async/await
Consider using continuation passing style. If you can restructure your Convert method like this,
public void ConvertAndContinueWith(XDocument input, Action<XDocument> continueWith)
{
var ns = input.Root.Name.Namespace;
var elements = input.Root.Descendants(ns + "a");
int incompleteCount = input.Root.Descendants(ns + "a").Count;
foreach (var element in elements)
{
Uri uri = new Uri((string)element.Attribute("href"));
var wc = new WebClient();
wc.OpenReadCompleted += ((sender, e) =>
{
element.Attribute("href").Value = e.Result.ToString();
if (interlocked.Decrement(ref incompleteCount) == 0)
// This is the final callback, so we can continue executing.
continueWith(input);
}
);
wc.OpenReadAsync(uri);
}
}
You then run that code like this:
XDocument doc = something;
ConvertAndContinueWith(doc, (finishedDocument) => {
// send the completed document to the web client, or whatever you need to do
});