Bot Framework v4 Loading Facebook Webview - c#

I'm trying to figure out how to get the MS Bot Framework v4 to work with the Facebook Web View. Currently there isn't anything on the entire internet on how to get this working. There are some examples, like this one, showing how it can work with BF v3.
What I can't figure out is how this works with HeroCards and CardActions in v4.
It seems from the documentation that this type of feature would require an ActionTypes that included a value for web_url which that enum completely ommits. Suggesting this feature isn't supported in BF v4.
I'm currently porting a Botman PHP Bot to MS Bot Framework at it seems it's extremely trivial to do this in Botman by simple calling enableExtensions() on the button element.
I've tried too many approaches to list here but the current attempt looks like this:
var viewButton = new CardAction(
"web_url",
"View Details",
null,
"",
"",
"https://myurl",
JObject.FromObject(new { messenger_extensions = true }));
I've gone through all the domain whitelisting processes so I'm sure that is all ready to go, However, with my current attempts in place Messenger just errors as it seems Favebook dislikes the JSON the Bot Framework is producing.
I've also tried sub-classing the CardAction class like this:
public class WebViewCardAction : CardAction
{
public WebViewCardAction(string displayText, string url)
{
Type = "web_url";
Url = url;
Title = displayText;
MessengerExtensions = true;
WebviewHeightRatio = "compact";
}
[JsonProperty(PropertyName = "url")]
public string Url { get; set; }
[JsonProperty(PropertyName = "webview_height_ratio")]
public string WebviewHeightRatio { get; set; }
[JsonProperty(PropertyName = "messenger_extensions")]
public bool MessengerExtensions { get; set; }
}
Which when looking at the JSON in the Bot Framework emulator produces JSON like this:
{
"messenger_extensions": true,
"title": "View Details",
"type": "web_url",
"url": "https://myurl",
"webview_height_ratio": "compact"
}
Which seems to agree with the stuff I can find in the examples for FB messenger. But with this in place FB messenger errors without even displaying the HeroCard.
Has anyone got this working?
Are there any examples online to look at?

Because the activity schema has not changed, the example you linked also works in V4:
private async Task TestFacebookWebview(ITurnContext turnContext,
CancellationToken cancellationToken)
{
var reply = turnContext.Activity.CreateReply();
var attachment = new
{
type = "template",
payload = new
{
template_type = "button",
text = "Your 🍕 is on it's way!",
buttons = new[]
{
new
{
type = "web_url",
url = "https://mybot.azurewebsites.net/",
title = "See on map",
webview_height_ratio = "compact",
messenger_extensions = true,
},
},
},
};
reply.ChannelData = JObject.FromObject(new { attachment });
await turnContext.SendActivityAsync(reply, cancellationToken);
}
As you can see, there's no need for hero cards or card actions. In this example, the Facebook webview is invoked using a button template that's passed through the ChannelData, which is metadata in the activity that's specific to the channel. Messenger reads that data and creates something that looks like a card for you.
Make sure you whitelist your domain in order for this to work.

Related

How to send a json object instead of a string with Azure Client SDK

I'm struggling with creating a message from a device to the IotHub in the correct format.
I'm using the Azure Client SDK (Microsoft.Azure.Devices.Client)
For better understanding lets start with a small example, we have the following string:
var TableName = "table01";
var PartitionKey = "key01";
string messagePayload = $"{{\"tablename\":\"{TableName}\",\"partitionkey\":\"{PartitionKey}\"}}";
( Taken from the example Send device to cloud telemetry) we create an eventMessage
using var eventMessage = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes(messagePayload))
{
ContentEncoding = Encoding.UTF8.ToString(),
ContentType = "application/json"
};
And then send it to the Cloud:
Console.WriteLine(messagePayload);
await deviceClient.SendEventAsync(eventMessage);
Output from the writeline, which is what I wanted in the first place:
{"tablename":"table01","partitionkey":"key01"}
What I can see in the shell after following the answer about watching incoming IotHub Messages:
{
"event": {
"origin": "WinSensorTest",
"module": "",
"interface": "",
"component": "",
"payload": "{\"tablename\":\"table01\",\"partitionkey\":\"key01\"}"
}
}
The Problem is, that I want it to either look like the code below or completely without the "event" etc, just the string above.
{
"event":{
"origin":"WinSensorTest",
"module":"",
"interface":"",
"component":"",
"payload":{
"tablename":"table01",
"partitionkey":"key01"
}
}
}
Where did I go wrong, how can the payload be correct json format?
Edit:
I just tried the same in Java, with the same result. Why does this not work, or is the data seen in the shell not correctly parsed?
If you create a proper Json object first it works and also shows up correct in the shell - interestingly only for this c# project, I tried doing the same in Java on Android and the same wierd formatting stuff still happens even after making an object with gson.
For the solution:
class JsonMessage
{
public string tablename { get; set; }
public string partitionkey { get; set; }
}
And then Used JsonMessage and JsonConvert to get the desired payload.
JsonMessage newMsg = new JsonMessage()
{
tablename = "table01",
partitionkey = "key01",
};
string payload = JsonConvert.SerializeObject(newMsg);
using var eventMessage = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes(payload))
{
ContentEncoding = Encoding.UTF8.ToString(),
ContentType = "application/json"
};

