Open browser window on click - c#

I am using botframework 3.9 and for some reasons I can't upgrade now. I would like to know if there is a way to open a new browser window where I can render a page or fire a JavaScript function. Here is how I am opening link:
await context.PostAsync(#"please [click here](http://www.example.com/)");
This does renders the link however, I wanna open a link in JavaScript window so I can close the window programmatically or if possible if I can fire some JavaScript function.

This is actually much easier than you think. If you have a look at the WebChat README you can see there are many ways WebChat can be customized. Pay particular attention to sample 11, which you can demo here. The body of that page looks like this:
<div id="webchat" role="main"></div>
<script>
(async function () {
// In this demo, we are using Direct Line token from MockBot.
// To talk to your bot, you should use the token exchanged using your Direct Line secret.
// You should never put the Direct Line secret in the browser or client app.
// https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication
const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' });
const { token } = await res.json();
// We are creating our own version of Redux store, which include middleware and optional initial state.
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
// After connected, we will send a message by dispatching a Redux action.
dispatch({ type: 'WEB_CHAT/SEND_MESSAGE', payload: { text: 'sample:backchannel' } });
} else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
// When receiving an activity of type "event" with name of "sample:backchannel", prompt it out.
const { activity } = action.payload;
if (activity.type === 'event' && activity.name === 'sample:backchannel') {
alert(JSON.stringify(activity, null, 2));
}
}
return next(action);
}
);
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
// We will use a custom version of Redux store, which we added middleware to handle backchannel messages.
store
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
</script>
You can see in this sample that WebChat has been modified to respond to certain activities from the bot by opening a popup window using JavaScript's alert function. The modification is done by creating a store and then passing that store as an argument to renderWebChat.
Rather than opening an alert window, you want to open a window you can close. This could be achieved if you modify the store to look like this:
let windows = {};
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const { activity } = action.payload;
if (activity.type === 'event') {
let url = activity.value;
if (activity.name == 'open' && !windows[url]) {
windows[url] = window.open(url);
}
if (activity.name == 'close' && windows[url]) {
windows[url].close();
windows[url] = null;
}
}
}
return next(action);
}
);
You don't have to implement it this way, but I've implemented it so that when WebChat receives an event activity named open it will open a window and when it receives an event activity named close it will close a window. It even keeps track of multiple windows so you can choose which window to close.
I've set up a bot that sends open and close events when the user types "open [url]" or "close [url]". The bot code looks like this:
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var text = activity.Text;
var words = text.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
var firstWord = words.FirstOrDefault().ToLower();
var secondWord = words.Length > 1 ? words[1] : "https://stackoverflow.com/";
Activity reply = null;
switch (firstWord)
{
case "open":
case "close":
reply = activity.CreateReply();
reply.Type = ActivityTypes.Event;
reply.Name = firstWord;
reply.Value = secondWord;
break;
default:
reply = activity.CreateReply("Try \"open ...\" or \"close ...\"");
break;
}
await connector.Conversations.SendToConversationAsync(reply);
Hopefully you can use this information and modify it to suit your needs.

Related

Web push C# library function

