Programatically Invoking LUIS Outside the Message Controler - frameworks

I'm writting a bot application that uses a Prompt Dialog to interact with users.
The idea here is when a user selects a certain option a message should be sent to LUIS that will be processing the request via ML.
Thought about two ways to get it done.
1 - Invoke LUIS directly
2 - Simulate a user entry to make sure the message would pass by the Message Controller and finally the Root Dialog which will be making a LUIS call
Makes sense?
I've tried something like this but it didn't work.
public virtual async Task ChoiceReceivedAsync_MainMenuOption(IDialogContext context, IAwaitable<MainMenuOption> activity)
{
...
IMessageActivity message = Activity.CreateMessageActivity();
message.Text = "Como e a seguranca da escola?";
message.TextFormat = "plain";
message.Locale = "en-Us";
var luisAttributes = new LuisModelAttribute(BellaMain.GlobalVariable.LuisModelID, BellaMain.GlobalVariable.LuisSubscriptionKey);
var luisService = new LuisService(luisAttributes);
await Conversation.SendAsync(message, () => new Dialogs.RootDialog(luisService));
}
Any ideas?
Thanks

Trying to call LUIS by mocking up a new Activity to send to the bot is not recommended.
Instead you should call LUIS through a simple request using an HttpClient.
Here is a sample from the LUIS Endpoint API:
Copy-pasted example:
using System;
using System.Net.Http.Headers;
using System.Text;
using System.Net.Http;
using System.Web;
namespace CSHttpClientSample
{
static class Program
{
static void Main()
{
MakeRequest();
Console.WriteLine("Hit ENTER to exit...");
Console.ReadLine();
}
static async void MakeRequest()
{
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{subscription key}");
// Request parameters
queryString["timezoneOffset"] = "{number}";
queryString["verbose"] = "{boolean}";
queryString["spellCheck"] = "{boolean}";
queryString["staging"] = "{boolean}";
queryString["bing-spell-check-subscription-key"] = "{string}";
queryString["log"] = "{boolean}";
var uri = "https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/{appId}?q={q}&" + queryString;
var response = await client.GetAsync(uri);
}
}
}

Related

Why is this cost explorer code throwing this json error?

I'm trying to run the following code:
var awsCredentials = new BasicAWSCredentials("SomeSecret","SomeKey");
var client = new AmazonCostExplorerClient(awsCredentials, Amazon.RegionEndpoint.USEast1);
var requestObject = new GetCostAndUsageWithResourcesRequest();
requestObject.Granularity = "DAILY";
var range = new DateInterval();
range.Start = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd");
range.End = DateTime.Now.ToString("yyyy-MM-dd");
requestObject.TimePeriod = range;
GetCostAndUsageWithResourcesResponse costs = await client.GetCostAndUsageWithResourcesAsync(requestObject);
The routine seems to run then I get the error:
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles.
I'm not sure what I'm missing here to get the proper result.
Any thoughts are appreciated!
EDIT:
I got this working in case anyone needs it.
The issue was that I wasn't being smart with my code setup
The code above was being called in an async method and was incorrectly calling it in the consumer method.
Example:
Incorrect usage in consumer was:
public async Task<IActionResult> GetAwsCost()
{
var coster = new CostExplorerDash(_connectionInfo);
var res = coster.GetMonthlyCost();
return Ok(res);
}
Proper usage is:
public async Task<IActionResult> GetAwsCost()
{
var coster = new CostExplorerDash(_connectionInfo);
var res = coster.GetMonthlyCost(); //async method call
return Ok(res.Result);
}
The issue (I think) was just that I was trying to use an unfinished async task which caused a mess when .NET tried to do serialzation of the objects involved.

Dynamics 365 Plugin call External REST API - SSL/TSL could not create channel issue