Getting error with Stripe: No such payment_intent: 'my payment intent id'

sorry I'm pretty new to coding so I don't know many of the abbreviations/shorthand stuff.
So I'm working with React and C# trying to use Stripe to handle payments and I've gotten to the point where I am getting back a payment_intent id, client_secret, and payment method Id, but when I run the code:
const result = await stripe.confirmCardPayment(this.state.clientSecret, {
payment_method: paymentMethodRQ.paymentMethod.id,
});
I get the error:
No such payment_intent. Which is a 404 for the /v1/payment_intent/confirm
I guess that means the payment intent isn't actually being created since it doesn't show up on the Stripe dashboard either. Not really sure how to fix this. Most of the other similar questions either use different languages or don't address how to solve my particular issue. I followed the documentation for collecting payments then paying out, found at https://stripe.com/docs/connect/collect-then-transfer-guide#setup
This is my React code for the submit:
handleSubmit = async (event) => {
event.preventDefault();
const { stripe, elements } = this.props;
if (!stripe || !elements) {
_logger("Stripe.js has not yet loaded.");
// Make sure to disable form submission until Stripe.js has loaded.
return;
}
const paymentMethodRQ = await stripe.createPaymentMethod({
type: "card",
card: elements.getElement(CardElement),
});
const result = await stripe.confirmCardPayment(this.state.clientSecret, {
payment_method: paymentMethodRQ.paymentMethod.id,
});
if (result.error) {
toast.error("payment not processed");
_logger(result.error.message, "payment not processed");
} else {
toast.success("The payment processing!");
if (result.paymentIntent.status === "succeeded") {
_logger("payument successful");
// havent gotten to this part yet
}
}
};
I am passing in an amount and currency for the PaymentIntentCreateOptions from React.
and this is my controller for the payment intent in Visual Studio:
[HttpPost("paymentintent")]
public async Task<IActionResult> PaymentIntent(PaymentIntentCreateOptions options)
{
StripeConfiguration.ApiKey = "my test secret key";
ItemResponse<PaymentIntentModel> response = new ItemResponse<PaymentIntentModel>();
var service = new PaymentIntentService();
var paymentIntent = service.Create(options);
Logger.LogInformation(paymentIntent.ToString());
var paymentIntentModel = new PaymentIntentModel();
paymentIntentModel.Id = paymentIntent.Id;
paymentIntentModel.ClientSecretKey = paymentIntent.ClientSecret;
response.Item = paymentIntentModel;
return Ok200(response);
}
You have to make sure that your public key you declare in the frontend matches your public key in your stripe account otherwise you will get this error.

How do i add Link to firebase cloud messaging with .net admin sdk

I am using the Firebase .net Admin SDK on my back end to send push notifications.
According to this link I should be able to add the following json into a message object that will open the set link when the notification is clicked on while the app is in background.
"webpush": {
"fcm_options": {
"link": "https://dummypage.com"
}
I have read through the .net Admin Sdk documentation but cannot figure out where to add this.
Here is the code that I used to new up the message object
var fcm = FirebaseAdmin.Messaging.FirebaseMessaging.DefaultInstance;
var Message = new Message()
{
Notification = new Notification
{
Title = title,
Body = message,
},
Token = user.PushTokenWeb,
};
var result = await fcm.SendAsync(Message);
Does anyone know where I would set the callback link?
In FirebaseAdmin .net v1.9.0 you can
var message = new Message()
{
Token = token,
Notification = new Notification()
{
Body = notificationBody,
Title = title
},
Android = new AndroidConfig()
{
Priority = Priority.High
},
Webpush = new WebpushConfig()
{
FcmOptions = new WebpushFcmOptions()
{
Link= "https://www.davnec.eu/aurora-boreale/previsioni/"
}
}
};
.NET SDK does not support this setting yet. It's only exposed in Node.js and Go at the moment. You can provide a pull request at https://github.com/firebase/firebase-admin-dotnet to implement this feature.

How do I grab user info from Microsoft Graph for authenticated user using Azure mobile app backend?

Using the backend of my app, I am attempting to capture information from Microsoft Graph for a user that has been authenticated and then add that user to a database. The authentication appears to be working correctly, but the user is never added to the database. I am really stuck on this. I've studied the online documentation extensively, but have been unable to find a solution. If I could just tell if the user properties were getting populated, I could figure out what's going on, but I've been unable to do that since the code runs on the server. (I've attempted to remote debug, but have been unable to successfully set a breakpoint.) Can anyone tell me what I'm doing wrong in the code below?
class MicrosoftAccountInfo
{
public string id { get; set; }
public string displayName { get; set; }
public string mail { get; set; }
}
[MobileAppController]
public class MicrosoftAccountController : ApiController
{
MicrosoftAccountCredentials credentials;
string msRequestUrl;
MyAppContext context;
EntityDomainManager<User> domainManager;
// GET api/<controller>
public async Task<User> Get()
{
if (credentials == null)
{
credentials = await this.User.GetAppServiceIdentityAsync<MicrosoftAccountCredentials>(this.Request);
}
msRequestUrl = "https://graph.microsoft.com/v1.0/me/?$select=id,displayName,mail";
var client = new System.Net.Http.HttpClient();
var headerValue = "Bearer" + credentials.AccessToken;
client.DefaultRequestHeaders.Add("Authorization", headerValue);
var resp = await client.GetAsync(msRequestUrl);
resp.EnsureSuccessStatusCode();
var msInfo = await resp.Content.ReadAsStringAsync();
MicrosoftAccountInfo info = JsonConvert.DeserializeObject<MicrosoftAccountInfo>(msInfo);
context = new MyAppContext();
domainManager = new EntityDomainManager<User>(context, Request);
var user = context.Users.FirstOrDefault(u => u.Email == info.mail);
if (user == null)
{
user = new DataObjects.User { Email = info.mail, UserName = info.displayName, ProviderId = info.id };
await domainManager.InsertAsync(user);
}
else if (string.IsNullOrEmpty(user.ProviderId))
{
user.UserName = info.displayName;
user.ProviderId = info.id;
await context.SaveChangesAsync();
}
return user;
}
}
As to why this is failing, it is difficult to determine without an actual error message. There are simply to many variables/potential failure points involved to say for sure.
That said, you can reduce the number of potential failure points by using the Microsoft Graph .NET Client Library. There is also a NuGet package available: Install-Package Microsoft.Graph.
This library will handle composing the Microsoft Graph and deserializing the response into an object. Along with removing a risk factor, it will greatly simplify your code:
Microsoft.Graph.GraphServiceClient graphClient =
new Microsoft.Graph.GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) =>
{
requestMessage.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", "{your-access-token}");
return Task.FromResult(0);
}));
Microsoft.Graph.User user = await graphClient.Me.Request().GetAsync();
I would also suggest implementing a monitoring solution that can trap exceptions on the server. This will help with debugging. If you're running on Azure, I strongly recommend using Application Insights. Aside from being free to get started, it is effectively a "click once, get monitoring" solution. It will handle wiring up the server and provide reporting for any exceptions it runs into.
Note that you can also use App Insights with your own servers or apps hosted on other services (i.e. AWS, RackSpace), there may however be some manual configuration required.

