Google Calendar API V3 FreeBusy request receives Bad Request Error - google-calendar-api

I'm trying to fetch FreeBusy data from my Google calendar using the .NET client API V3.
The following code allows me to login using a service authentication and fetch the calendar list and calendar settings. I can also fetch the events as shown.
To make this work I have shared my calendar with my development Id:
<my-id>#developer.gserviceaccount.com
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Google.Apis.Calendar;
using Google.Apis.Calendar.v3;
using Google.Apis.Authentication;
using Google.Apis.Authentication.OAuth2;
using Google.Apis.Authentication.OAuth2.DotNetOpenAuth;
using DotNetOpenAuth.OAuth2;
using System.Diagnostics;
using Google.Apis.Calendar.v3.Data;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Discovery;
using Google.Apis.Drive.v2;
using Google.Apis.Util;
namespace consoleGoogleResearch
{
class Program
{
private const string SERVICE_ACCOUNT_EMAIL = "<your-value>#developer.gserviceaccount.com";
private const string SERVICE_ACCOUNT_PKCS12_FILE_PATH = #"<path-to\<your-value>-privatekey.p12";
/// <summary>
/// Build a Calendar service object authorized with the service account.
/// </summary>
/// <returns>Drive service object.</returns>
static CalendarService BuildCalendarService()
{
AssertionFlowClient client = new AssertionFlowClient(
GoogleAuthenticationServer.Description, new X509Certificate2(SERVICE_ACCOUNT_PKCS12_FILE_PATH, "notasecret", X509KeyStorageFlags.Exportable))
{
Scope = CalendarService.Scopes.Calendar.GetStringValue(),
ServiceAccountId = SERVICE_ACCOUNT_EMAIL,
};
OAuth2Authenticator<AssertionFlowClient> authenticator = new OAuth2Authenticator<AssertionFlowClient>(client, AssertionFlowClient.GetState);
return new CalendarService(authenticator);
}
public static void Main(string[] args)
{
var service = BuildCalendarService();
// Get the calendar service
Google.Apis.Calendar.v3.CalendarListResource.ListRequest clrq = service.CalendarList.List();
var result = clrq.Fetch();
// Prove we can get the settings.
SettingsResource.ListRequest slr = service.Settings.List();
var sr = slr.Fetch();
try
{
Console.WriteLine("Calendars: ");
foreach (CalendarListEntry calendar in result.Items)
{
Console.WriteLine("{0}", calendar.Id);
Console.WriteLine("\tAppointments:");
Google.Apis.Calendar.v3.EventsResource.ListRequest elr = service.Events.List(calendar.Id);
var events = elr.Fetch();
if (events.Items != null)
{
foreach (Event e in events.Items)
{
Console.WriteLine("\tSummary: {0}, Location: {1}", e.Summary, e.Location);
if (e.IsAllDayEvent())
{
Console.WriteLine("\t\tAll Day: {0}", e.Start.GetDateTime().ToLongDateString());
}
else
{
Console.WriteLine("\t\tFrom: {0}", e.Start.GetDateTime());
Console.WriteLine("\t\tTo: {0}", e.End.GetDateTime());
}
if (e.Attendees != null)
{
foreach (var att in e.Attendees)
{
Console.WriteLine("Attendee:\t\t\t{0}<{1}>", att.DisplayName, att.Email);
}
}
Console.WriteLine();
}
}
}
}
catch (Exception ex)
{
log.DebugFormat("Error: {0}", ex.Message);
}
// Attempt to get free busy data.
FreebusyResource.QueryRequest fbq = service.Freebusy.Query(new FreeBusyRequest());
FreeBusyRequestItem c = new FreeBusyRequestItem();
c.Id = "<your calendar id>";
fbq.Body.Items = new List<FreeBusyRequestItem>();
fbq.Body.Items.Add(c);
fbq.Body.TimeZone = "Europe/London";
fbq.Body.TimeMin = "2013-01-101T00:00:00.000Z";
fbq.Body.TimeMax = "2013-01-301T00:00:00.000Z";
// This call fails with global bad request
var fbres = fbq.Fetch();
Console.ReadKey();
}
}
static internal class Extensions
{
static internal DateTime GetDateTime(this EventDateTime edt)
{
if (String.IsNullOrEmpty(edt.DateTime))
{
if (String.IsNullOrEmpty(edt.Date))
{
return DateTime.MinValue;
}
else
{
return DateTime.Parse(edt.Date);
}
}
else
{
return DateTime.Parse(edt.DateTime);
}
}
static internal Boolean IsAllDayEvent(this Event e)
{
return (e.Start.DateTime == null && e.Start.Date != null);
}
}
}
However the code that attempts to fetch free busy information always receives a "bad request" error.
I have checked the request sent using fiddler and as far as I can see it is correct.
POST https://www.googleapis.com/calendar/v3/freeBusy?alt=json&prettyPrint=true HTTP/1.1
Authorization: Bearer <removed>
Content-Type: application/json; charset=utf-8
User-Agent: ConsoleApplication1 google-api-dotnet-client/ Win32NT/6.1.7601.65536 (gzip)
Host: www.googleapis.com
Content-Length: 144
Accept-Encoding: gzip, deflate
{"items":[{"id":"apps.vivid#gmail.com"}],"timeMax":"2013-01-301T00:00:00.000Z","timeMin":"2013-01-101T00:00:00.000Z","timeZone":"Europe/London"}
Can anyone tell me why I'm receiving the bad request error and more importantly how to fix it?
Many thanks
Chris.

