I can't configure a webhook URI for "Whatsapp Cloud API" - azure

I created an app and configure whatsapp but in configuring webhook I have issues
The error
URL can't be saved. The URL is ok, the endpoint was tested wih postman with no issues.
Server Code
I use Asp.Net Core - WebApi project and create a controller with the method and print in the console a log. I return Ok + challenge if token is equals, otherwise 403 http response.
using Microsoft.AspNetCore.Mvc;
namespace MyApiZ.WebApi.Controllers
{
[ApiController]
[Route("")]
public class MessageController : Controller
{
const string VerfifyToken = "1234";
[HttpGet("webhook")]
public ActionResult<string> SetupWebHook([FromQuery(Name = "hub_mode")] string hubMode,
[FromQuery(Name = "hub_challenge")] int hubChallenge,
[FromQuery(Name = "hub_verify_token")] string hubVerifyToken)
{
Console.WriteLine("█ WebHook with get executed. ");
Console.WriteLine($"█ Parameters: hub_mode={hubMode} hub_challenge={hubChallenge} hub_verify_token={hubVerifyToken}");
if (!hubVerifyToken.Equals(VerfifyToken))
{
return Forbid("VerifyToken doesn't match");
}
return Ok(hubChallenge);
}
[HttpPost("webhook")]
public ActionResult ReceiveNotification([FromBody] string data)
{
Console.WriteLine("█ WebHook with Post executed. ");
Console.WriteLine(data);
return Ok();
}
public IActionResult Index()
{
return View();
}
}
}
Test with Postman
No issues in request from Postman
My app is hosted in Azure App Service. I checked the app log in Azure Portal.
When the request is executed in Postman, the messages are printed. But when click on facebook in the "Verify and save button" the error is present, the message aren't print in the log, the endpoint is never called.

I have written a brief article on WhatsApp Cloud API like how to send and receive WhatsApp messages and also set up a never expiry access token. Please have a look enter link description here
You will get your answer from my article. BTW when you click the verify & save button then you will get the response from WhatsApp to your callback URL. You just need to respond back the hub_challenge key(sent from whatsapp) respond back to whatsapp with 200 status code then your webhook should automatically verify

Simple change
from
public ActionResult<string> SetupWebHook([FromQuery(Name = "hub_mode")] string hubMode,
[FromQuery(Name = "hub_challenge")] int hubChallenge,
[FromQuery(Name = "hub_verify_token")] string hubVerifyToken)
to
public ActionResult<string> SetupWebHook([FromQuery(Name = "hub.mode")] string hubMode,
[FromQuery(Name = "hub.challenge")] int hubChallenge,
[FromQuery(Name = "hub.verify_token")] string hubVerifyToken)

Once you click the Verify and Save button then you will get the API request from WhatsApp to your server webhook callback URL.
Now, your webhook needs to respond back > hub_challenge.

Related

sending mails using sendgrid from azure app-service webjob

I have developed a C# console application sending emails to our customers when certain conditions occur. Mails are not sent when application is deployed as azure webjob.
When testing from visual studio in my development environment Mails are sent without any problems as intended, but when the application is deployed and run as an azure app-service webjob no mails are sent. The application is otherwise working as intended also when deployed as azure webjob.
public enum MailType : short { Plain, Html }
private static string MimeType(MailType type)
{ return (type == MailType.Html) ? "text/html" : "text/plain"; }
private static async Task sendMail(string to, string name, string subject, MailType mailType, string content)
{
SendGridMessage msg = new SendGridMessage();
msg.From = new EmailAddress("noreply#foo.org", "Foo Ltd.");
msg.AddTo(to, name);
msg.Subject = subject;
msg.AddContent(MimeType(mailType), content);
SendGridClient client = new SendGridClient(SendGridAPIKey);
await client.SendEmailAsync(msg);
}
public static void SendMail(string to, string name, string subject, MailType mailType, string content)
{
sendMail(to, name, subject, mailType, content).Wait();
}
Answers to all other questions regarding this issue (a lot of developers have met this problem) focus on the code; especially the async implementation, but it seems this is not the issue. Does azure have some restrictions to the communication between the application deployed as webjob and the sendgrid server? (I am using the sendgrid and sendgrid.helpers.mail)
I test with you code and it work well both on local and on Azure. I invoke the SendMail method in a queueTrigger.
public static void ProcessQueueMessage([QueueTrigger("queue1")] string message, TextWriter log)
{
log.WriteLine(message);
SendMail("xxxxx#gmail.com", "xxxxx", "hello world", MailType.Plain, "have a good day.");
}
So you could refer to the following ways to troubleshoot it.
1.Check your SendGridAPIKey. If you stored SendGridAPIKey as an environment variable in the project, you need to go to Configuration>Application Settings and add the key in it.
2.Check your SendGrid Activity.The problem could be getting your request to SendGrid, or it could be that SendGrid is getting your request but isn't fulfilling it. Check the Activity Feed and search for the particular email you are expecting