How to use Embedding with C#? Discord BOT

I am looking to embed the following:
Using the Discord API. I have looked and the only resources I can find are for Python, Java, Ruby, etc.
But when using:
var embed = new Message.Embed(
{
Author =
{
Name = "Name",
Url = "www.url.com"
}
});
It comes back with the message:
And:
Not sure What I need to do to be able use the embed library. Just looking for some guidance on how this works
Edit:
When Using this I get no errors but when running the embed doesnt seem to build. It doesnt error. It just never builds the embed variable
var embed = new Message.Embed
{
Author =
{
Name = "Lawler",
Url = "www.twitch.tv/Lawler"
},
Title = "www.twitch.tv/Lawler",
Thumbnail =
{
ProxyUrl = "https://yt3.ggpht.com/-m-P7t2g-ecQ/AAAAAAAAAAI/AAAAAAAAAAA/YtS2YsD8-AM/s900-c-k-no-mo-rj-c0xffffff/photo.jpg",
Url = "www.twitch.tv/Lawler"
},
Description = "**Now Playing**\n" +
"Rocket League\n" +
"**Stream Title**\n" +
"Lawler RLCS Caster"
};
*Note: I am using Discord v 0.9.6
You can create an Embed Message like the following code (using the most recent version of Discord.Net):
var builder = new EmbedBuilder()
{
//Optional color
Color = Color.Green,
Description = "This is the description of the embed message"
};
Build a field inside the Embed Message:
builder.AddField(x =>
{
x.Name = Author.Name;
x.Value = Author.Url;
x.IsInline = false;
});
And reply to the same channel context:
//Use await if you're using an async Task to be completed.
await ReplyAsync("", false, builder.Build())
The code above should build an embed message, there are more options in the Discord.Net docs. Link: https://docs.stillu.cc/guides/introduction/intro.html
I hope you find this helpful.
Just a quick look at your code, I think you've got a close parenthesis in the wrong place.
Try the following:
var embed = new Message.Embed()
{
Author =
{
Name = "Name",
Url = "www.url.com"
}
};
Again, without doing any research you may also need to do the following:
var embed = new Message.Embed()
{
Author = new Author()
{
Name = "Name",
Url = "www.url.com"
}
};
var embed = new EmbedBuilder()
instead of
var embed = new Message.Embed()
To send the message:
await Context.Channel.SendMessageAsync("", false, embed);
EDIT: 0.9.6 doesn't support embeds, so the code above is useless
If you are in Discord.Net 1.0.1, you can format an embed like so:
var eb = new EmbedBuilder() { Title = "Cool Title", Description = "Description" };
Read the documentation here for more info here.
And if you want to make your text look a little better, you can read the Discord Markdown Documentation here. This works in 0.9.6.
To send an embed use:
await Context.Channel.SendMessageAsync("", false, eb);

Categories

Resources