The answer is in the comment above, I made a mistake with the dates.

Related

Why doesn't my PHP website receive the variable that I send POST from an Android Xamarin app?

I can't see the result that I send from a Visual Basic 2019 Xamarin Forms app to a PHP REST. Basically this is what I do in the Mainpage.xaml.cs:
protected override async void OnAppearing()
{
HttpClient client = new HttpClient();
Uri uri = new Uri("https://www.miweb.com/prueba.php");
Msj mensaje = new Msj { Mensaje = "PRUEBAAAAAA" };
string json = JsonConvert.SerializeObject(mensaje);
var content = new StringContent(json, UnicodeEncoding.UTF8, "application/json");
//HttpResponseMessage response = client.PostAsync(uri, content).Result;
using (var response = await client.PostAsync(uri, content))
{
}
base.OnAppearing();
}
The class Msj:
internal class Msj
{
public string Mensaje { get; internal set; }
}
And this is the PHP code:
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
$input = $_POST;
header("HTTP/1.1 200 OK");
$file = fopen("app.txt", "w");
fwrite($file, json_encode($input['Mensaje']) . PHP_EOL);
fclose($file);
exit();
}
The app.txt file is created, but its content is "null" (without quotes.)
To view the sent data you can use:
print_r($_POST);
From this you should be able to work out what is/isn't being sent and alter your code from there.
Finally I solved so, without JSON. Thanks to all:
protected override async void OnAppearing()
{
HttpClient client = new HttpClient();
Uri uri = new Uri("https://www.miweb.com/prueba.php");
var datos = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("mensaje", "SOLVED!")
};
var content = new FormUrlEncodedContent(datos);
using (var response = await client.PostAsync(uri, content))
{
}
base.OnAppearing();
}
I had the similar problem, I was trying to post to a website URL without index.php at the end, as I thought it wasn't needed. The script was posted to but POST variables were none.
When I appended "/index.php" to the URL, POST variables were there.
It is strange behavior.

Unauthorized when accessing Azure cognitive services from netcore3.1 console app