Messages not coming thru to Azure SignalR Service

I'm implementing Azure SignalR service in my ASP.NET Core 2.2 app with React front-end. When I send a message, I'm NOT getting any errors but my messages are not reaching the Azure SignalR service.
To be specific, this is a private chat application so when a message reaches the hub, I only need to send it to participants in that particular chat and NOT to all connections.
When I send a message, it hits my hub but I see no indication that the message is making it to the Azure Service.
For security, I use Auth0 JWT Token authentication. In my hub, I correctly see the authorized user claims so I don't think there's any issues with security. As I mentioned, the fact that I'm able to hit the hub tells me that the frontend and security are working fine.
In the Azure portal however, I see no indication of any messages but if I'm reading the data correctly, I do see 2 client connections which is correct in my tests i.e. two open browsers I'm using for testing. Here's a screen shot:
Here's my Startup.cs code:
public void ConfigureServices(IServiceCollection services)
{
// Omitted for brevity
services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions => {
jwtOptions.Authority = authority;
jwtOptions.Audience = audience;
jwtOptions.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// Check to see if the message is coming into chat
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/im")))
{
context.Token = accessToken;
}
return System.Threading.Tasks.Task.CompletedTask;
}
};
});
// Add SignalR
services.AddSignalR(hubOptions => {
hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(10);
}).AddAzureSignalR(Configuration["AzureSignalR:ConnectionString"]);
}
And here's the Configure() method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Omitted for brevity
app.UseSignalRQueryStringAuth();
app.UseAzureSignalR(routes =>
{
routes.MapHub<Hubs.IngridMessaging>("/im");
});
}
Here's the method I use to map a user's connectionId to the userName:
public override async Task OnConnectedAsync()
{
// Get connectionId
var connectionId = Context.ConnectionId;
// Get current userId
var userId = Utils.GetUserId(Context.User);
// Add connection
var connections = await _myServices.AddHubConnection(userId, connectionId);
await Groups.AddToGroupAsync(connectionId, "Online Users");
await base.OnConnectedAsync();
}
Here's one of my hub methods. Please note that I'm aware a user may have multiple connections simultaneously. I just simplified the code here to make it easier to digest. My actual code accounts for users having multiple connections:
[Authorize]
public async Task CreateConversation(Conversation conversation)
{
// Get sender
var user = Context.User;
var connectionId = Context.ConnectionId;
// Send message to all participants of this chat
foreach(var person in conversation.Participants)
{
var userConnectionId = Utils.GetUserConnectionId(user.Id);
await Clients.User(userConnectionId.ToString()).SendAsync("new_conversation", conversation.Message);
}
}
Any idea what I'm doing wrong that prevents messages from reaching the Azure SignalR service?
It might be caused by misspelled method, incorrect method signature, incorrect hub name, duplicate method name on the client, or missing JSON parser on the client, as it might fail silently on the server.
Taken from Calling methods between the client and server silently fails
:
Misspelled method, incorrect method signature, or incorrect hub name
If the name or signature of a called method does not exactly match an appropriate method on the client, the call will fail. Verify that the method name called by the server matches the name of the method on the client. Also, SignalR creates the hub proxy using camel-cased methods, as is appropriate in JavaScript, so a method called SendMessage on the server would be called sendMessage in the client proxy. If you use the HubName attribute in your server-side code, verify that the name used matches the name used to create the hub on the client. If you do not use the HubName attribute, verify that the name of the hub in a JavaScript client is camel-cased, such as chatHub instead of ChatHub.
Duplicate method name on client
Verify that you do not have a duplicate method on the client that differs only by case. If your client application has a method called sendMessage, verify that there isn't also a method called SendMessage as well.
Missing JSON parser on the client
SignalR requires a JSON parser to be present to serialize calls between the server and the client. If your client doesn't have a built-in JSON parser (such as Internet Explorer 7), you'll need to include one in your application.
Update
In response to your comments, I would suggest you try one of the Azure SignalR samples, such as
Get Started with SignalR: a Chat Room Example to see if you get the same behavior.
Hope it helps!

