HoloLens 2 throwing NotSupportedException on System.Net.Http.WebRequestHandler - c#

I am trying to use Azure Cognitive Services (OCR) on the HoloLens 2. I'm using their .NET demo application with Nuget for Unity and importing all the necessary libraries. Everything compiles the way it should, but in runtime on the HoloLens, the code fails to execute the authentication part, saying there's a NotSupportedException. I've checked Internet/Client capabilities in Unity and I'm using the .NET 2.0 API (using the .NET 4.x doesn't help either). The scripting backend is IL2CPP because it's a UWP app. I'm using Unity 2020.3.13. I've gone through Azure's services and double-checked my endpoints and keys and those all work fine. It works through the Unity editor but fails on the HoloLens side. I've tried adding in a 'using' statement for System.Net.Http and double-checked the .dll is included in my editor folder, but I'm not sure how to make the HoloLens support this call. How do I get the device to access the API from within the code? I am new to networking and POST/GET calls.
Here's the part from UnityPlayer.log that details the exception:
NotSupportedException: System.Net.Http.WebRequestHandler::.ctor
at System.Net.Http.WebRequestHandler..ctor () [0x00000] in <00000000000000000000000000000000>:0
at Microsoft.Rest.ServiceClient`1[T].CreateRootHandler () [0x00000] in <00000000000000000000000000000000>:0
at Microsoft.Rest.ServiceClient`1[T]..ctor (System.Net.Http.DelegatingHandler[] handlers) [0x00000] in <00000000000000000000000000000000>:0
at Microsoft.Azure.CognitiveServices.Vision.ComputerVision.ComputerVisionClient..ctor (Microsoft.Rest.ServiceClientCredentials credentials, System.Net.Http.DelegatingHandler[] handlers) [0x00000] in <00000000000000000000000000000000>:0
at MainController.Start () [0x00000] in <00000000000000000000000000000000>:0
Here's my main program (I've shortened the unnecessary + working methods):
using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision;
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Linq;
using UnityEngine;
using UnityEngine.Windows.WebCam;
using System.Net.Http;
using TMPro;
public class MainController : MonoBehaviour
{
PhotoCapture photoCaptureObject = null;
public TextMeshPro debugText;
private ComputerVisionClient client;
private static string subscriptionKey = "<key>";
private static string endpoint = "<endpoint>";
private string photoFilePath;
// Start is called before the first frame update
void Start()
{
debugText.text = "In start" + "\n";
ComputerVisionClient client = Authenticate(endpoint, subscriptionKey);
// fails here, in the HL, doesn't even go into the if block
if (client == null)
{
debugText.text += "client is null" + "\n";
}
else
{
debugText.text += "client is not null" + "\n";
}
}
// Update is called once per frame
void Update()
{
}
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
public void CaptureImage()
{
// called from ImageCapture button in app
PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
}
void OnPhotoCaptureCreated(PhotoCapture captureObject)
{
...
// code for use in the HL to capture an image from what the user is seeing
}
void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
{
...
// save photo as .jpg and store on device
}
void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
{
...
// check success result and stop photo mode
}
void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
{
photoCaptureObject.Dispose();
photoCaptureObject = null;
ReadFileLocal(client, photoFilePath).Wait();
}
public async Task ReadFileLocal(ComputerVisionClient client, string localFile)
{
debugText.text += "reading file from local" + "\n";
string operationLocation = "";
string operationId = "";
if (!File.Exists(localFile))
{
debugText.text += "file does not exist in the path" + "\n";
}
else
{
debugText.text += "file exists, continuing" + "\n";
}
try
{
// Read text from URL
var textHeaders = await client.ReadInStreamAsync(File.OpenRead(localFile));
// After the request, get the operation location (operation ID)
operationLocation = textHeaders.OperationLocation;
Thread.Sleep(2000);
}
catch (Exception e)
{
debugText.text += "reading file failed" + "\n";
debugText.text += "Exception: " + e + "\n";
}
// <snippet_extract_response>
// Retrieve the URI where the recognized text will be stored from the Operation-Location header.
// We only need the ID and not the full URL
const int numberOfCharsInOperationId = 36;
operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
// Extract the text
ReadOperationResult results;
do
{
results = await client.GetReadResultAsync(System.Guid.Parse(operationId));
}
while ((results.Status == OperationStatusCodes.Running ||
results.Status == OperationStatusCodes.NotStarted));
// </snippet_extract_response>
// <snippet_extract_display>
// Display the found text.
var textUrlFileResults = results.AnalyzeResult.ReadResults;
foreach (ReadResult page in textUrlFileResults)
{
foreach (Line line in page.Lines)
{
debugText.text += line + "\n";
}
}
}
}

