error extracting text from Azure Computer Vision API - c#

I am testing out the Azure Computer Vision API to try extract handwritten text from a local .jpg file. I am following the following example: https://learn.microsoft.com/en-us/azure/cognitive-services/computer-vision/quickstarts-sdk/csharp-sdk
Unfortunately when I run my code, I get an exception thrown: System.AggregateException: "this.Endpoint" cannot be null
My test code currently:
class Program
{
static string subscriptionKey = Environment.GetEnvironmentVariable("{SUBSCRIPTION-KEY}");
static string endpoint = Environment.GetEnvironmentVariable("https://{MY-ENDPOINT}.cognitiveservices.azure.com/");
private const string EXTRACT_TEXT_LOCAL_IMAGE = "vision3.jpg";
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
static void Main()
{
Console.WriteLine("Azure Cognitive Services Computer Vision - .NET quickstart example");
Console.WriteLine();
ComputerVisionClient client = Authenticate(endpoint, subscriptionKey);
//ExtractTextUrl(client, EXTRACT_TEXT_URL_IMAGE).Wait();
ExtractTextLocal(client, EXTRACT_TEXT_LOCAL_IMAGE).Wait();
}
public static async Task ExtractTextLocal(ComputerVisionClient client, string localImage)
{
Console.WriteLine("----------------------------------------------------------");
Console.WriteLine("EXTRACT TEXT - LOCAL IMAGE");
Console.WriteLine();
// Helps calucalte starting index to retrieve operation ID
const int numberOfCharsInOperationId = 36;
Console.WriteLine($"Extracting text from local image {Path.GetFileName(localImage)}...");
Console.WriteLine();
using (Stream imageStream = File.OpenRead(localImage))
{
// Read the text from the local image
BatchReadFileInStreamHeaders localFileTextHeaders = await client.BatchReadFileInStreamAsync(imageStream);
// Get the operation location (operation ID)
string operationLocation = localFileTextHeaders.OperationLocation;
// Retrieve the URI where the recognized text will be stored from the Operation-Location header.
string operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
// Extract text, wait for it to complete.
int i = 0;
int maxRetries = 10;
ReadOperationResult results;
do
{
results = await client.GetReadOperationResultAsync(operationId);
Console.WriteLine("Server status: {0}, waiting {1} seconds...", results.Status, i);
await Task.Delay(1000);
if (maxRetries == 9)
{
Console.WriteLine("Server timed out.");
}
}
while ((results.Status == TextOperationStatusCodes.Running ||
results.Status == TextOperationStatusCodes.NotStarted) && i++ < maxRetries);
// Display the found text.
Console.WriteLine();
var textRecognitionLocalFileResults = results.RecognitionResults;
foreach (TextRecognitionResult recResult in textRecognitionLocalFileResults)
{
foreach (Line line in recResult.Lines)
{
Console.WriteLine(line.Text);
}
}
Console.WriteLine();
}
}
}
edit:
From trying to debug, it looks like both subscriptionKey and endpoint variables are null from the beginning, even though I initialized them instantly. Why is this?
edit2:
When I hardcode the subscriptionKey and endpoint in Main():
ComputerVisionClient client = Authenticate("https://{END-POINT}.cognitiveservices.azure.com/", "{SUBSCRIPTION-KEY}");
It works fine. Can anybody tell me why my 2 static string variables do not work? As I do not want to hardcode these variables

Not sure what you want these two lines to accomplish -
static string subscriptionKey = Environment.GetEnvironmentVariable("{SUBSCRIPTION-KEY}");
static string endpoint = Environment.GetEnvironmentVariable("https://{MY-ENDPOINT}.cognitiveservices.azure.com/");
You either pick up environment variables or assign string literals, you're trying to... do a combination of the two?
Maybe read those secrets from appsettings.json instead.

This is for future people who are following the tutorials and stuck at the environment variables like me, to add new variables from visual studio go to your project properties >> Debug
then add new key and value as provided to you check here to see image explanation

Please try adding the below code before sending the request to API or at the starting of code execution.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;

Related

c# Using static variables in different projects