I am currently working on web push notifications and am at the last stage of using the web push libraries to send the notification.
I am using the C# web push library here. However, I do not see a notification when on the page or when not on it.
I am attaching my code below:
I wrote the code in my store subscription method so it could be one of the issues.
[HttpPost]
public void StoreSubscription(string [] publicKey, string [] auth, string notificationEndPoint )
{
var pushEndpoint = notificationEndPoint;
var pushAuth = auth[0].ToString();
var pushP256DH = publicKey[0].ToString();
var subject = "mailTo:hhhhhhh#gmail.com";
var uPublicKey = "yyzzxx";
var privateKey = "xxyyzz";
System.IO.File.WriteAllText(#"\Desktop\Subscription.txt", pushEndpoint);
var subscription = new PushSubscription(pushEndpoint, pushP256DH, pushAuth);
var gcmAPIKey = "AAAA";
var vapidDetails = new VapidDetails(subject, uPublicKey, privateKey);
var webPushClient = new WebPushClient();
try
{
webPushClient.SetGCMAPIKey(gcmAPIKey);
webPushClient.SendNotification(subscription, "payload", gcmAPIKey);
}
catch (WebPushException exception)
{
Console.WriteLine("HTTP status Code:" + exception.StatusCode);
}
}
And my service worker code is as follows for handling the push:
self.addEventListener('push', function (event) {
debugger
var body;
if (event.data) {
body = event.data.text();
} else {
body = 'Push message no payload';
}
var options = {
body: body,/*'This message was generated from a push'*/
icon: '/Images/noun_Pushing_1823359.png',
vibrate: [100, 200, 100, 200, 400],
data: {
dateOfArrival: Date.now(),
primaryKey: '2'
},
actions: [
{
action: 'explore', title: 'Explore this new world',
icon: '/Images/noun_Check Mark_4870.png'
},
{
action: 'close', title: 'Close',
icon: '/Images/noun_Close_887590.png'
},
]
};
event.waitUntil(
self.registration.showNotification('Push Notification', options)
);
});
I have been stuck on this for almost a long time now and very new to promise, service worker and push and notification apis.
the function is getting hit and does not throw any exception. Also, when i put a debugger in the service worker, it does not get hit so apparently the push is not getting handles.I might be completely wrong on this.
I had the same issue. I base 64 encoded my auth and p256dh used to create the subscription.
If there is no exception it could mean the JSON payload is valid JSON but in the wrong format for the service worker. I Changed my payload to a valid JSON object for my service worker (Angular):
{ "notification": {"title": "message title", "body": "message body"} }
Please see docs... https://developer.mozilla.org/en-US/docs/Web/API/Notification/Notification
Sent notification and hit the service worker.
I was using Vapid Details not GCMApiKey.

Proper way to insert into database when receiving a POST request

My slack application currently sends buttons attached with messages. Whenever a button is clicked, it sends a post request. If the button's attached value is true, it saves a value to the database.
How the button should work is that when it's first clicked by any user, it replies with a Ok status and a message saying "Correct", anything subsequently will say "question has already been answered".
The problem i come across is that if multiple people click the button where it's attached value is set to true roughly at the same time. It'll all respons with "Correct". May I ask how should i be responding to the post request and how should i be inserting into the database sequentially so that only one correct is sent.
Current code
public async Task<ActionResult> Post()
{
var payload = Request.Form.FirstOrDefault(x => x.Key == "payload");
bool value= JsonConvert.DeserializeObject<RootObject>(payload.Value);
using (var contexts = new TriviaBotDbContextFactory().CreateDbContext(null))
{
if (value)
{
// return if
var item = contexts.Questions.Include(x => x.Guesses).First(x => x.Id == question.Id);
if (item.Guesses.Any(y => y.Correct))
return StatusCode(200);
// Send Message Code
SBMClient client = new SBMClient(webHook);
Message msg = new Message("Correct");
client.Send(msg);
// Save to database
item.Guesses.Add(new Answer
{
Correct = true,
User = button.user.name
});
await contexts.SaveChangesAsync();
}
}
return StatusCode(200);
}

Send email from Xamarin.Forms app using Dependency Service

In my app, for debugging purposes and testing purposes I need to send an email.
How do I present the mail controller, when the class that sends it does not contain a definition for PresentViewController ? The class needs to fire off the email app after the user clicks "yes" from the alert which fires.
public async Task<bool> SendEmail(Exception ex)
{
var result = await SendNotificationToRequestSendingEmail();
if (result)
{
if (MFMailComposeViewController.CanSendMail)
{
mailController = new MFMailComposeViewController();
mailController.SetToRecipients(new string[] { "test#one.com", "test#two.com" });
mailController.SetSubject("Details");
mailController.SetMessageBody($"Message: {ex.Message}" +
$"Exception: {ex.ToString()}"
, false);
mailController.Finished += (object s, MFComposeResultEventArgs args) =>
{
Console.WriteLine(args.Result.ToString());
args.Controller.DismissViewController(true, null);
};
this.PresentViewController(mailController, true, null); //this line causes the error
}
}
return true;
}
How can I fix this problem or get around it? This is called from a Xamarin Forms page.
Please take a look at this answer:
Sending e-mail from Gmail in Xamarin.Forms app
besides that you can also do it with this NuGet package:
https://www.nuget.org/packages/Xam.Plugins.Messaging/

How to custom message on browser when internet is not connected

I want to show custom message when my web application is failed to connect to internet.
Currently when my internet connectivity fails then the browser shows "unable to connect" or "server not found". so I want to show my custom message on my page.
I have written this :
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (bb == true)
{
//custom message
}
else
//meesage
But still it is not working.
How can I show that?
I think you are expecting internet connectivity from browser, if so use navigator.onLine;
<script type="text/javascript">
var isOnline = navigator.onLine;
if (!isOnline)
alert("Your custom message for no internet connectivity!!!");
</script>
Periodically call from client to server, and if there is no answer or not expecting answer - show error message.
for web forms:
create handler with implemetation of ProcessRequest like this:
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Ok");
}
for mvc:
create action with simple result like this:
public ActionResult CheckInternetConnection()
{
return Json("Ok");
}
of course, this request handlers should not require any authorization or another pretreatment
then create js timer and method for request
var maxTime = <your interval time>;
var timer;
//write own method for check request
function performRequest() {
var xhr = new XMLHttpRequest();
// reserve 1 sec for timeout function execution
// if we didn't - you can get a situation when
// simultaneously performing more than 1 request
xhr.timeout = maxTime - 1000;
xhr.ontimeout = function {
//waiting to long
alert('<your message>');
window.clearInterval(timer);
};
xhr.open('GET', '<url of your check connection handler>', true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState != 4)
return;
if (xhr.responseText !== 'OK') {
//Can't access to handler
alert('<your message>');
window.clearInterval(timer);
}
}
}
//after page load start request timer
document.onload += function () {
timer = window.setInterval(performRequest, maxTime);
}
I haven't debug this code.