Related

How to use C# HTTPClient with Windows Credentials

I wrote a console app that will read a text file of links and test them using the HttpClient class to check if the links exist. It works wonderfully at home when tested against common links such as google.com.
When I run the app at under my work intranet, though, I get "Forbidden" errors when it checks links on our company Sharepoint and "Unauthorized" errors when it checks links on the Azure Website. My hope was that running it under my authorized Windows desktop PC would be all I needed for it to work, but nope.
Any hints one how to pass my Network credentials when I access the links with HttpClient?
EDIT: Added code to handle passed console argument (string of authentication cookies)
using System;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
namespace linkbot
{
class Program
{
private static async Task ProcessRepositories(string the_url, string the_cookies)
{ int the_index=the_url.IndexOf("/",9);
string base_string=the_url;
string the_rest="/";
if (the_index>=0)
{
base_string=the_url.Substring(0,the_index);
the_rest=the_url.Substring(the_index);
}
try {
var baseAddress = new Uri(base_string);
using (var handler = new HttpClientHandler { UseCookies = false })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var message = new HttpRequestMessage(HttpMethod.Get, the_rest);
message.Headers.Add("Cookie", the_cookies);
var result = await client.SendAsync(message);
result.EnsureSuccessStatusCode();
}
Write("\n" + the_url + " - WORKED!");
}
catch(Exception e )
{
Write("\nFailed: " + the_url + "||||||" +e.ToString() );
//throw e;
}
}
static async Task Main(string[] args)
{
if (args.Length<2){
Console.Write("\n###################\nLinkChecker by Sean J. Miller 2022\n\nusage:\n linkchecker.exe <linkfile> <cookies>\nwhere <linkfile> contains a text file of fully specified links (URLs) with one link per line. Example, https://www.google.com\n\nAn output file is generated titled brokenlinks.txt in the same directory where LinkChecker was launched. <cookies> should be a string such as \"cookie1=value1;cookie2=value2;cookie3=value3;\"\n###################\n\n\n");
return;
}
System.IO.File.Delete("brokenlinks.txt");
System.IO.File.WriteAllText("brokenlinks.txt", "Last Check Started " + (DateTime.Now).ToString());
int counter=0;
int total_lines=TotalLines(#args[0]);
Console.Write("Started " + (DateTime.Now).ToString() + "\n");
foreach (string line in System.IO.File.ReadLines(#args[0]))
{
Console.Write("Processing Link " + (++counter) + "/" + total_lines + "\n");
await ProcessRepositories(line, args[1]);
}
Console.Write("Finished " + (DateTime.Now).ToString() + "\n");
Write("\n");
}
static void Write(string the_text)
{
//Console.Write(the_text);
try
{
System.IO.File.AppendAllText("brokenlinks.txt", the_text);
}
catch (Exception ex)
{
throw ex;
}
}
static int TotalLines(string filePath)
{
using (StreamReader r = new StreamReader(filePath))
{
int i = 0;
while (r.ReadLine() != null) { i++; }
return i;
}
}
}
}
You want to set UseDefaultCredentials to true to use the current logged-on user credentials in your request. You can do that by instantiating your HttpClient like so:
private static readonly HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });

How can I connect my Unity android app to a 000webhost database?

I'm making a Unity Android app that displays info from a database.
For that I used 000WebHost to make a website and a sql server. When I test the app with Unity in my computer, it works fine, a bit of loading time required, but it works perfectly.
But, when I build the apk and test it on my phone, it doesn't work. It gets stuck in the "loading text" screen I made and never loads the text from the database.
I have a log error in Unity that activates when the connection fails, and I suppose the same is happening here.
Is there a way to solve it or is it because i'm a free user?
Here are the codes:
WebTextLoader.cs (Unity/Displays text from the database)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class WebTextLoader : MonoBehaviour
{
[Serializable]
public class PlaceInfo
{
public string Titulo = "";
public string Texto = "";
}
public string URL; //example: https://arguidetest.000webhostapp.com/pruebaMedieval.php
public Text TituloUI;
public Text TextoUI;
public PlaceInfo placeInfo;
public void Start()
{
if (Debug.isDebugBuild)
{
StartCoroutine(GetRequest(URL));
}
}
IEnumerator GetRequest(string uri)
{
using (UnityWebRequest webRequest = UnityWebRequest.Get(uri))
{
// Request and wait for the desired page.
yield return webRequest.SendWebRequest();
string jsonForm = uri;
if (webRequest.isNetworkError)
{
Debug.Log("Error loading");
}
else
{
try
{
placeInfo = JsonUtility.FromJson<PlaceInfo>(webRequest.downloadHandler.text);
TituloUI.text = placeInfo.Titulo;
TextoUI.text = placeInfo.Texto;
}
catch
{
Debug.Log("Error in connection");
}
}
}
}
}
pruebaMedieval.php (000webhost / turns an array of title and text into a JSon)
<?php
$server = ***;
$usuario = ***;
$pass = ***;
$database= ***;
$mysqli = new mysqli($server, $usuario, $pass, $database);
$query = $mysqli -> query("SELECT * FROM INFORMACION_EVENTOS where id = 1");
while ($valores = mysqli_fetch_array($query)) {
$titulo = $valores["titulo"];
$info = $valores["informacion"];
$array = array(
"Titulo" => $titulo,
"Texto" => $info
);
}
$result = json_encode($array);
echo $result;
?>
Also, in Unity player settings I have the internet connection as Require.
Sorry for the wall of text