I have a solution with two projects which act as Server and Client respectively. The Client is a simple console application which sends data to the server. The server is a WPF application which receives the data and displays it in a datagrid. The MVVM approach is used here.
In the Server UI there are three textboxes in which the user can type in:
IP Address: ("127.0.0.1")
Port: (some port)
Delimeter: (some char like '#' for example)
The challenge for me in this one is that, whatever delimeter the user provides, it should be used in the client project, to be put in between the data which is to be sent. For example the client sends:
Name + Delimeter + Surname + Delimeter + Age
What i have tried:
I added a Utils class with static fields for IPAddress, port and delimeter like this:
public class Utils
{
public static string IP_ADDRESS = " ";
public static int PORT = 0;
public static char DELIMETER = '\0';
}
I then tried to change these values in my ViewModel where the respective properties which are bound to the UI are by assigning them:
private void storeData()
{
Utils.IP_ADDRESS = IP;
Utils.PORT = Port;
Utils.DELIMETER = Delimeter;
}
In the client program:
static void Main(string[] args)
{
Client client = new Client(Utils.IP_ADDRESS, Utils.PORT);
while (true)
{
client.SendData("some Name" + Utils.DELIMETER + "some Surname" + Utils.DELIMETER + some Age + Utils.DELIMETER + "something else");
Thread.Sleep(3000);
}
}
The problem here is that whenever i start a new Client instance the values from the util class are still the default ones (null).
Any help is appreciated.
Let's break down your problem:
The server can change ip or ports at will and the clients will somehow guess the new port and connect.
The server changes the delimiter at will and the clients adapt to the new delimiter.
Problem 1 is impossible. Information cannot magically get transferred to clients before the client connects to the server, and the client needs ip and ports to connect to the server. Whatever technique you use to transfer the ip and port to the client is a better communication channel than your client/server, so you don't need a client/server.
Problem 2 has been solved by WCF already. Use WCF and SOAP or REST (which is just HTML).
Here is a sample of what the code would look like for the clients to determine the delimiter before sending the main request:
class Server
{
private TcpListener _listener = new TcpListener(12312);
public void Start()
{
_listener.Start();
while (true)
{
var client = _listener.AcceptTcpClient();
var stream = client.GetStream();
var request = getRequest(stream);
if (request == "GetDelimiter")
{
SendResponse(Utils.DELIMITER, stream);
}
else
{
ProcessNameSurnameAge(request);
}
}
}
}
class Client
{
private TcpClient _client = new TcpClient();
public void DoTheThing()
{
_client.Connect("127.0.0.1", 12312);
var stream = _client.GetStream();
SendRequest("GetDelimiter", stream);
var delimiter = GetResponse(stream);
var newRequest = "some Name" + delimiter + "some Surname" + delimiter + "some Age" + delimiter + "something else";
SendRequest(newRequest);
}
}
Note that I skip over the encoding details of sending data over TCP because it seems like you've already got a handle on that.
I was able to solve this in a rather simple manner. Steps i used to solve are as follow:
In the server:
Created a text file in my solution.
When the server starts in my view model, i saved the properties ip, port and delimeter in a string array.
Next i used the IO File class to write the content of the array in the text file.
In the client:
First i read from the file.
Next i created the client instance and passed the ip and port as parameters to it's constructor.
Thank you D Stanley and Damian Galletini for your suggestions. Also thank you everybody else who tried to help.

Convert from console to string for return [duplicate]

What I really want to do is this
static string Main(string[] args)
but that doesn't work, your only options are void and int. So, What are some different ways to return the string that I need to return to the calling application?
Background
I need to write a console app that is specifically designed to be called from another application
Process.Start("MyCode.exe -Option 12aaa1234");
How can this calling program receive a string returned from that executable?
Research
From what I can tell, at this point in time my only option is to have the calling application attach a listening stream to the Standard Output stream of the process before starting it, and send the "return" using Console.Out.Write from inside my executable. Is this in fact the ONLY way to do this, or is there something different/better I can use?
Is this in fact the ONLY way to do this, or is there something different/better I can use?
This isn't the only way to do this, but it is the most common.
The other options would involve some form of interprocess communication, which is likely going to be significantly more development effort for a single string.
Note that, if the calling application is a .NET application, and you have control over both applications, it might make more sense to just write a class library instead of a console application. This would allow you to keep the code completely separate, but have the executable "call into" your library to get the string data.
Idea 1:
Using MyCode.exe, create an encrypted text file, which is saved in a specified path, which can then be decrypted in the current app and read.
In the app: "MyCode.exe", add this code:
public void ReturnToOther()
{
string ToReturn = "MyString";
System.IO.File.WriteAllText("Path", Encrypt(ToReturn));
}
public String Encrypt(string ToEncrypt)
{
string Encrypted = null
char[] Array = ToEncrypt.ToCharArray();
for (int i = 0; i < Array.Length; i++)
{
Encrypted += Convert.ToString(Convert.ToChar(Convert.ToInt32(Array[i]) + 15));
}
return Encrypted;
}
In the app you are making now:
public void GetString()
{
string STR = Decrypt(System.IO.File.ReadAllText("Path"));
Console.WriteLine("The string is: {0}", STR);
}
// If you want to keep this running before the file exists, use this:
/*
public void GetString()
{
for(int i = 0; i > -1; ++i)
{
if(System.IO.File.Exists("Path"))
{
string STR = Decrypt(System.IO.File.ReadAllText("Path"));
Console.WriteLine("The string is: {0}", STR);
break;
}
else
{
//Do something if you want
}
}
} */
public String Decrypt(string ToDecrypt)
{
string Decrypted = null
char[] Array = ToDecrypt.ToCharArray();
for (int i = 0; i < Array.Length; i++)
{
Decrypted += Convert.ToString(Convert.ToChar(Convert.ToInt32(Array[i]) - 15));
}
return Decrypted;
}
Idea 2:
Use TCP to upload the string to a port, e.g. LocalHost (127.0.0.1), and then receive the string on the app you are developing, using a TCP Listener
An article on TCP - http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
Hope this helps :)
EDIT:
Have a look at Sockets too: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx

Connecting to IRC via a proxy (.NET)

I wish to hide my IP when connecting to IRC via my .NET app. I currently use the IrcDotNet library but it doesn't seems to support proxies.
I've not had much experience with sockets, so I think modifying IrcDotNet would be easier than making my own IRC library. I looked around for socket libraries that handle proxy connections that I could implement in IrcDotNet. I found one called ProxySocket but it only supports BeginConnect not the new ASyncConnect method that IrcDotNet uses.
To break it down, in order of preference, here's what I'm looking for;
An IRC library that supports connecting via a HTTP/SOCKS proxy
A socket library that supports connecting via a HTTP/SOCKS proxy via
ASyncConnect
Example code on how to extend the socket class to support connecting
via a HTTP/SOCKS proxy via ASyncConnect
The version of IrcDotNet I am using is 0.4.1 found at https://launchpad.net/ircdotnet.
Update 1: Still no luck i'm afraid. Fredrik92's answer, while helpful, is not applicable to the version of IrcDotNet I am using (see above).
The IRC.NET library uses the standard Socket class in the System.Net.Sockets namespace.
So you could just modify the IrcDotNet/IrcClient.cs file in the IRC.NET source code (# http://ircdotnet.codeplex.com/SourceControl/latest).
You should add a constructor for proxy enabled IRC clients and call the default constructor.
Then all you should need to do is to modify the Connect methods in the same file (almost at the bottom). Each time they call this.client.BeginConnect(..) you have to add code for connecting to the Proxy (instead of the remote host)
Now you only have to create a new Connect-callback method that sends a HTTP CONNECT request to the proxy. Read the response from the HTTP Proxy and then everything else should work.
In this case I would write the HTTP request as raw ASCII bytes to the Proxy (instead of using the HttpWebRequest class), so that you have full control over the network stream you get in return...
You should add sth. like this to the IrcClient class:
private bool useProxy = false;
private IWebProxy proxy;
private IEnumerable<Uri> proxyRemoteUris;
public IrcClient(IWebProxy proxy)
: this()
{
this.useProxy = true;
this.proxy = proxy;
}
private void ProxyPerformHttpConnect(Uri remoteIrcUri)
{
string httpConnectRequest = string.Format("CONNECT {0}:{1} HTTP/1.1\r\nHost: {2}\r\n\r\n",
remoteIrcUri.Host, remoteIrcUri.Port, this.proxy.GetProxy(remoteIrcUri));
byte[] httpConnectData = Encoding.ASCII.GetBytes(httpConnectRequest);
this.stream.Write(httpConnectData, 0, httpConnectData.Length);
bool responseReady = false;
string responseText = string.Empty;
// Byte-by-byte reading required, because StringReader will read more than just the HTTP response header
do
{
int readByte = this.stream.ReadByte();
if (readByte < 0)
throw new WebException(message: null, status: WebExceptionStatus.ConnectionClosed);
char readChar = (char)(readByte); // Only works because HTTP Headers are ASCII encoded.
responseText += readChar;
responseReady = responseText.EndsWith("\r\n\r\n");
} while (!responseReady);
int statusStart = responseText.IndexOf(' ') + 1;
int reasonStart = responseText.IndexOf(' ', statusStart) + 1;
int reasonEnd = responseText.IndexOfAny(new char[] { '\r', '\n'});
HttpStatusCode responseStatus = (HttpStatusCode)(int.Parse(responseText.Substring(responseText.IndexOf(' ') + 1, length: 3)));
if (responseStatus != HttpStatusCode.OK)
{
string reasonText = responseText.Substring(reasonStart, reasonEnd - reasonStart);
if (string.IsNullOrWhiteSpace(reasonText))
reasonText = null;
throw new WebException(reasonText, WebExceptionStatus.ConnectFailure);
}
// Finished Response Header read...
}
private void ProxyConnectCallback(IAsyncResult ar)
{
try
{
this.client.EndConnect(ar);
this.stream = this.client.GetStream();
bool proxyTunnelEstablished = false;
WebException lastWebException = null;
foreach (Uri remoteIrcUri in this.proxyRemoteUris)
{
if (this.client.Connected == false)
{
// Re-establish connection with proxy...
Uri proxyUri = this.proxy.GetProxy(remoteIrcUri);
this.client.Connect(proxyUri.Host, proxyUri.Port);
}
try
{
ProxyPerformHttpConnect(remoteIrcUri);
proxyTunnelEstablished = true;
break;
}
catch (WebException webExcept)
{
lastWebException = webExcept;
}
}
if (!proxyTunnelEstablished)
{
OnConnectFailed(new IrcErrorEventArgs(lastWebException));
return;
}
this.writer = new StreamWriter(this.stream, Encoding.Default);
this.reader = new StreamReader(this.stream, Encoding.Default);
HandleClientConnected((IrcRegistrationInfo)ar.AsyncState);
this.readThread.Start();
this.writeThread.Start();
OnConnected(new EventArgs());
}
catch (Exception ex)
{
OnConnectFailed(new IrcErrorEventArgs(ex));
}
}
The code for the proxy handling in all Connect methods of the IrcClient class would thus look sth. like this:
// Code snippet to insert before the call to this.client.BeginConnect(...)
if (this.useProxy)
{
// Assign host and port variables for EndPoint objects:
// var host = remoteEP.Address;
// var port = remoteEP.Port;
this.proxyRemoteUris = new Uri[] { new Uri(string.Format("irc://{0}:{1}/", host, port)) };
// Replace the line above with the following line in the method where an array of IP addresses is specified as a parameter
// this.proxyRemoteUris = from ip in addresses select new Uri(string.Format("irc://{0}:{1}/", ip, port));
Uri proxyUri = this.proxy.GetProxy(this.proxyRemoteUris.First());
string proxyHost = proxyUri.Host;
int proxyPort = proxyUri.Port;
this.client.BeginConnect(proxyHost, proxyPort, ProxyConnectCallback, registrationInfo);
}
else
// Original this.client.BeginConnect(...) call here...

WebSockets in firefox

For implementing my websocket server in C# I'm using Alchemy framework. I'm stuck with this issue. In the method OnReceive when I try to deserialize json object, I get a FormatException:
"Incorrect format of the input string." (maybe it's different in english, but I'm getting a localized exception message and that's my translation :P). What is odd about this is that when I print out the context.DataFrame I get: 111872281.1341000479.1335108793.1335108793.1335108793.1; __ad which is a substring of the cookies sent by the browser: __gutp=entrystamp%3D1288455757%7Csid%3D65a51a83cbf86945d0fd994e15eb94f9%7Cstamp%3D1288456520%7Contime%3D155; __utma=111872281.1341000479.1335108793.1335108793.1335108793.1; __adtaily_ui=cupIiq90q9.
JS code:
// I'm really not doing anything more than this
var ws = new WebSocket("ws://localhost:8080");
C# code:
static void Main(string[] args) {
int port = 8080;
WebSocketServer wsServer = new WebSocketServer(port, IPAddress.Any) {
OnReceive = OnReceive,
OnSend = OnSend,
OnConnect = OnConnect,
OnConnected = OnConnected,
OnDisconnect = OnDisconnect,
TimeOut = new TimeSpan(0, 5, 0)
};
wsServer.Start();
Console.WriteLine("Server started listening on port: " + port + "...");
string command = string.Empty;
while (command != "exit") {
command = Console.ReadLine();
}
Console.WriteLine("Server stopped listening on port: " + port + "...");
wsServer.Stop();
Console.WriteLine("Server exits...");
}
public static void OnReceive(UserContext context) {
string json = "";
dynamic obj;
try {
json = context.DataFrame.ToString();
Console.WriteLine(json);
obj = JsonConvert.DeserializeObject(json);
} catch (Exception e) {
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
return;
}
}
On the C# side I'm using Newtonsoft.Json, though it's not a problem with this library...
EDIT:
One more thing - I browsed through the code in here: https://github.com/Olivine-Labs/Alchemy-Websockets-Example and found nothing - I mean, I'm doing everything the same way authors did in this tutorial...
EDIT:
I was testing the above code in Firefox v 17.0.1, and it didn't work, so I tested it under google chrome, and it works. So let me rephrase the question - what changes can be made in js, so that firefox would not send aforementioned string?
I ran into the same issue - simply replacing
var ws = new WebSocket("ws://localhost:8080");
with
var ws = new WebSocket("ws://127.0.0.1:8080");
fixed the issue for me.
In C# console app I connect the client to the server using :
var aClient = new WebSocketClient(#"ws://127.0.0.1:81/beef");
Your code above is connecting using
var ws = new WebSocket("ws://localhost:8080");
There could be one of two issues -
First is to see if WebSocketClient works instead.
To make sure your url is of the format ws://ur:port/context. This threw me off for a while.

p4.net cannot connect Perforce

I am using p4.net API to generate some reports from the metadata.
In one of the reports, I need to generate then number of the changes lines for each changeset report.
As a reporting tool, I am using MS SQL Reporting services 2008, and I have written a custom dll that uses p4.net API to calculate the number of changed lines. it works on the local without any problem. However, when I run the code on the server, it calculates let's say first %20 part then starts throwing Unable to connect to the Perforce Server!
Unable to connect to Perforce! exception.
I try same credentials on the local, it works.. I use commandline with same credentials on the server, it works.
Could anyone help me with that please, if encountered before?
Here is the code I use. If needed
public static class PerforceLib
{
public static P4Connection p4conn = null;
private static void CheckConn()
{
try
{
if (p4conn == null)
{
p4conn = new P4Connection();
p4conn.Port = "address";
p4conn.User = "user";
p4conn.Password = "pwd*";
p4conn.Connect();
p4conn.Login("pwd");
}
else if (p4conn != null)
{
if(!p4conn.IsValidConnection(true, false))
{
Log("Check CONN : Connection is not valid, reconnecting");
p4conn.Login("pwd*");
}
}
}
catch (Exception ex )
{
Log(ex.Message);
}
}
public static int DiffByChangeSetNumber(string ChangeSetNumber)
{
try
{
CheckConn();
P4Record set = p4conn.Run("describe", "-s",ChangeSetNumber)[0];
string[] files = set.ArrayFields["depotFile"].ToArray<string>();
string[] revs = set.ArrayFields["rev"].ToArray<string>();
string[] actions = set.ArrayFields["action"].ToArray<string>();
int totalChanges = 0;
List<P4File> lstFiles = new List<P4File>();
for (int i = 0; i < files.Count(); i++)
{
if (actions[i].ToString() == "edit")
lstFiles.Add(new P4File() { DepotFile = files[i].ToString(), Revision = revs[i].ToString(), Action = actions[i].ToString() });
}
foreach (var item in lstFiles)
{
if (item.Revision != "1")
{
string firstfile = string.Format("{0}#{1}", item.DepotFile, (int.Parse(item.Revision) - 1).ToString());
string secondfile = string.Format("{0}#{1}", item.DepotFile, item.Revision);
P4UnParsedRecordSet rec = p4conn.RunUnParsed("diff2", "-ds", firstfile, secondfile);
if (rec.Messages.Count() > 1)
{
totalChanges = PerforceUtil.GetDiffResults(rec.Messages[1].ToString(), item.DepotFile);
}
}
}
GC.SuppressFinalize(lstFiles);
Log(string.Format("{0} / {1}", ChangeSetNumber,totalChanges.ToString() + Environment.NewLine));
return totalChanges;
}
catch (Exception ex)
{
Log(ex.Message + Environment.NewLine);
return -1;
}
}
}
your help will be appreciated
Many thanks
I have solved this issue. we identified that the code is circling through the ephemeral port range in around two minutes. once it reaches the maximum ephemeral port, it was trying to use same port again. Due to each perforce command creates a new socket, available ports were running out after it processed about 1000 changesets.
I have set the ReservedPorts value of HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters default(1433,143) that gave me larger range of ephemeral port.
and also implemented singleton pattern for P4Conn which helped as I dont close the connection. I only check the validity of the connection, and login if the connection is not valid.
Please let me know if any of you guys needs any help regarding this

Categories

Resources