Fans-only content in facebook with asp.net C# sdk

Hi i'm developing an application in facebook with c# sdk and i want that the user whom liked my page can only use my application. (Like woobox)
I found some solutions in php in this link but there isn't any source about .net how can i get the liked info in ASP.NET
I find another examples in php in this link again but i can't find c# answer :\
Thanks
You get signed request when your web page is loaded within facebook canvas app; you should be able to parse signed request something similar to following:
if (Request.Params["signed_request"] != null)
{
string payload = Request.Params["signed_request"].Split('.')[1];
var encoding = new UTF8Encoding();
var decodedJson = payload.Replace("=", string.Empty).Replace('-', '+').Replace('_', '/');
var base64JsonArray = Convert.FromBase64String(decodedJson.PadRight(decodedJson.Length + (4 - decodedJson.Length % 4) % 4, '='));
var json = encoding.GetString(base64JsonArray);
var o = JObject.Parse(json);
var lPid = Convert.ToString(o.SelectToken("page.id")).Replace("\"", "");
var lLiked = Convert.ToString(o.SelectToken("page.liked")).Replace("\"", "");
var lUserId= Convert.ToString(o.SelectToken("user_id")).Replace("\"", "");
}
You need to add reference to json libraries in order to parse signed requestin C#, download from http://json.codeplex.com/
Also refere to How to decode OAuth 2.0 for Canvas signed_request in C#? if you are worndering about signed request.
This is only possible with the legacy APIs, or with the user_likes permission. As you want a solution without specific permissions I'll show you 2 methods. Use them in combination with AJAX to refresh the page when a user presses like.
Option 1) REST API
Using the legacy API, it's possible to use Pages.IsFan
https://api.facebook.com/method/pages.isFan?
page_id=...&
uid=...&
access_token=...
Do this in C# as follows.
var appID = "....";
var appSecret = "....";
var uid = "....";
var pageId = "....";
WebClient client = new WebClient();
var appAuthUri = string.Concat("https://graph.facebook.com/oauth/access_token?",
"client_id=", appID,
"&client_secret=", appSecret,
"&grant_type=", "client_credentials"
);
var response = client.DownloadString(appAuthUri);
var access_token = response.Split('=')[1];
var isFanUri = string.Concat("https://api.facebook.com/method/pages.isFan?",
"format=", "json",
"&page_id=", pageId,
"&uid=", uid,
"&access_token=", access_token
);
response = client.DownloadString(isFanUri);
bool isFan;
bool.TryParse(response, out isFan);
Option 2) Client side
The FBXML method. This is done with Javascript on the client, by subscribing to an event when the user clicks the like button. It's documented here.
How do I know when a user clicks a Like button?
If you are using the XFBML version of the button, you can subscribe to
the 'edge.create' event through FB.Event.subscribe.
Generate an FBXML like button here.
<div id="fb-root"></div>
<script>(function(d){
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js#appId=132240610207590&xfbml=1";
d.getElementsByTagName('head')[0].appendChild(js);
}(document));</script>
<div class="fb-like" data-href="http://www.thecodeking.co.uk" data-send="true" data-width="450" data-show-faces="false"></div>
Then subscribe to the edge.create event using the Javascript SDK. Place this code in the document BODY preferably just before the end.
<script type="text/javascript">
<!--
window.fbAsyncInit = function () {
FB.init({ appId: '245693305442004', status: true, cookie: true, xfbml: true });
FB.Event.subscribe('edge.create',
function (href, widget) {
// Do something here
alert('User just liked '+href);
});
(function () {
var e = document.createElement('script'); e.async = true;
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
document.getElementById('fb-root').appendChild(e);
} ());
};
//-->
</script>
this.canvasAuthorizer = new CanvasAuthorizer {
Permissions = new[] { "user_about_me", "publish_stream", "offline_access", "user_likes", "friends_about_me" }
};
this.canvasAuthorizer.Authorize();
if (FacebookWebContext.Current.IsAuthorized())
{
this.facebookWebClient = new FacebookWebClient(FacebookWebContext.Current);
string requested_Data = HttpContext.Current.Request.Form["signed_request"];
dynamic decodedSignedRequest = FacebookSignedRequest.Parse(this.facebookApplication, requested_Data);
if (decodedSignedRequest.Data.page != null)
{
// Funs Page
this.IsLike = decodedSignedRequest.Data.page.liked;
}
else
{
// Application Page
dynamic likes = this.facebookWebClient.Get("/me/likes");
foreach (dynamic like in likes.data)
{
if (like.id == this.FacebookFanPageID)
{
this.IsLike = true;
}
}
}
}
If your app is a canvas app, you could (should?) use the signed_request parameter to check if the user likes the page it's on:
# pseudocode
signed_request = decode_signed_request()
if signed_request['page']['liked']:
# user liked page, do something cool
else:
# user doesn't like page. redirect somewhere to tell them why they should
The signed_request is passed to your page as a POST variable; just as if there was a form field named signed_request and the form was submitted on the page previous to yours (in fact this is basically how facebook "runs" your app; the form is auto-submitted instead of waiting for a user to submit it). So in ASP.net you should be able to get it through the Request object:
Request["signed_request"]
This approach is useful if you're creating a "tab app" for a page; you can detect whether the user liked the page without them granting you extra permissions.
This can be done in PHP with the help of an SQL Query
`$result = $facebook->api(array( "method" => "fql.query",
"query" => "SELECT uid FROM page_fan WHERE uid=$uid AND page_id=$page_id"
));
Here $result variable can be used for segregating the Fan and non-Fan content

Categories