Why a 400 response from Azure endpoint for Postman but works fine with the Alexa console?

I am new to developing Alexa skills so I am using a sample I found on the web as a C# endpoint hosted on Azure. It works correctly with the Alexa console but when I try to test the same endpoint with the Postman app, I get a 400 error.
When I use the Alexa console, it displays the JSON input that it sends to the endpoint and the JSON output that it receives from the endpoint. If I copy the JSON input and paste it into Postman and send it to the same endpoint, I get a 400 error. Obviously, I am missing something.
The following are my two source files and the JSON input.
RollTheDice.cs
public static class RollTheDice
{
[FunctionName("RollTheDice")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
var speechlet = new RollTheDiceSpeechlet();
return await speechlet.GetResponseAsync(req);
}
}
RollTheDiceSpeechlet.cs
public class RollTheDiceSpeechlet : SpeechletBase, ISpeechletWithContext
{
public SpeechletResponse OnIntent(IntentRequest intentRequest, Session session, Context context)
{
try
{
// Default to 6 sides if not specified
if (!int.TryParse(intentRequest.Intent.Slots["DiceType"].Value, out int numSides))
numSides = 6;
var rollResults = new Random().Next(Math.Max(1, numSides - 1)) + 1; // Account for random returning '0'
return new SpeechletResponse
{
ShouldEndSession = false,
OutputSpeech = new PlainTextOutputSpeech { Text = $"I rolled a {numSides} sided die and got a {rollResults}." }
};
}
catch (Exception ex)
{
return new SpeechletResponse
{
ShouldEndSession = false,
OutputSpeech = new PlainTextOutputSpeech { Text = ex.Message }
};
}
}
public SpeechletResponse OnLaunch(LaunchRequest launchRequest, Session session, Context context)
{
return new SpeechletResponse
{
ShouldEndSession = false,
OutputSpeech = new PlainTextOutputSpeech { Text = "Welcome to the Roll the Dice. Ask me to roll the dice." }
};
}
public void OnSessionEnded(SessionEndedRequest sessionEndedRequest, Session session, Context context)
{
return;
}
public void OnSessionStarted(SessionStartedRequest sessionStartedRequest, Session session, Context context)
{
return;
}
}
JSON Input
Again, everything works fine but when I test it with Postman I get a 404 error.
The endpoint is C# serverless function that I developed in Visual Studio 201.
When I run it locally, I copy/paste the URL in the Postman app and send a post. See attached screenshots.
As the error suggest you are missing Signature and SignatureCertChainUrl headers. These helps to protect your endpoint and verify that incoming requests were sent by Alexa. Any requests coming from other sources should be rejected. When you test it via Test Console these headers are included and you get successful response.
Headers:
Signature
SignatureCertChainUrl
There are two parts to validating incoming requests:
Check the request signature to verify the authenticity of the request.
Check the request timestamp to ensure that the request is not an old request.
More information on verifying that the request was sent by Alexa here

How to view response of Luis.ai in azure web bot app