Face Recognition with Unity and SDK Watson

I would like to do facial recognition with the feed of the camera of my computer with Unity and SDK Watson. I looked for some tutorials and demos in the internet and I think finally get it. This is one of my first projects in Unity so I would be so grateful if someone could help me to correct two errors I cannot fix.
I use this code for camera render and capture the image:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CameraRender : MonoBehaviour {
public Image overlay;
public FaceDetector fd;
// Use this for initialization
void Start () {
WebCamTexture backCam = new WebCamTexture();
backCam.Play();
overlay.material.mainTexture = backCam;
}
public void CaptureImage()
{
ScreenCapture.CaptureScreenshot(Application.persistentDataPath + "/screenshot.png");
fd.DetectFaces(Application.persistentDataPath + "/screenshot.png");
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
CaptureImage();
}
}
}
And this other one for face detection:
using IBM.Watson.DeveloperCloud.Connection;
using IBM.Watson.DeveloperCloud.Logging;
using IBM.Watson.DeveloperCloud.Services.VisualRecognition.v3;
using IBM.Watson.DeveloperCloud.Utilities;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FaceDetector : MonoBehaviour {
public Text dataOutput;
private VisualRecognition _visualRecognition;
// Use this for initialization
void Start ()
{
Credentials credentials = new Credentials(apiKey: "key", url: "url");
_visualRecognition = new ExampleVisualRecognition(credentials)
{
VersionDate = "2016-05-20"
};
}
public void DetectFaces(string path)
{
// Classify using image url
//if (!_visualRecognition.DetectFaces("<image-url>", OnDetectFaces, OnFail))
// Log.Debug("ExampleVisualRecognition.DetectFaces()", "Detect faces failed!");
// Classify using image path
if (!_visualRecognition.DetectFaces(OnDetectFaces, OnFail, path)) {
Log.Debug("ExampleVisualRecognition.DetectFaces()", "Detect faces failed!");
} else
{
Debug.Log("Calling Watson");
dataOutput.text = "";
}
}
private void OnDetectFaces(DetectedFaces multipleImages, Dictionary<string, object> customData)
{
var data = multipleImages.images[0].faces[0]; //assume 1
dataOutput.text = "Age : " + data.age.min + "-" + data.age.max + " PROBABILITY: " + data.age.score + "\n" + "Gender" + data.gender.gender + " PROBABILITY: " + data.age.score + "\n";
Log.Debug("ExampleVisualRecognition.OnDetectFaces(): Detect faces result: {0}", customData["json"].ToString());
}
private void OnFail(RESTConnector.Error error, Dictionary<string,object> customData)
{
Debug.LogError("ExampleVisualRecognition.OnFail(): Error received: " + error.ToString());
}
// Update is called once per frame
void Update () {
}
}
But I cannot fix this two errors:
NotImplementedException: The requested feature is not implemented. IBM.Watson.DeveloperCloud.Services.VisualRecognition.v3.VisualRecognition.op_Implicit (.ExampleVisualRecognition v) (at Assets/Watson/Scripts/Services/VisualRecognition/v3/VisualRecognition.cs:1444)
FaceDetector.Start () (at Assets/FaceDetector.cs:21)
NullReferenceException: Object reference not set to an instance of an object
FaceDetector.DetectFaces (System.String path) (at Assets/FaceDetector.cs:35)
CameraRender.CaptureImage () (at Assets/CameraRender.cs:20)
CameraRender.Update () (at Assets/CameraRender.cs:27)
Could someone bring some help? Thank you all.
You are instantiating ExampleVisualRecognition when you should be instantiating VisualRecognition. Please see this gist.
private IEnumerator CreateService()
{
// Create tokenOptions
TokenOptions visualRecognitionTokenOptions = new TokenOptions()
{
IamApiKey = visualRecognitionApiKey
};
// Create credentials
Credentials visualRecognitionCredentials = new Credentials(visualRecognitionTokenOptions, visualRecognitionServiceUrl);
// Wait for tokendata
while (!visualRecognitionCredentials.HasIamTokenData())
yield return null;
// Instantiate service
visualRecognition = new VisualRecognition(visualRecognitionCredentials);
// Set version date
visualRecognition.VersionDate = versionDate;
// Classify
visualRecognition.DetectFaces(OnDetectFaces, OnFail, imagePath);
}
private void OnDetectFaces(DetectedFaces response, Dictionary<string, object> customData)
{
// Print response json to console
Log.Debug("ClassifyExample", "{0}", customData["json"].ToString());
// Print gender, age and confidence
Log.Debug("ClassifyExample", "gender: {0}, score: {1}, age: {2} - {3}, score: {4}", response.images[0].faces[0].gender.gender, response.images[0].faces[0].gender.score, response.images[0].faces[0].age.min, response.images[0].faces[0].age.max, response.images[0].faces[0].age.score);
}
// Fail callback
private void OnFail(RESTConnector.Error error, Dictionary<string, object> customData)
{
Log.Debug("ClassifyExample", "Failed to classify");
}
}

