About Twilio web hooks - c#

I have developed application, which is sending sms by twilio.
I need to track sms statuses - deliveries, fails, etc. for this reason I use twilio provided web hooks.
Of course I save sent sms into database - for some purposes and then also updating sms status in the db.
I achieved this by getting smsId - what twilio returns when sending sms - this id is saved into db - to track deliveries as mentioned above.
Actual question:
web hook is posting very fast to my endpoint status - actually for that time I event don't expect it to be saved in db.
I tried some of the optimizations - but nothing helped - still web hook is faster - so the resource is not in db - and of course I get NullReferenceException.
dealing with that - I came to the solution - to trying reading resource multiple times with some delays and at the end it gets resource and everything is fine.
actually - I don't like querying database multiple times for very small amount of time.
What can be other solution?
Code sample:
var response = _notificationSender.SendSms(new SendSmsRequest
{
Text = text,
ToNumber = contact.Mobile ?? contact.Phone
});
_db.Database.ExecuteSqlCommand(#"INSERT INTO [Table] ([field], .. ) Values(Field1,...),");
SendSms:
public SendSmsResponse SendSms(SendSmsRequest request)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
TwilioClient.Init(_twilioConfiguration.AccountSid, _twilioConfiguration.Token);
var message = MessageResource.Create(
body: request.Text,
from: new Twilio.Types.PhoneNumber(FromNumber),
statusCallback: new Uri(_twilioConfiguration.StatusCallbackUrl),
to: new Twilio.Types.PhoneNumber(request.ToNumber)
);
return new SendSmsResponse
{
Ok = true,
From = _twilioConfiguration.FromNumbers.First().Value,
Sid = message.Sid,
ErrorCode = (TwillioErrorCode?)message.ErrorCode,
SmsStatus = response.SmsStatus
};
}

Related

Query Azure Application Insights CustomEvents in Azure function in C#.Net

