I use C# for programming Telegram Bot, but when I set webhook I can't fill Update object? I use ashx handler.
public void ProcessRequest(HttpContext context)
{
Fwk_Log.Insert("before","before");
var update = context.Request.QueryString["Update"];
Fwk_Log.Insert(update, "update = ");
long offset = 0;
int whilecount = 0;
int updateId = 0;
whilecount += 1;
string updates = Fwk_HttpRequest.ExecuteUrlRequestJSONString("https://api.telegram.org/bot" + Token + "/getUpdates");
Shp_Telegram_GetUpdate list = new JavaScriptSerializer().Deserialize<Shp_Telegram_GetUpdate>(updates);
if (list != null)
{
foreach (var r in list.result)
{
//offset = list.result.First().update_id;
if (r.message.text == "/start")
{
Fwk_HttpRequest.ExecuteUrlRequestJSONString("https://api.telegram.org/bot" + Token +
"/sendMessage?chat_id=" + r.message.chat.id + "&text=" + "Hello World");
Fwk_Log.Insert("sendMessage", "");
}
}
}
}
You are getting things mixed up. See here
There are two mutually exclusive ways of receiving updates for your
bot — the getUpdates method on one hand and Webhooks on the other.
Incoming updates are stored on the server until the bot receives them
either way, but they will not be kept longer than 24 hours.
Regardless of which option you choose, you will receive
JSON-serialized Update objects as a result.
If you are using webhooks, you do not need to call getUpdate method.
Related
I need to call Web API(Hosted on different network) from windows application from users machine for 30,000 times within one hour of time span.
I tried Multithreading to achieve the same but it is not working(giving system out of memory exceprion).
I used TreadPool as below
private static object threadLock = new object();
public delegate void BarDelegate();
int ThreadCount = dtExcel.Rows.Count;
private void button2_Click(object sender, EventArgs e)
{
for (int i = 0; i < ThreadCount - 1; i++)
{
ThreadPool.QueueUserWorkItem(output => CallAPI());
}
}
public void CallAPI()
{
string branchCode = "",
para1 = dtExcel.Rows[progressBar.Value]["para1"].ToString(),
para2 = "324",
para3 = "Test",
para4 = dtExcel.Rows[progressBar.Value]["para4"].ToString();
//Console.WriteLine(Thread.CurrentThread.Name + ": " + progressBar.Value);
var service = new APIService();
var resp = service.CallAPIService(para1, para2, para3, para4, para5);
if (resp.IsSuccess == true)
{
DataGridViewRow dtGrdVwR = dataGrid.Rows[progressBar.Value];
dtGrdVwR.Cells[3].Value = "Success";
}
else
{
DataGridViewRow dtGrdVwR = dataGrid.Rows[progressBar.Value];
dtGrdVwR.Cells[3].Value = "Failed: "+ resp.Message;
}
try
{
this.Invoke(new BarDelegate(UpdateBar));
}
catch
{
}
}
private void UpdateBar()
{
lblEndTime.Text = DateTime.Now.ToString();
progressBar.Value++;
if (progressBar.Value == progressBar.Maximum)
{
// We are finished and the progress bar is full.
}
}
Here dtExcel has 30,000 records(Uploaded by user from excel) which needs to processed within one hour and update the status of executed record in respective row in dataGrid.
The API call is made over network where single call takes approximate 1 to 2 seconds to execute.
service.CallAPIService(para1, para2, para3, para4, para5);
The above method internally performs heavy task like request encryption and digital signature and response decryption and digital signature verification.
Please help me with the best way possible where i can perform the task within time period and without getting SystemOutOfmemoryException.
Thanks in Advance.
Right now your code is horribly broken because of the race condition accessing progressBar.Value. It's pointless to discuss any other issues, because you are going to totally reorganize your code to fix the race condition, rendering other comments obsolete.
Fix it so that you don't have N threads all trying to process item #1, and then ask a new question with your new code.
I am working on an ASP.NET Webform project (legacy code).On my button_click event i am sending sms message to all the datas populated in this.
var customerSMS = BusinessLayer.SMS.SmsSetup.GetAllCustomerSMS(OfficeId);
This takes around 15seconds to do all the computing and get the data(1000rows)
from the Db.And for each data it runs through the loop and does validation and
sends the sms and it does take time.I want to do this task in background and
redirect the user to the index page and the background process continues till it
gets out of the loop.I am new to this and still learning this beautiful
language C#.I did go through this amazing Asynchronous Programming async/await
and Multithreading approach and got hold of it only in simple WindowsForm
applications.Any reference/code snippet/best approach with a simple explanation for my case would be helpful.
My button click event code :
protected void ReturntoDashboard_Click(object sender, EventArgs e)
{
sms = Everest.Net.BusinessLayer.SMS.SmsSetup.GetSmsSetUp(OfficeId);
if (sms.EnableSmsData && sms.SmsCount > 0)
{
#region Loan Section
var smsLoan = Everest.Net.BusinessLayer.SMS.SmsSetup.GetLoanId(s.Sms_AccountNumber);
var loanId =
BusinessLayer.SMS.SmsSetup.GetLoanIdValue(s.Sms_AccountNumber);
var dateexceeded =
BusinessLayer.SMS.SmsSetup.IsDateExceeded(loanId);
if (smsLoan != null && dateexceeded == true)
{
foreach (Common.SMS.SMSSetup sm in smsLoan)
{
var smsClosingBalanceLoan = BusinessLayer.SMS.SmsSetup.GetAmountForLoanAlert( sm.LoanId,
BusinessLayer.Core.DateConversion
.GetCurrentServerDate()
.AddDays(sms.DaysbeforeLoanalerts).ToString());
if (smsClosingBalanceLoan != null)
{
if (smsClosingBalanceLoan.LoanAmountToPay > 0)
{
int smsSentAlertCount = sms.LoanAlertCount;
var logCount = BusinessLayer.SMS.SmsSetup.GetLoanSmsAlertSentCount(DateTime.Now.AddDays(-smsSentAlertCount).ToString("yyyy-MM-dd"), DateTime.Now.ToString("yyyy-MM-dd"), sm.LoanAccountNumber);
if (logCount < smsSentAlertCount)
{
smsLog = new Everest.Net.Common.SMS.SMSSetup();
finalMessage = "Dear Member, Your Loan accnt " + sm.LoanAccountNumber + " with Principal"+ "+" + "Int Amnt: Rs." + smsClosingBalanceLoan.LoanAmountToPay + " need to be payed.Thank You," + officeName.OfficeName;
smsLog.LogServiceType = "Loan";
smsLog.LogSmsType = s.Sms_SmsType;
smsLog.LogSmsMessage = finalMessage;
smsLog.LogCustomerId = s.CustomerId.ToString();
smsLog.LogAccountNumber = s.Sms_AccountNumber;
smsLog.LogAccountType = s.Sms_AccountType;
smsLog.LogSmsSentDate = BusinessLayer.Core.DateConversion.GetCurrentServerDate();
smsLog.LogSmsFailedDate = "";
smsLog.LogSentStatus = true;
smsLog.LogUserId = UserId;
smsLog.LogSmsFailedMessage = "";
try
{
var result = Everest.Net.BusinessLayer.SMS.smsParameters.SendSMS(sms.FromNum, sms.Token, sms.Url, cellNum, finalMessage);
}
catch (Exception ex)
{
smsLog.LogSmsFailedDate = System.DateTime.Now.ToString("MM/dd/yyyy HHmmss");
smsLog.LogSentStatus = false;
smsLog.LogSmsFailedMessage = ex.Message;
Everest.Net.BusinessLayer.SMS.SmsSetup.InsertSMSLog(smsLog);
}
sms = Everest.Net.BusinessLayer.SMS.SmsSetup.GetSmsSetUp(OfficeId);
sms.SmsCount = sms.SmsCount - 1;
Everest.Net.BusinessLayer.SMS.SmsSetup.UpdateSmsSetup(sms);
Everest.Net.BusinessLayer.SMS.SmsSetup.InsertSMSLog(smsLog);
}
}
}
}
}
}
}
}
catch (Exception ex)
The ideal solution would remove the responsibility of sending the SMS from the web application itself. Instead, the web application should create a database record containing the message and recipient addresses, and a separate background job (e.g. a Windows Service) should poll the database and send SMS messages when neeeded. This is the best solution in terms of fault tolerance and auditability, because there is a permanent record of the messaging job which can be resumed if the system fails.
That being said, maybe you don't want to go to all that trouble. If you feel strongly that you wish to send the SMS directly from the ASP.NET application, you will need to create a Task and queue it to run using QueueBackgroundWorkitem. You will need to refactor your code a bit.
Move all the logic for sending the SMS into a separate function that accepts all the information needed as parameters. For example,
static void SendSMS(string[] addresses, string messagetext)
{
//Put your SMS code here
}
When you need to call the function, queue it as a background item
HostingEnvironment.QueueBackgroundWorkItem(a => SendSMS(addresses, messageText));
If your worker task needs to access its own cancellation token (e.g. if it is supposed to loop until cancelled), it is passed as an argument to the lambda expression. So you could modify the prototype
static void SendSMS(string[] addresses, string messagetext, CancellationToken token)
{
while (!token.IsCancellationRequested)
{
//Put your code here
}
}
and pass it thus:
HostingEnvironment.QueueBackgroundWorkItem(token => SendSMS(addresses, messageText, token));
Placing the task in the background queue ensures that ASP.NET keeps track of the thread, doesn't try to garbage collect it, and shuts it down properly when the application pool needs to shut down.
After queuing the background operation, your page can render is content per usual and conclude the HTTP response while the task continues to execute.
Below is a button, when pressed it calls a function that pings a bunch of IP addresses. If the IP address returns a response, it adds the IP address to the output_networkSearch.Text.
private void button_networkSearch_Click(object sender, RoutedEventArgs e)
{
output_networkSearch.Text = networkSearch(Convert.ToInt32(input_searchLimit.Text));
}
Below isn't the whole method, just the part that I can't get to work. The for loop starts at whatever the last digit on the users default gateway IP address is, and stops at whatever limit they have inputed (1 - 255).
// i is equal to the last digit in the default gateway IP, if it was 192.168.0.1 then i = 1.
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
// If the method receieves a ping reply...
if (PingHostSweep(gatewayIPRebuild + i))
{
// Returns 192.168.0. + i + ACTIVE
string response = gatewayIPRebuild + i + " ACTIVE";
return response;
}
else
{
string response = gatewayIPRebuild + i + " CLOSED";
return response;
}
}
This worked on a console application but for a WPF application it seems to run through the loop once and stop due to the return statement.
My idea to work around this would be to remove the Return Response statements and try and access the TextBox (output_networkSearch) directly.
So I would do something like:
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
// If the method receieves a ping reply...
if (PingHostSweep(gatewayIPRebuild + i))
{
// Returns 192.168.0. + i + ACTIVE
string response = gatewayIPRebuild + i + " ACTIVE";
output_networkSearch.Text = reponse;
}
else
{
string response = gatewayIPRebuild + i + " CLOSED";
output_networkSearch.Text = reponse;
}
}
HOWEVER, I can't access the textbox within the method for some reason. I've only just started learning C# so I'm not entirely familiar with how it works.
Here's an image of a partially working concept. As you can see the limit is set at 10, so it should ping IP address 1 through 10 and give an ACTIVE or CLOSED response. This did work in my console application version.
WPF version
Console version
This might do the trick for you
List<string> responses = new List<string>();
string response;
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
if (PingHostSweep(gatewayIPRebuild + i))
{
response = gatewayIPRebuild + i + " ACTIVE";
}
else
{
response = gatewayIPRebuild + i + " CLOSED";
}
responses.Add(response)
}
Now after the loop the list which is responses would have the list of all the IPs which are active and closed. Like the way you do had in the console Application.
i think you need use threading, there are need many child threading work in backend to scan, when they finish them work then response the result to MainForm, so i write some code hope can help you!
using System.Threading;
using System.Threading.Tasks;
public void Start(string ip)
{
Task.Factory.StartNew(() =>
{
// If the method receieves a ping reply...
string response;
if (PingHostSweep(ip))
{
// Returns 192.168.0. + i + ACTIVE
response = ip + " ACTIVE";
}
else
{
response = ip + " CLOSED";
}
this.Invoke((MethodInvoker)(() => { textBox1.AppendText("\r\n" + response); }));
});
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 255; i++)
{
Start(String.Format("192.168.100.{0}", i));
}
}
The previous answer was correct (though it didn't touch on a more advanced point that you will ultimately need to learn ... delegation and invocation ... long story ... won't bore you now).
What you wrote distills to this:
// SIDE NOTE: you cannot actually treat an IPv4 address as four "pure" quads (but that's not your question)
var notNecessarilyAHost = splitGatewayIP[3];
var searchStart = Convert.ToInt32(notNecessarilyAHost);
for (var i = searchStart; i <= searchLimit; ++i)
{
if (PingHostSweep(gatewayIPRebuild + i))
{
return $"{gatewayIPRebuild}{i} ACTIVE";
}
else
{
return $"{gatewayIPRebuild}{i} CLOSED";
}
}
...and if you (mentally) step through what you wrote it's fairly straightforward to see that the loop will only ever cycle once. Upon entry to the loop i will be equal to whatever searchStart is. Then you enter the if test. If that test is true, you fall into the true side of the branch (i.e., "...ACTIVE"). Otherwise, you'll drop into the else branch (i.e., "...CLOSED". FROM THERE...
You ALWAYS return. That will exit the loop (and the function that contains it). You will never cycle the loop again. "break" and "return" (and plausibly goto ... but that's for a different day) will ALWAYS exit the current scope (scope being a block of code wrapped by '{' and '}' (be they explicitly or implicitly written).
Following?
The previous answer was correct. It adjusts your code so that the loop adds the string you're composing with each iteration to a list of strings. Then, when you exit the loop (because i reaches searchLimit) that list of strings will contain N many, well, strings. You probably want to return or continue working that.
All that said, you can't (technically you can but you SHOULDN'T) do any of this inside a UI thread. If you do, the UI will block (and become 100% unresponsive to the user) while the loop runs (and the network calls that it makes run), etc.
I have a loop that is running every 10 seconds that does a few things. One thing it does is it enables a button when there is a message that I am sending to the users of the app. I want to send a notification to the system tray when that button enables, but for obvious reasons I only want that notification triggered once when the user has an unread broadcast.
Here is the code I have:
private void EnableBroadcasts()
{
string query = "SELECT COUNT(*) FROM db.broadcasts WHERE broadcast_active = '1'";
int count = StoredProcedures.CountRecordsT4(query);
StreamReader re = new StreamReader(#"C:\\Users\\" + Environment.UserName + #"\\appdata\\Local\\Cache\\broadcasts.cache");
List<string> ReadBroadcastList = new List<string>();
List<string> BcastID = BroadcastID();
if (BroadcastCount != count)
{
string text = re.ReadToEnd();
re.Close();
string[] lines = text.Split('\r');
foreach (string s in lines)
{
ReadBroadcastList.Add(s);
}
for (int t = 0; t < ReadBroadcastList.Count(); t++)
{
ReadBroadcastList[t] = ReadBroadcastList[t].Trim('\n');
}
ReadBroadcastList.Remove("");
BroadcastCount = ReadBroadcastList.Count();
}
var test = BcastID.Except(ReadBroadcastList).ToList();
int read = test.Count();
if (count != 0)
{
btnWESBroadcast.Visible = true;
}
else
{
btnWESBroadcast.Visible = false;
}
The button enables once count is not zero. I have a list of broadcast ID's that are active from the db,I also have a cache file that records what broadcast ID's that user has read.
I am looking for a solution that will have the notification only run when the button is active and there is a broadcast that the user has not read.
Wrap your string broadcast in a simple type: BroadcastMessage. Add a bool IsRead flag.
Mark IsRead = true and the message will be ignored with the following logic.
// pseudo
if (button.IsEnabled && ReadBroadcastList.Any(msg => !msg.IsRead)) {
NotifyTray();
}
Then you can later add a feature for the user to mark a message Unread.
If you intend to persist this data in the database, then both the message and flag can be stored in the BroadcastMessage object. When a user reads the message and the object is marked as read, update the database with the change.
Update: based on clarification in comment
Add a bool IsNotified flag to the BroadcastMessage notification and check !msg.IsNotified instead of !msg.IsRead.
I have setup Kinesis stream in Amazon WebServices. I Also want to accomplish the following tasks:
Put Records into Single Stream with Single Shard (C# Api) - SUCCESS
Also I wrote Sample App in which multiple Producers are working on different Stream - SUCCESS
Also I setup Sample App to Perform Mutiple Workers put the Data into Single Stream - SUCCESS
Also I want to be able to enforce the SequenceNumberOrdering in the Reacords.
But the real pain is the GetRecords Consumer Operation using Kinesis C# Api.
I created a sample App for the Records. The problem is that it doesn't stop the Iteration even if there are no Records present in the Kinesis Stream. Also keeping the SequenceNumber in the DB or some file and retrieving the file again is time consuming - what is the advantage of using Kinesis Stream for GetRecords?
Why does it keep on iterating even when there is no data in the Stream?
I used following piece of code for the REFERENCE;
private static void GetFilesKinesisStream()
{
IAmazonKinesis kinesis = AWSClientFactory.CreateAmazonKinesisClient();
try
{
ListStreamsResponse listStreams = kinesis.ListStreams();
int numBuckets = 0;
if (listStreams.StreamNames != null &&
listStreams.StreamNames.Count > 0)
{
numBuckets = listStreams.StreamNames.Count;
Console.WriteLine("You have " + numBuckets + " Amazon Kinesis Streams.");
Console.WriteLine(string.Join(",\n", listStreams.StreamNames.ToArray()));
DescribeStreamRequest describeRequest = new DescribeStreamRequest();
describeRequest.StreamName = "******************";
DescribeStreamResponse describeResponse = kinesis.DescribeStream(describeRequest);
List<Shard> shards = describeResponse.StreamDescription.Shards;
foreach (Shard s in shards)
{
Console.WriteLine("shard: " + s.ShardId);
}
string primaryShardId = shards[0].ShardId;
GetShardIteratorRequest iteratorRequest = new GetShardIteratorRequest();
iteratorRequest.StreamName = "*********************";
iteratorRequest.ShardId = primaryShardId;
iteratorRequest.ShardIteratorType = ShardIteratorType.AT_SEQUENCE_NUMBER;
iteratorRequest.StartingSequenceNumber = "49544005271533118105145368110776211536226129690186743810";
GetShardIteratorResponse iteratorResponse = kinesis.GetShardIterator(iteratorRequest);
string iterator = iteratorResponse.ShardIterator;
Console.WriteLine("Iterator: " + iterator);
//Step #3 - get records in this iterator
GetShardRecords(kinesis, iterator);
Console.WriteLine("All records read.");
Console.ReadLine();
}
// sr.WriteLine("You have " + numBuckets + " Amazon S3 bucket(s).");
}
catch (AmazonKinesisException ex)
{
if (ex.ErrorCode != null && ex.ErrorCode.Equals("AuthFailure"))
{
Console.WriteLine("The account you are using is not signed up for Amazon EC2.");
Console.WriteLine("You can sign up for Amazon EC2 at http://aws.amazon.com/ec2");
}
else
{
Console.WriteLine("Caught Exception: " + ex.Message);
Console.WriteLine("Response Status Code: " + ex.StatusCode);
Console.WriteLine("Error Code: " + ex.ErrorCode);
Console.WriteLine("Error Type: " + ex.ErrorType);
Console.WriteLine("Request ID: " + ex.RequestId);
}
}
}
private static void GetShardRecords(IAmazonKinesis client, string iteratorId)
{
//create reqest
GetRecordsRequest getRequest = new GetRecordsRequest();
getRequest.Limit = 100;
getRequest.ShardIterator = iteratorId;
//call "get" operation and get everything in this shard range
GetRecordsResponse getResponse = client.GetRecords(getRequest);
//get reference to next iterator for this shard
string nextIterator = getResponse.NextShardIterator;
//retrieve records
List<Record> records = getResponse.Records;
//print out each record's data value
foreach (Record r in records)
{
//pull out (JSON) data in this record
string s = Encoding.UTF8.GetString(r.Data.ToArray());
Console.WriteLine("Record: " + s);
Console.WriteLine("Partition Key: " + r.PartitionKey);
}
if (null != nextIterator)
{
//if there's another iterator, call operation again
GetShardRecords(client, nextIterator);
}
}
Why does a kinesis consumer keep iterating after the "end" of the data?
Because there is no "end". Kinesis is sort of like a queue, but not exactly. Think of it like a moving time window of recorded events. You don't consume records, you examine records passively that are currently in the window (which amazon hardcodes to 24 hours). Because the window is always moving, once you reach the "last" record, it keeps watching in real time. New records could come at any time; the consumer doesn't know that there aren't any producers.
If you want to stop based on some condition, that condition has to be contained in your payload. For example, if you wanted to stop when you got to "now", part of your payload could be a timestamp, which the consumer checks for proximity to its current time.