How can i create a private message from telegram bot?

I'm connecting to telegram bot with webhook and i wanted to respond in private chat through telegram but if i send UID it doesn't send any message to the user from the bot.
this is what i did.
I created a Web API Project with .net framework to connect to webhook with telegram bot.
As a user, i wrote a command that will return some list of objects.
From the WebAPI i got the command and processed correctly
on sending response back i passed this {"method":"sendMessage","chat_id":"[user's UID who sent the command]", "text":"[returning list converted as string]", "reply_to_message_id":"[message id for the command]"}
This is the actual code that i'm sending
return new TelegramResponseModel
{ method = "sendMessage", chat_id = newUpdate.message.chat.id.ToString(),
text = text, reply_to_message_id = newUpdate.message.message_id };
on telegram nothing happens!!
You can use Nuget package library for implementing integration with Telegram called Telegram.Bot. Also there is few examples how you can use this library.
For example this short program shows how you can use WebHook's
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.Owin.Hosting;
using Owin;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using File = System.IO.File;
namespace Telegram.Bot.Examples.WebHook
{
public static class Bot
{
public static readonly TelegramBotClient Api = new TelegramBotClient("Your API Key");
}
public static class Program
{
public static void Main(string[] args)
{
// Endpoint must be configured with netsh:
// netsh http add urlacl url=https://+:8443/ user=<username>
// netsh http add sslcert ipport=0.0.0.0:8443 certhash=<cert thumbprint> appid=<random guid>
using (WebApp.Start<Startup>("https://+:8443"))
{
// Register WebHook
// You should replace {YourHostname} with your Internet accessible hosname
Bot.Api.SetWebhookAsync("https://{YourHostname}:8443/WebHook").Wait();
Console.WriteLine("Server Started");
// Stop Server after <Enter>
Console.ReadLine();
// Unregister WebHook
Bot.Api.DeleteWebhookAsync().Wait();
}
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
var configuration = new HttpConfiguration();
configuration.Routes.MapHttpRoute("WebHook", "{controller}");
app.UseWebApi(configuration);
}
}
public class WebHookController : ApiController
{
public async Task<IHttpActionResult> Post(Update update)
{
var message = update.Message;
Console.WriteLine("Received Message from {0}", message.Chat.Id);
if (message.Type == MessageType.Text)
{
// Echo each Message
await Bot.Api.SendTextMessageAsync(message.Chat.Id, message.Text);
}
else if (message.Type == MessageType.Photo)
{
// Download Photo
var file = await Bot.Api.GetFileAsync(message.Photo.LastOrDefault()?.FileId);
var filename = file.FileId + "." + file.FilePath.Split('.').Last();
using (var saveImageStream = File.Open(filename, FileMode.Create))
{
await Bot.Api.DownloadFileAsync(file.FilePath, saveImageStream);
}
await Bot.Api.SendTextMessageAsync(message.Chat.Id, "Thx for the Pics");
}
return Ok();
}
}
}
here you have a functional code on php:
<?php
$token = 'yout_boot_tocken';
$website = 'https://api.telegram.org/bot'.$token;
$input = file_get_contents('php://input');
$update = json_decode($input, TRUE);
$chatId = $update['message']['chat']['id'];
$message = $update['message']['text'];
$messageCode = strtoupper($message);
switch($messageCode) {
case 'hello':
$response = 'Hello my friend... how are you?';
sendMessage($chatId, $response);
break;
case 'address':
$response = 'Your Addres is Rosent wallet 245';
sendMessage($chatId, $response);
break;
case '/INFO':
$response = 'Hi, i am a Boot';
sendMessage($chatId, $response);
break;
case 'bye':
$response = 'it was a pleasure chat with you';
sendMessage($chatId, $response);
break;
default:
$response = 'I dont understand what do you mean with '.$messageCode;
sendMessage($chatId, $response);
break;
}
function sendMessage($chatId, $response) {
$url = $GLOBALS['website'].'/sendMessage?
chat_id='.$chatId.'&parse_mode=HTML&text='.urlencode($response);
file_get_contents($url);
}
?>