I need to query CustomEvents under application insights in an azure function.
I was able to read CustomEvents using below package:
Microsoft.Azure.ApplicationInsights.Query
Here is the code:
string applicationId = "xxxx-xxxx-xxxx";
string key = "xxxxxxxxxxx";
// Create client
var credentials = new ApiKeyClientCredentials(key);
var applicationInsightsClient = new ApplicationInsightsDataClient(credentials);
// Query Application Insights
var query = "customEvents" +
" | where timestamp > ago(840h)" +
" | take 3";
var response = await applicationInsightsClient.Query.ExecuteWithHttpMessagesAsync(applicationId, query);
The library 'Microsoft.Azure.ApplicationInsights.Query is however deprecated and suggestion is to use Azure.Monitor.Query
Below is the code that Microsoft documentation has as an example to query logs using Azure.Monitor.Query :
Azure.Response<Azure.Monitor.Query.Models.LogsQueryResult> response = await logsQueryClient.QueryWorkspaceAsync(
"<workspaceId>",
"customEvents ",
new QueryTimeRange(TimeSpan.FromMinutes(300)));
Since this library queries using workspace id, I linked my application insights instance to a log analytics workspace instance. However the function fails with a BadArgumentError "Failed to resolve table or column expression named 'customEvents'"
Is there a way we can query CustomEvents using the package Azure.Monitor.Query?
Any help is appreciated.
Thanks
Yes, it works.
Below is a tested code.
Once you link your Application Insights to Azure Monitor workspace, you can query your AI tables from that WS, without the need to use app().
The thing is that the tables` names are different, e.g., traces becomes AppTraces.
In the same manner, customEvents becomes AppEvents.
Well, it turns out it is even documented, under Migrate to workspace-based Application Insights resources
Legacy table name
New table name
Description
availabilityResults
AppAvailabilityResults
Summary data from availability tests.
browserTimings
AppBrowserTimings
Data about client performance, such as the time taken to process the incoming data.
dependencies
AppDependencies
Calls from the application to other components (including external components) recorded via TrackDependency() – for example, calls to REST API, database or a file system.
customEvents
AppEvents
Custom events created by your application.
customMetrics
AppMetrics
Custom metrics created by your application.
pageViews
AppPageViews
Data about each website view with browser information.
performanceCounters
AppPerformanceCounters
Performance measurements from the compute resources supporting the application, for example, Windows performance counters.
requests
AppRequests
Requests received by your application. For example, a separate request record is logged for each HTTP request that your web app receives.
exceptions
AppExceptions
Exceptions thrown by the application runtime, captures both server side and client-side (browsers) exceptions.
traces
AppTraces
Detailed logs (traces) emitted through application code/logging frameworks recorded via TrackTrace().
using Azure;
using Azure.Identity;
using Azure.Monitor.Query;
using Azure.Monitor.Query.Models;
string workspaceId = "...";
var client = new LogsQueryClient(new DefaultAzureCredential());
try
{
Response<LogsQueryResult> response = await client.QueryWorkspaceAsync(
workspaceId,
"AppEvents | count",
QueryTimeRange.All);
LogsTable table = response.Value.Table;
foreach (var row in table.Rows)
{
Console.WriteLine(row);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}

How do I create a webhook in ASP.NET MVC?

I'm trying to create a simple webhook to receive a delivery receipt from Nexmo SMS service. The only documentation on their website was this.
During account set-up, you will be asked to supply Nexmo a CallBack URL for Delivery Receipt to which we will send a delivery receipt for each of your SMS submissions. This will confirm whether your message reached the recipient's handset. The request parameters are sent via a GET (default) to your Callback URL and Nexmo will be expecting response 200 OK response, or it will keep retrying until the Delivery Receipt expires (up to 72 hours).
I've been searching for ways to do this, and so far I have this method from an example I found online, although I'm not sure if this is correct. Anyways, this is being run on ASP.NET and on port 6563, so is this the port I'm supposed to be listening to? I downloaded an application called ngrok which should expose my local web server to the internet, so I ran the application and instructed it to listen onto port 6563, but no luck. I've been fiddling with it trying to find someway to post to this function.
[HttpPost]
public ActionResult CallbackURL()
{
System.IO.StreamReader reader = new System.IO.StreamReader(HttpContext.Request.InputStream);
string rawSendGridJSON = reader.ReadToEnd();
return new HttpStatusCodeResult(200);
}
Usually I can call the function directly to return the view just by visiting http://localhost:6563/Home/Index/CallbackURL
So I've inserted a breakpoint on the method signature, but it'll only get called if I remove the [HttpPost] from it. Any next steps that I should try?
First you have to remove the [HttpPost] bit because it clearly states that "parameters are sent via a GET".
Then you should also remove the return HttpStatusCodeResult(200) as it will return the 200 OK status code anyway if no error occures.
Then you should simply read the values from querystring or using model binding. Here is a sample:
public string CallbackURL()
{
string vals = "";
// get all the sent data
foreach (String key in Request.QueryString.AllKeys)
vals += key + ": " + Request.QueryString[key] + Environment.NewLine;
// send all received data to email or use other logging mechanism
// make sure you have the host correctly setup in web.config
SmtpClient smptClient = new SmtpClient();
MailMessage mailMessage = new MailMessage();
mailMessage.To.Add("...#...com");
mailMessage.From = new MailAddress("..#....com");
mailMessage.Subject = "callback received";
mailMessage.Body = "Received data: " + Environment.NewLine + vals;
mailMessage.IsBodyHtml = false;
smptClient.Send(mailMessage);
// TODO: process data (save to database?)
// disaplay the data (for degugging purposes only - to be removed)
return vals.Replace(Environment.NewLine, "<br />");
}
Before couple of weeks Asp.Net team has announced to support Web Hooks with Visual Studio.
Please have a look here for more detailed information:
https://neelbhatt40.wordpress.com/2015/10/14/webhooks-in-asp-net-a-visual-studio-extension/
Microsoft is working on ASP.NET WebHooks, a new addition to the ASP.NET family. It supports a lightweight HTTP pattern providing a simple pub/sub model for wiring together Web APIs and SaaS services.
See Introducing Microsoft ASP.NET WebHooks Preview
So the issue I was having wasn't with my webhook at all, it was actually with IIS Express. Apparently it blocks most traffic from foreign hosts so there is some tweaking you can do before tunneling anything to your server. If you follow these guides you should have a working server.
https://gist.github.com/nsbingham/9548754
https://www.twilio.com/blog/2014/03/configure-windows-for-local-webhook-testing-using-ngrok.html

Facebook Graph API {id}/feed?limit=x - restrict to messages since a certain message id

I have a small problem, I am working on an aggregation application that is collecting messages from pages in realtime.
This is working fine, but I get the same message on every call and then filter out the messages that I have already seen manually.
This means that a large amount of data is being transferred every time I make a call to the graph api.
Is there a way to limit the message as messages since this message id?
currently using the c# Facebook SDK
var fb = new FacebookClient("access_token");
dynamic parameters = new ExpandoObject();
parameters.limit = _facebookMessagesToRetrieveAtATime.ToString(CultureInfo.InvariantCulture);
//Want to add a new param here to say messages since this id.
var facebookUrl = String.Format("{0}/feed", "Page ID");
dynamic resp = fb.Get(facebookUrl, parameters);
Thanks in advance.
You can use the since url parameter in your calls, as described at https://developers.facebook.com/docs/graph-api/using-graph-api/v2.1#paging
This would make it necessary that you store somewhere in your application the timestamp when you last requested the respective feed
This would yield in
var facebookUrl = String.Format("{0}/feed?since={last_update_timestamp}", "Page ID");
where {last_update_timestamp} is the timestamp (unixtime in seconds) of the last update.

POST to Notifications API works fine with "user-id-1" but doesn't work with "user-id-2"

I am trying to server-side POST to Notifications API but I can't make it work consistently.
As required in the
Notifications API
I am using the App Access Token
to post to Facebook's Notifications API.
Both users have authorized the app.
The notification-post works fine, when using "specific-user-id-1/notifications" and returns {"success":true}
When using "specific-user-id-2/notifications"
The same lines of code don't work,
and return
"(OAuthException - #2) An unexpected error has occurred. Please retry your request later."
Should I change something in the way I post to the Notifications API ?
This was also submitted to facebook bugs... just in case.
var fb = new FacebookClient();
fb.AppId = "APP_ID";
fb.AppSecret = "APP_SECRET";
fb.AccessToken = "APP_ACCESS_TOKEN";
dynamic nparams = new ExpandoObject();
nparams.access_token = "APP_ACCESS_TOKEN";
nparams.template = "testing";
nparams.href = "";
var response = fb.Post("RECIPIENT_FACEBOOK_USER_ID/notifications", nparams);
UPDATE
Notifications are working fine now. (without code changes)
It seems that this was a Facebook problem.
UPDATE 2
1 day after the previous update... not working again...

Finding Connection by UserId in SignalR

I have a webpage that uses ajax polling to get stock market updates from the server. I'd like to use SignalR instead, but I'm having trouble understanding how/if it would work.
ok, it's not really stock market updates, but the analogy works.
The SignalR examples I've seen send messages to either the current connection, all connections, or groups. In my example the stock updates happen outside of the current connection, so there's no such thing as the 'current connection'. And a user's account is associated with a few stocks, so sending a stock notification to all connections or to groups doesn't work either. I need to be able to find a connection associated with a certain userId.
Here's a fake code example:
foreach(var stock in StockService.GetStocksWithBigNews())
{
var userIds = UserService.GetUserIdsThatCareAboutStock(stock);
var connections = /* find connections associated with user ids */;
foreach(var connection in connections)
{
connection.Send(...);
}
}
In this question on filtering connections, they mention that I could keep current connections in memory but (1) it's bad for scaling and (2) it's bad for multi node websites. Both of these points are critically important to our current application. That makes me think I'd have to send a message out to all nodes to find users connected to each node >> my brain explodes in confusion.
THE QUESTION
How do I find a connection for a specific user that is scalable? Am I thinking about this the wrong way?
I created a little project last night to learn this also. I used 1.0 alpha and it was Straight forward. I created a Hub and from there on it just worked :)
I my project i have N Compute Units(some servers processing work), when they start up they invoke the ComputeUnitRegister.
await HubProxy.Invoke("ComputeUnitReqisted", _ComputeGuid);
and every time they do something they call
HubProxy.Invoke("Running", _ComputeGuid);
where HubProxy is :
HubConnection Hub = new HubConnection(RoleEnvironment.IsAvailable ?
RoleEnvironment.GetConfigurationSettingValue("SignalREndPoint"):
"http://taskqueue.cloudapp.net/");
IHubProxy HubProxy = Hub.CreateHubProxy("ComputeUnits");
I used RoleEnviroment.IsAvailable because i can now run this as a Azure Role , a Console App or what ever in .NET 4.5. The Hub is placed in a MVC4 Website project and is started like this:
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(50);
RouteTable.Routes.MapHubs();
public class ComputeUnits : Hub
{
public Task Running(Guid MyGuid)
{
return Clients.Group(MyGuid.ToString()).ComputeUnitHeartBeat(MyGuid,
DateTime.UtcNow.ToEpochMilliseconds());
}
public Task ComputeUnitReqister(Guid MyGuid)
{
Groups.Add(Context.ConnectionId, "ComputeUnits").Wait();
return Clients.Others.ComputeUnitCameOnline(new { Guid = MyGuid,
HeartBeat = DateTime.UtcNow.ToEpochMilliseconds() });
}
public void SubscribeToHeartBeats(Guid MyGuid)
{
Groups.Add(Context.ConnectionId, MyGuid.ToString());
}
}
My clients are Javascript clients, that have methods for(let me know if you need to see the code for this also). But basicly they listhen for the ComputeUnitCameOnline and when its run they call on the server SubscribeToHeartBeats. This means that whenever the server compute unit is doing some work it will call Running, which will trigger a ComputeUnitHeartBeat on javascript clients.
I hope you can use this to see how Groups and Connections can be used. And last, its also scaled out over multiply azure roles by adding a few lines of code:
GlobalHost.HubPipeline.EnableAutoRejoiningGroups();
GlobalHost.DependencyResolver.UseServiceBus(
serviceBusConnectionString,
2,
3,
GetRoleInstanceNumber(),
topicPathPrefix /* the prefix applied to the name of each topic used */
);
You can get the connection string on the servicebus on azure, remember the Provider=SharedSecret. But when adding the nuget packaged the connectionstring syntax is also pasted into your web.config.
2 is how many topics to split it about. Topics can contain 1Gb of data, so depending on performance you can increase it.
3 is the number of nodes to split it out on. I used 3 because i have 2 Azure Instances, and my localhost. You can get the RoleNumber like this (note that i hard coded my localhost to 2).
private static int GetRoleInstanceNumber()
{
if (!RoleEnvironment.IsAvailable)
return 2;
var roleInstanceId = RoleEnvironment.CurrentRoleInstance.Id;
var li1 = roleInstanceId.LastIndexOf(".");
var li2 = roleInstanceId.LastIndexOf("_");
var roleInstanceNo = roleInstanceId.Substring(Math.Max(li1, li2) + 1);
return Int32.Parse(roleInstanceNo);
}
You can see it all live at : http://taskqueue.cloudapp.net/#/compute-units
When using SignalR, after a client has connected to the server they are served up a Connection ID (this is essential to providing real time communication). Yes this is stored in memory but SignalR also can be used in multi-node environments. You can use the Redis or even Sql Server backplane (more to come) for example. So long story short, we take care of your scale-out scenarios for you via backplanes/service bus' without you having to worry about it.

Categories