I have a netcore console app which is accessing the Azure's Text analysis API's using the Client library from the Microsoft.Azure.CognitiveServices.Language.TextAnalytics Nuget package.
When trying to access the API, I receive the following HttpException:
Unauthorized. Access token is missing, invalid, audience is incorrect (https://cognitiveservices.azure.com), or have expired.
Unhandled exception. System.AggregateException: One or more errors occurred. (Operation returned an invalid status code 'Unauthorized')
When accessing the same API using exactly the same code which is hosted on Azure Functions - everything works as expected. I was unable to find any info in the docs or anywhere else.
Try the .net core console app code below to use TextAnalytics SDK :
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.CognitiveServices.Language.TextAnalytics;
using Microsoft.Azure.CognitiveServices.Language.TextAnalytics.Models;
using Microsoft.Rest;
namespace TextAnalysis
{
class Program
{
private static readonly string key = "<your text analyisis service key>";
private static readonly string endpoint = "<your text analyisis service endpoint>";
static void Main(string[] args)
{
var client = authenticateClient();
sentimentAnalysisExample(client);
languageDetectionExample(client);
entityRecognitionExample(client);
keyPhraseExtractionExample(client);
Console.Write("Press any key to exit.");
Console.ReadKey();
}
static TextAnalyticsClient authenticateClient()
{
ApiKeyServiceClientCredentials credentials = new ApiKeyServiceClientCredentials(key);
TextAnalyticsClient client = new TextAnalyticsClient(credentials)
{
Endpoint = endpoint
};
return client;
}
class ApiKeyServiceClientCredentials : ServiceClientCredentials
{
private readonly string apiKey;
public ApiKeyServiceClientCredentials(string apiKey)
{
this.apiKey = apiKey;
}
public override Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
request.Headers.Add("Ocp-Apim-Subscription-Key", this.apiKey);
return base.ProcessHttpRequestAsync(request, cancellationToken);
}
}
static void sentimentAnalysisExample(ITextAnalyticsClient client)
{
var result = client.Sentiment("I had the best day of my life.", "en");
Console.WriteLine($"Sentiment Score: {result.Score:0.00}");
}
static void languageDetectionExample(ITextAnalyticsClient client)
{
var result = client.DetectLanguage("This is a document written in English.","us");
Console.WriteLine($"Language: {result.DetectedLanguages[0].Name}");
}
static void entityRecognitionExample(ITextAnalyticsClient client)
{
var result = client.Entities("Microsoft was founded by Bill Gates and Paul Allen on April 4, 1975, to develop and sell BASIC interpreters for the Altair 8800.");
Console.WriteLine("Entities:");
foreach (var entity in result.Entities)
{
Console.WriteLine($"\tName: {entity.Name},\tType: {entity.Type ?? "N/A"},\tSub-Type: {entity.SubType ?? "N/A"}");
foreach (var match in entity.Matches)
{
Console.WriteLine($"\t\tOffset: {match.Offset},\tLength: {match.Length},\tScore: {match.EntityTypeScore:F3}");
}
}
}
static void keyPhraseExtractionExample(TextAnalyticsClient client)
{
var result = client.KeyPhrases("My cat might need to see a veterinarian.");
// Printing key phrases
Console.WriteLine("Key phrases:");
foreach (string keyphrase in result.KeyPhrases)
{
Console.WriteLine($"\t{keyphrase}");
}
}
}
}
You can find your key and endpoint here on Azure portal :
Result :

How to implement reCaptcha V3 in ASP.NET