I have a task to call the external REST API to get data from third party application.
In that, i have created a C# Console application for tried this and it is working fine and i can get the data from thirty party application via REST API.
The same code used to tried in Dynamics Custom workflow\Plugin, i have got a error below. Please give your valuable suggestion on this.
"System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel."
Note: The below options are tried but no luck.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AlwaysGoodCertificate);
ServicePointManager.Expect100Continue = true;
Thanks,
Vasanth
It is not clear how you are calling external API from D365 Plugin.
// Call external API
static async Task<bool> CallExternalAPI(Guid beziehungId)
{
bool status = false;
HttpClient apiClient = new HttpClient();
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string url = #"https://reqres.in/api/users?page=2";
HttpResponseMessage response = await apiClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
}
return status;
}
If your problem with SSL/TLS secure channel you can use WebClient.
// Could not create SSL/TLS secure channel.
// Use (SecurityProtocolType)3072
using (WebClient client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.UserAgent, "AvoidError");
ServicePointManager.Expect100Continue = true;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
htmlCode = client.DownloadString("MY LINK");
//passing the URL again to function from which to extract the content and compare from above content.
strNewCompanyCode = client.DownloadString("MY LINK");
}

Sending an async email without await from a .Net core web service

I have a webservice .Net core2 that has certain methods that send an email. I have it working fine using smtpclient.sendemailasync.
public async Task<bool> SendEmailAsync(MailMessage email)
{
try
{
if (string.IsNullOrWhiteSpace(emailFrom)) email.From = new MailAddress(emailFrom);
using (SmtpClient client = getSMTPClientInstance())
{
await client.SendMailAsync(email);
}
return true;
}
catch (Exception ex)
{
Log.Error(ex, "Error sending email in EmailService.SendEmailAsync");
return false;
}
}
The only issue is that some SMTP servers take a little too long to respond. I want to set up the email, queue it and return without waiting for the result.
Just using an unawaited async is out for 2 reasons;
It is not reliable to continue a method outside a request context in asp
I need access to the database context of my entity framework to write a log
I have to allow for external or internal SMTP (my client specifies), so a collection folder is not a possibility - at least not without a service that manages it.
How could I achieve this? Do I need to write a service that manages this? If so, how would I do that inside my .Net Core App, keeping in mind that the service also needs to access the EF context to write a log
UPDATE
There is plumbing available in .NetCore DI especially for this. Refer to my additional answer below. Use IServiceScopeFactory
You can call the RegisterAsyncTask method on the Page object. That will signal the ASP.NET runtime you want to make sure these are finished before terminating the request context:
Example:
public void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
}
public async Task LoadSomeData()
{
var clientcontacts = Client.DownloadStringTaskAsync("api/contacts");
var clienttemperature = Client.DownloadStringTaskAsync("api/temperature");
var clientlocation = Client.DownloadStringTaskAsync("api/location");
await Task.WhenAll(clientcontacts, clienttemperature, clientlocation);
var contacts = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Contact>>(await clientcontacts);
var location = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clientlocation);
var temperature = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clienttemperature);
listcontacts.DataSource = contacts;
listcontacts.DataBind();
Temparature.Text = temperature;
Location.Text = location;
}
https://www.hanselman.com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx
So, while I have marked an answer, there are a couple of options that are better solutions for my specific example. First is the option to use a library like hangfire to schedule tasks - although that is not technically an answer to the question.
The better solution in .net core is to use IServiceScopeFactory
With IServiceScopeFactory you can rescope a task so it doesnt go out of scope when the request is complete. I did the following directly in a controller (I later moved to using the hangfire approach, but this works). As you can see, the async task is fired off in a new unawaited thread while the controller code continues.
var task = Task.Run(async () =>
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<ApprovalService>();
await service.sendResponseEmailAsync(approvalInfo.ApprovalId, userID, approvalInfo.emailTo, approvalInfo.ccTo);
}
});

How to consume REST api in Xamarin.iOS?