WWW/UnityWebRequest POST/GET request won't return the latest data from server/url

I am creating a HoloLens app using Unity which has to take data from a REST API and display it.
I am currently using WWW datatype to get the data and yield return statement in a coroutine that will be called from the Update() function. When I try to run the code, I get the latest data from the API but when someone pushes any new data onto the API, it does not automatically get the latest data in real time and I have to restart the app to see the latest data.
My Code:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
public class TextChange : MonoBehaviour {
// Use this for initialization
WWW get;
public static string getreq;
Text text;
bool continueRequest = false;
void Start()
{
StartCoroutine(WaitForRequest());
text = GetComponent<Text>();
}
// Update is called once per frame
void Update()
{
}
private IEnumerator WaitForRequest()
{
if (continueRequest)
yield break;
continueRequest = true;
float requestFrequencyInSec = 5f; //Update after every 5 seconds
WaitForSeconds waitTime = new WaitForSeconds(requestFrequencyInSec);
while (continueRequest)
{
string url = "API Link goes Here";
WWW get = new WWW(url);
yield return get;
getreq = get.text;
//check for errors
if (get.error == null)
{
string json = #getreq;
List<MyJSC> data = JsonConvert.DeserializeObject<List<MyJSC>>(json);
int l = data.Count;
text.text = "Data: " + data[l - 1].content;
}
else
{
Debug.Log("Error!-> " + get.error);
}
yield return waitTime; //Wait for requestFrequencyInSec time
}
}
void stopRequest()
{
continueRequest = false;
}
}
public class MyJSC
{
public string _id;
public string author;
public string content;
public string _v;
public string date;
}
This is happening because resources caching is enabled on the Server.
Three possible solutions I know about:
1.Disable resources caching on the server. Instructions are different for every web server. Usually done in .htaccess.
2.Make each request with unique timestamp. The time should in Unix format.
This method will not work on iOS. You are fine since this is for HoloLens.
For example, if your url is http://url.com/file.rar, append ?t=currentTime at the end. currentTime is the actual time in Unix Format.
Full example url: http://url.com/file.rar?t=1468475141
Code:
string getUTCTime()
{
System.Int32 unixTimestamp = (System.Int32)(System.DateTime.UtcNow.Subtract(new System.DateTime(1970, 1, 1))).TotalSeconds;
return unixTimestamp.ToString();
}
private IEnumerator WaitForRequest()
{
string url = "API Link goes Here" + "?t=" + getUTCTime();
WWW get = new WWW(url);
yield return get;
getreq = get.text;
//check for errors
if (get.error == null)
{
string json = #getreq;
List<MyJSC> data = JsonConvert.DeserializeObject<List<MyJSC>>(json);
int l = data.Count;
text.text = "Data: " + data[l - 1].content;
}
else
{
Debug.Log("Error!-> " + get.error);
}
}
3.Disable Cache on the client side by supplying and modifying the Cache-Control and Pragma headers in the request.
Set Cache-Control header to max-age=0, no-cache, no-store then set Pragma header to no-cache.
I suggest you do this with UnityWebRequest instead of the WWW class. First, Include using UnityEngine.Networking;.
Code:
IEnumerator WaitForRequest(string url)
{
UnityWebRequest www = UnityWebRequest.Get(url);
www.SetRequestHeader("Cache-Control", "max-age=0, no-cache, no-store");
www.SetRequestHeader("Pragma", "no-cache");
yield return www.Send();
if (www.isError)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Received " + www.downloadHandler.text);
}
}

Categories

Resources