Does anyone have a full implementation demo of reCaptcha V3 in ASP.NET?
I found this article: Google Recaptcha v3 example demo
At the moment I am using reCaptcha V2 with the following code:
public bool RecaptchaValidate()
{
string Response = Request.Form["g-recaptcha-response"];//Getting Response String Append to Post Method
bool Valid = false;
//Request to Google Server
var CaptchaSiteKey = Settings["NewUserRegCaptchaSecretSiteKey"].ToString();
HttpWebRequest req = (HttpWebRequest)WebRequest.Create
(" https://www.google.com/recaptcha/api/siteverify?secret=" + CaptchaSiteKey + "&response=" + Response);
try
{
//Google recaptcha Response
using (WebResponse wResponse = req.GetResponse())
{
using (StreamReader readStream = new StreamReader(wResponse.GetResponseStream()))
{
string jsonResponse = readStream.ReadToEnd();
JavaScriptSerializer js = new JavaScriptSerializer();
ReCaptchaObject data = js.Deserialize<ReCaptchaObject>(jsonResponse);// Deserialize Json
Valid = Convert.ToBoolean(data.success);
}
}
return Valid;
}
catch (WebException ex)
{
throw ex;
}
}
On the view.ascx page I have:
<%# Register TagPrefix="recaptcha" Namespace="Recaptcha" Assembly="Recaptcha" %>
<script src='https://www.google.com/recaptcha/api.js'></script>
<scrip>
var recap = grecaptcha.getResponse();
if (recap.length == 0) {
$("#verifyhuman").css("display", "block");
}
</script>
<div class="g-recaptcha" data-sitekey="<%=ReCaptchaPublicKey%>" id="recaptcha" data-callback="recaptchaCallback"></div>
The simplest implementation:
In your cshtml file (at the top)
#section Scripts
{
<script src="https://www.google.com/recaptcha/api.js?render=your site key"></script>
<script>
grecaptcha.ready(function () {
grecaptcha.execute('your site key', { action: 'homepage' }).then(function (token) {
document.getElementById("foo").value = token;
});
});
</script>
}
In your cshtml, inside the form (just before </form>):
<input type="hidden" id="foo" name="foo" />
A function inside your Pagemodel class. See the documentation for the response object:
public static bool ReCaptchaPassed(string gRecaptchaResponse)
{
HttpClient httpClient = new HttpClient();
var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret=your secret key no quotes&response={gRecaptchaResponse}").Result;
if (res.StatusCode != HttpStatusCode.OK)
{
return false;
}
string JSONres = res.Content.ReadAsStringAsync().Result;
dynamic JSONdata = JObject.Parse(JSONres);
if (JSONdata.success != "true" || JSONdata.score <= 0.5m)
{
return false;
}
return true;
}
Finally, inside your OnPostAsync() handler, at the top:
if (!ModelState.IsValid)
{
return Page();
}
else
{
if (!ReCaptchaPassed(Request.Form["foo"]))
{
ModelState.AddModelError(string.Empty, "You failed the CAPTCHA.");
return Page();
}
}
Edit : I have added a demo project . Check this github repository .
https://github.com/NIHAR-SARKAR/GoogleRecaptchav3-example-In-asp.net
From frontend (.aspx page) you need to send ajax request to pass the token to backend server . Using "recaptcha.execute" U can get the response , and pass the token using ajax request .Please check the code block .
<script src="http://www.google.com/recaptcha/api.js?render=recaptchaSiteKey"></script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('recaptchaSiteKey', {action: 'homepage'}).then(function(token) {
$.ajax({
//pass the toket to Webmethod using Ajax
});
});
});
</script>
Reference link:
https://developers.google.com/recaptcha/docs/verify
https://developers.google.com/recaptcha/docs/display#js_api
Now in the aspx.cs you need to write a "[WebMethod]" to receive the token from Ajax request .
[WebMethod]
public static void CaptchaVerify(string token)
{
var responseString = RecaptchaVerify(token);
ResponseToken response = new ResponseToken();
response = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseToken>(responseString.Result);
}
To get the response from google recapcha api u need to use async call using httpClient . you also need to create a class which will contain same properties like the response string . After getting the "responseString" u need to convert the response to ResponseToken object by using Newtonsoft.Json.
response = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseToken>(responseString.Result);
private string apiAddress = "https://www.google.com/recaptcha/api/siteverify";
private string recaptchaSecret = googleRecaptchaSecret;
public async Task<string> RecaptchaVerify(string recaptchaToken)
{
string url = $"{apiAddress}?secret={recaptchaSecret}&response={recaptchaToken}";
using (var httpClient = new HttpClient())
{
try
{
string responseString= httpClient.GetStringAsync(url).Result;
return responseString;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
public class ResponseToken
{
public DateTime challenge_ts { get; set; }
public float score { get; set; }
public List<string> ErrorCodes { get; set; }
public bool Success { get; set; }
public string hostname { get; set; }
}
The accepted answer on this page is totally wrong!!! Google returns a score between 0 and 1 to indicate whether the submission is likely to be a bot or likely to be a human.
The success property returned only means that the recaptcha token was processed correctly.
It is the score property that should be checked, not the success property
These lines are the probelem
if (JSONdata.success != "true")
return false;
return true;
The actual score to compare will probably be in a variable that can be adjusted if need be. Google recommends starting with 0.5.
So the code should change to something like:
var recaptchaScore = 0.5m; // this could be in appSettings or whereever/however you are storing your constants
if (JSONdata.success != "true" || JSONdata.score <= recaptchaScore)
return false;
return true;
Of course you will likely want to add logging etc to this answer but this is the bare logic that is required.
The accepted answer isn't following the Google's spec for sending the response and checking the action. Its Http requests will exhaust the number of sockets also. This is my implementation.
Browser
// Could be called from an event or another piece of code.
function FunctionToCall(term) {
// Google reCaptcha check
grecaptcha.ready(function() {
grecaptcha.execute(reCaptchaSiteKey, {action: "search"}).then(function(token) {
// You can take the response token Google returns, check it server side using
// the GoogleReCaptcha class and respond with a pass or fail. If a pass, run a block of code client side.
// { ... block of code ... }
// Or if you want to secure an endpoint that your sending request too.
// Send the response token with the request to your endpoint and check the response token server side and respond with a pass or fail.
// Use the repsonse to show a message or redirect site, etc
});
});
}
Server
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class GoogleReCaptcha
{
public class ReCaptchaResponse
{
public bool success { get; set; }
public double score { get; set; }
public string action { get; set; }
public DateTime challenge_ts { get; set; }
public string hostname { get; set; }
[JsonProperty("error-codes")]
public List<string> error_codes { get; set; }
}
public static async Task<(ReCaptchaResponse Response, bool HasPassed)> ReCaptchaPassed(string secretKey, string gRecaptchaToken, string expected_action)
{
try
{
// validate
if (string.IsNullOrWhiteSpace(secretKey) || string.IsNullOrWhiteSpace(gRecaptchaToken) || string.IsNullOrWhiteSpace(expected_action))
return (null, false);
// we use HttpClientFactory to avoid exhausting number of sockets available
var httpClient = HttpClientFactory.Create();
var verifyUrl = "https://www.google.com/recaptcha/api/siteverify";
var parameters = new Dictionary<string, string>
{
{"secret", secretKey},
{"response", gRecaptchaToken}
//{"remoteip", "ip" } <= this is optional
};
using (HttpContent formContent = new FormUrlEncodedContent(parameters))
{
using (var response = await httpClient.PostAsync(verifyUrl, formContent).ConfigureAwait(false))
{
// check HTTP response code
if (response.StatusCode != HttpStatusCode.OK)
return (null, false);
// get reCaptcha response
string gRecaptchaJsonresult = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(gRecaptchaJsonresult))
return (null, false);
// check reCaptcha response is successful
var recaptcha_response = JsonConvert.DeserializeObject<ReCaptchaResponse>(gRecaptchaJsonresult);
if (recaptcha_response == null)
{
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha response is null" }, DefaultLogValues);
return (recaptcha_response, false);
}
if (!recaptcha_response.success)
{
var errors = string.Join(",", recaptcha_response.error_codes);
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha error codes:\n{errors}" }, DefaultLogValues);
return (recaptcha_response, false);
}
// check reCaptcha response action
if (recaptcha_response.action.ToUpper() != expected_action.ToUpper())
{
//Logging.Log(new Logging.LogItem { Msg = $"Google RecCaptcha action doesn't match:\nExpected action: {expected_action} Given action: {recaptcha_response.action}" }, DefaultLogValues);
return (recaptcha_response, false);
}
// response score
// anything less than 0.5 is a bot
if (recaptcha_response.score < 0.5)
return (recaptcha_response, false);
else
return (recaptcha_response, true);
}
}
}
catch (Exception ex)
{
//Logging.Log(ex, DefaultLogValues);
// default to false
return (null, false);
}
}
}
You would call it like so..
var reCaptchaTask = GoogleReCaptcha.ReCaptchaPassed(Settings.GoogleReCaptcha.secret_key, SearchReq.gRecaptchaToken, "search");
Make sure to put your keys in a settings file and not in the code.
There are several Recaptcha libraries available for ASP.Net. I chose to use reCAPTCHA.AspNetCore because it provides an HtmlHelper.
Please note that this library only supports one ReCatpcha per page, and it doesn't support Recaptcha v3 passive monitoring on non-form pages.

How to send an XML to an asp.net Web api call?

I am trying to make a web API Post method call as follows but it not working as expected,xmlcontent seems OK but somehow the formatting seems messed up when the request is being sent and the response throws an error ,I double checked the XML from python and it works,is there a better way to create and send the XML?what am I doing wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
namespace WebApiXML
{
public class Program
{
static void Main(string[] args)
{
testWCF2(); //Or whatever
Console.ReadLine();
}
public static async Task testWCF2()
{
string xmlcontent = #"<SoftwareProductBuild>
<BuildSource>DATASOURCE</BuildSource>
<BuiltBy>username1</BuiltBy>
<CreatedBy>username1</CreatedBy>
<Name>username1_1959965_1969310_524f7fef-5b37-11e7-b4ee-f0921c133f10_UL.AB.1.2_test2</Name>
<Status>Approved</Status>
<BuiltOn>2017-06-27T06:20:30.275690</BuiltOn>
<Tag>username1_1959965_1969310_524f7fef-5b37-11e7-b4ee-f0921c133f10_test2</Tag>
<Keywords>
<KeywordInfo>
<Name>subystem</Name>
</KeywordInfo>
</Keywords>
<SoftwareImageBuilds>
<SoftwareImageBuild>
<Type>LA</Type>
<Name>username1_1959965_1969310_524f7fef-5b37-11e7-b4ee-f0921c133f10_UL.AB.1.2_test2</Name>
<Location>\\location1\data1\PRECOMMIT_OS_DEF</Location>
<Variant>PRECOMMIT_OS_DEF</Variant>
<LoadType>Direct</LoadType>
<Target>msm8998</Target>
<SoftwareImages>
<SoftwareImage>
<Name>UL.AB.1.2</Name>
</SoftwareImage>
</SoftwareImages>
</SoftwareImageBuild>
</SoftwareImageBuilds>
</SoftwareProductBuild>";
#region using
using (var client = new System.Net.Http.HttpClient())
{
var response = await client.PostAsXmlAsync("http://server:8100/api/SoftwareProductBuild", xmlcontent);
if (!response.IsSuccessStatusCode)
{
//throw new InvalidUriException("Some error with details.");
Console.WriteLine(response);
}
Console.WriteLine("Printing DEV Pool Response\n");
}
#endregion
//return null;
}
}
}
PostAsXmlAsync will try to serialize the object passed to it. So you have a string that contains XML and then try to post the string as XML(Double serialization).
Use StringContent, giving it the XML string value and set the content type to appropriate media type, then post it. i.e. client.PostAsync(url, content)
using (var client = new System.Net.Http.HttpClient()) {
var url = "http://server:8100/api/SoftwareProductBuild";
var content = new StringContent(xmlcontent, Encoding.UTF8, "application/xml");
var response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode) {
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Printing DEV Pool Response\n");
Console.WriteLine(responseBody);
} else {
Console.WriteLine(string.Format("Bad Response {0} \n", response.StatusCode.ToString()));
}
}

Test and use chat bot without emulator

It may seems very basic question but any guidance is appreciated .Where can i start to learn?.
I have used bot framework and made some code that gives total number of cities in particular country .I integrated and used LUIS .All went good but now to test,i use bot emulator of microsoft.
In real time ,i want to use this chat application on my asp.net application .How can i use this code in Asp.net and test without bot emulator.
Working Code(in case it may help someone) -
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using Microsoft.Bot.Connector;
using Newtonsoft.Json;
namespace YahooBot
{
[BotAuthentication]
public class MessagesController : ApiController
{
/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
string StockRateString;
LUIS StLUIS = await GetEntityFromLUIS(activity.Text);
if (StLUIS.intents.Count() > 0)
{
switch (StLUIS.intents[0].intent)
{
case "StockPrice":
StockRateString = await GetStock(StLUIS.entities[0].entity);
break;
case "StockPrice2":
StockRateString = await GetStock(StLUIS.entities[0].entity);
break;
case "Getcity":
StockRateString = await GetCityDetails(StLUIS.entities[0].entity);
break;
default:
StockRateString = "Sorry, I am not getting you...";
break;
}
}
else
{
StockRateString = "Sorry, I am not getting you...";
}
Activity reply = activity.CreateReply(StockRateString);
await connector.Conversations.ReplyToActivityAsync(reply);
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
private async Task<string> GetStock(string StockSymbol)
{
double? dblStockValue = await YahooBot.GetStockRateAsync(StockSymbol);
if(dblStockValue==null)
{
return string.Format("This \"{0}\" is not an valid stock symbol", StockSymbol);
}
else
{
return string.Format("Stock Price of {0} is {1}", StockSymbol, dblStockValue);
}
}
private async Task<string> GetCityDetails(string citychar)
{
string dblcityValue = await YahooBot.GetCityAsync(citychar);
if (dblcityValue == "")
{
return string.Format("This \"{0}\" is not an valid city ", citychar);
}
else
{
return string.Format("number of cities beginning with {0} is {1}", citychar, dblcityValue);
}
}
private static async Task<LUIS> GetEntityFromLUIS(string Query)
{
Query = Uri.EscapeDataString(Query);
LUIS Data = new LUIS();
using (HttpClient client = new HttpClient())
{
string RequestURI = "https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/f2a85791-c9fe-44f8-b23c-2580581dc383?subscription-key=8b4566ea897c4c87960995755aa8881d&verbose=true&timezoneOffset=0&q=" + Query;
HttpResponseMessage msg = await client.GetAsync(RequestURI);
if (msg.IsSuccessStatusCode)
{
var JsonDataResponse = await msg.Content.ReadAsStringAsync();
Data = JsonConvert.DeserializeObject<LUIS>(JsonDataResponse);
}
}
return Data;
}
private Activity HandleSystemMessage(Activity message)
{
if (message.Type == ActivityTypes.DeleteUserData)
{
// Implement user deletion here
// If we handle user deletion, return a real message
}
else if (message.Type == ActivityTypes.ConversationUpdate)
{
// Handle conversation state changes, like members being added and removed
// Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
// Not available in all channels
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
// Handle add/remove from contact lists
// Activity.From + Activity.Action represent what happened
}
else if (message.Type == ActivityTypes.Typing)
{
// Handle knowing tha the user is typing
}
else if (message.Type == ActivityTypes.Ping)
{
}
return null;
}
}
}
A few steps must be followed:
Publish your bot on Azure (can be done from Visual Studio directly), see documentation
Register your bot on dev.botframework.com (see documentation)
Integrate the chat in your Asp.net site, for example using iFrame: see the tutorial on the documentation . There are also other possibilities described here. An important note is that you should use a token instead of secret in the iframe src, see details in the documentation provided before (option 1 vs option 2)
In a nutshell: everything you need is on the official documentation, in the How-to guides

Resources