I am working on a web bot app and I link it with luis.ai
I want to view the response of luis like which intent is been called and what was the entity called. I am using bot emulator version 4, but you can't find any type of info related to your intent or entities in it.
Is there any way we can see the json response of luis.ai ?
So that I can start building my bot further.
I am asking this because look How am I gonna know what's the format of luis response, how to get data from it as long as I don't know In which format i an receiving the response.
any details tutorial please?
There two ways to see luis response.
you can go to luis.ai and then copy the url of pulishment(in pulish section). And paste it in the navegator. You will get url like this: 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/xxxx?subscription-key=xxxxxxxxxx&verbose=true&timezoneOffset=0&q=your sentence', and setup q= your sentence.
Another way, you can log all luis conversation in you code. If you use c sharp bot builder, you can use this luis class.
[Serializable]
public class LogedLuisService : ILuisService
{
private ILuisService service;
private string moduleType;
public LogedLuisService(ILuisService service)
{
this.service = service;
}
public Uri BuildUri(LuisRequest luisRequest)
{
return service.BuildUri(luisRequest);
}
public LuisRequest ModifyRequest(LuisRequest request)
{
return service.ModifyRequest(request);
}
public Task<LuisResult> QueryAsync(Uri uri, CancellationToken token)
{
return service
.QueryAsync(uri, token)
.ContinueWith(
task => {
Trace.WriteLine("Luis: " + " : " + JsonConvert.SerializeObject(task.Result));
return task.Result;
});
}}

How to automate OAuth code retrieval from user in standalone program

Can any one help us to run the URL through java code :
we are trying to upload a file from our local drive to Gmail Drive.
Steps Followed
Generated the URL with the help of Google Developer(API)
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DriveScopes.DRIVE))
.setAccessType("online")
.setApprovalPrompt("auto").build();
String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
Got the below URL
https://accounts.google.com/o/oauth2/auth?access_type=online&approval_prompt=auto&client_id=1066028402320.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/drive
Run the URL in the internet browser
UserID and password is given as an input in the internet browser to get the unique response token
Now as a part of our development we have completed till step 2 and want to automate the steps 3 & 4 using java code. (After
generating the URL provided with our UserdId and password we should get the response as unique token.)
Expecting your help on this
I would use the following scenario
Set up local webserver to retrieve code from user's oauth redirect
Set redirect_uri of the flow to be local webserver and get auth url
Open browser of auth url for the user
Retrieve code from local webserver and exchange oauth code
Here are some more details with code.
Set up local webserver to retrieve HTTP request
Here is an example of setting local webserver with NanoHttpd
public class OAuthServer extends NanoHTTPD {
/**
* Constructs an HTTP server on given port.
*/
public DebugServer() {
super(8080);
}
#Override
public Response serve(String uri, Method method, Map<String, String> header, Map<String, String> parms, Map<String, String> files) {
bool error = false
string code = null
// User rejected approval
if (parm.containsKey("error")) {
error = true
}
// Here we get the code!
if (parm.containsKey("code")) {
code = parm.get("code")
}
StringBuilder sb = new StringBuilder();
sb.append("<html>");
sb.append("<head><title>Authorization</title></head>");
sb.append("<body>");
if (error) {
sb.append("<h1>User rejected</h1>");
}
if (code==null) {
sb.append("<h1>Unknown Error</h1>");
}
else {
sb.append("<h1>Success</h1>");
}
sb.append("</body>");
sb.append("</html>");
return new Response(sb.toString());
}
public static void main(String[] args) {
ServerRunner.run(OAuthServer.class);
}
}
Set redirect_uri of the flow to be local webserver and get auth url
String url = flow.newAuthorizationUrl().setRedirectUri("http://localhost:8080").build();
Open browser of auth url for the user
// open the default web browser for the HTML page
Desktop.getDesktop().browse(url);
Retrieve code from local webserver and exchange oauth code
Now, user will approve OAuth from the web browser and send code to the local webserver we just started. Now that we have the code retrieved from local webserver, we can parse it into int and authenticate and authorize with it!
Hope this helps

Resources