I have made a REST API and I want to use it using my Xamarin.iOS application.
Basically I want to call the API from my Xamarin application by sending some arguments to one of my API's function.
I tried the resources available at Xamarin's official website, but I a newbie so I cannot understand how it was done.
The REST API is hosted locally by the network I am using. It is not hosted at a static IP.
Kindly guide me.
You don't really need a fancy plugin if you just want to hit Web Endpoints. I simply use the basic WebRequest API.
var request = WebRequest.CreateHttp(YOUR_URL_HERE);
request.Method = "GET";
request.ContentType = "application/JSON";
request.BeginGetResponse(ResponseComplete, request);
... and then your response method can be something along the lines of...
protected void ResponseComplete(IAsyncResult result)
{
try
{
var request = result.AsyncState as HttpWebRequest;
if (request != null)
{
Debug.WriteLine("Completed query: " + request.RequestUri);
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
Debug.WriteLine("Query Result: " + result);
}
}
}
}
... and if you need to post data you can add request.BeginGetRequestStream(PostData, request); before request.BeginGetResponse(ResponseComplete, request); and make your GetRequestStream handling method something along the lines of...
protected void PostData(IAsyncResult result)
{
var request = result.AsyncState as HttpWebRequest;
if (request != null)
{
using (var postStream = request.EndGetRequestStream(result))
{
var json = JsonConvert.SerializeObject(DATA_TO_POST);
Debug.WriteLine("Posting data: " + json);
var byteArray = Encoding.UTF8.GetBytes(json);
postStream.Write(byteArray, 0, byteArray.Length);
}
}
}
I would recommend Refit, you can install it as a NuGet package. Its pritty simple to use.
Refit allows us to define an interface that describes the API that we're calling, and the Refit framework handles making the call to the service and deserializing the return.
Have a look at this great blog post on how to set it up and other packages that might help you out. http://arteksoftware.com/resilient-network-services-with-xamarin/
I have used RestSharp before but Refit is alot easier to get running.

Possible to force the C# Facebook SDK to use HTTP instead of HTTPS?

I need to do some connectivity simulations to see that my code handles various connectivity errors to Facebook. I want to be able to simulate 500s, timeouts etc.
The easiest way to do that is to use Fiddler, but it seems to not be working with HTTPS (I get 403s when I try).
Is ther a way to force the SDK to work with HTTP instead of HTTPS for debugging purposes?
Facebook C# SDK supports your scenario for mocking the entire HttpWebRequest and HttpWebResponse. In fact we actually use that internally in our unit tests so that every single line of the code in Facebook C# SDK actually gets executed and the result is always the same. https://github.com/facebook-csharp-sdk/facebook-csharp-sdk/blob/v5/Source/Facebook.Tests/TestExtensions.cs For now you will need to check these tests in v5 branch as we haven't yet migrated those tests to v6.
For v5, you will need to override the protected CreateHttpWebRequest method in FacebookClient.
Here is an example for v5 when there is no internet connection. There are three hidden classes HttpWebRequestWrapper, HttpWebResponseWrapper and WebExceptionWrapper that you will need to make use of.
public static void NoInternetConnection(this Mock<Facebook.FacebookClient> facebookClient, out Mock<HttpWebRequestWrapper> mockRequest, out Mock<WebExceptionWrapper> mockWebException)
{
mockRequest = new Mock<HttpWebRequestWrapper>();
mockWebException = new Mock<WebExceptionWrapper>();
var mockAsyncResult = new Mock<IAsyncResult>();
var request = mockRequest.Object;
var webException = mockWebException.Object;
var asyncResult = mockAsyncResult.Object;
mockRequest.SetupProperty(r => r.Method);
mockRequest.SetupProperty(r => r.ContentType);
mockRequest.SetupProperty(r => r.ContentLength);
mockAsyncResult
.Setup(ar => ar.AsyncWaitHandle)
.Returns((ManualResetEvent)null);
mockWebException
.Setup(e => e.GetResponse())
.Returns<HttpWebResponseWrapper>(null);
mockRequest
.Setup(r => r.GetResponse())
.Throws(webException);
mockRequest
.Setup(r => r.EndGetResponse(It.IsAny<IAsyncResult>()))
.Throws(webException);
AsyncCallback callback = null;
mockRequest
.Setup(r => r.BeginGetResponse(It.IsAny<AsyncCallback>(), It.IsAny<object>()))
.Callback<AsyncCallback, object>((c, s) =>
{
callback = c;
})
.Returns(() =>
{
callback(asyncResult);
return asyncResult;
});
var mockRequestCopy = mockRequest;
var mockWebExceptionCopy = mockWebException;
facebookClient.Protected()
.Setup<HttpWebRequestWrapper>("CreateHttpWebRequest", ItExpr.IsAny<Uri>())
.Callback<Uri>(uri =>
{
mockRequestCopy.Setup(r => r.RequestUri).Returns(uri);
mockWebExceptionCopy.Setup(e => e.Message).Returns(string.Format("The remote name could not be resolved: '{0}'", uri.Host));
})
.Returns(request);
}
You can then write your tests as below.
[Fact]
public void SyncWhenThereIsNotInternetConnectionAndFiddlerIsNotOpen_ThrowsWebExceptionWrapper()
{
var mockFb = new Mock<FacebookClient> { CallBase = true };
Mock<HttpWebRequestWrapper> mockRequest;
Mock<WebExceptionWrapper> mockWebException;
mockFb.NoInternetConnection(out mockRequest, out mockWebException);
Exception exception = null;
try
{
var fb = mockFb.Object;
fb.Get(_parameters);
}
catch (Exception ex)
{
exception = ex;
}
mockFb.VerifyCreateHttpWebRequest(Times.Once());
mockRequest.VerifyGetResponse();
mockWebException.VerifyGetReponse();
Assert.IsAssignableFrom<WebExceptionWrapper>(exception);
}
In v6 we have made mocking the HttpWebRequest and HttpWebResponse much easier.
Create your custom HttpWebRequest and HttpWebResponse by inheriting HttpWebRequestWrapper and HttpWebReponseWrapper.
Then change the default http web request factory for Facebook C# SDK. Here is the sample of the default factory.
FacebookClient.SetDefaultHttpWebRequestFactory(uri => new HttpWebRequestWrapper((HttpWebRequest)WebRequest.Create(uri)));
If you want to change the HttpWebRequestFactor per FacebookClient instance then use the following code.
var fb = new FacebookClient();
fb.HttpWebRequestFactory = uri=> new MyHttpWebRequestWrapper(uri);
Note: HttpWebRequestWrapper, HttpWebResponseWrapper, WebExceptionWrapper, FacebookClient.SetDefaultHttpWebRequestFactory and FacebookClient.HttpWebRequestFactory has the attribute [EditorBrowsable(EditorBrowsableState.Never)] so you might not see it in the intellisense.
Things like no internet connection that you mention should actually be a part of facebook c# sdk tests and not your app unit tests. The sdk should guarantee that when there is not internet conenction it always throws WebExceptionWrapper and your app unit tests should actually be handling the WebExceptionWrapper exception and not mocking the entire httpwebrequest and httpwebresponse.
I'd suggest you introduce another level of abstraction to your code and code to that abstraction rather than the implementation. Eg.
public interface IFacebookClient {
IEnumerable<Friend> GetFriends();
}
public class HttpsClient : IFacebookClient {
public IEnumerable<Friend> GetFriends() {
// Make a call out to the Facebook API, as per usual
};
}
In your consuming code you'd do something like;
public class ConsumingCode {
private IFacebookClient _client;
public ConsumingCode(IFacebookClient client) {
_client = client;
foreach (Friend friend in _client.GetFriends()) {
// Do something with each Friend
}
}
}
If you're using an IoC container this can all get wired up for you automatically. MVVM frameworks like Caliburn.Micro tend to support this as well.
Then when it comes to unit testing (or manual testing) you can change the implementation of your interface;
public class Http403Client : IFacebookClient {
public IEnumerable<Friend> GetFriends() {
throw new HttpException(403, "Forbidden");
}
}
Obviously this is just a mock up example but I think it demonstrates the concept that you want to implement.