Creating a web server in C# UWP - c#

I am writing a web server as a Universal Windows Platform app in C#. Here is my code so far:
sealed partial class App : Application
{
int port = 8000;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
StartServer();
}
private void StartServer()
{
StreamSocketListener listener = new StreamSocketListener();
listener.BindServiceNameAsync(port.ToString());
Debug.WriteLine("Bound to port: " + port.ToString());
listener.ConnectionReceived += async (s, e) =>
{
Debug.WriteLine("Got connection");
using (IInputStream input = e.Socket.InputStream)
{
var buffer = new Windows.Storage.Streams.Buffer(2);
await input.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.Partial);
}
using (IOutputStream output = e.Socket.OutputStream)
{
using (Stream response = output.AsStreamForWrite())
{
response.Write(Encoding.ASCII.GetBytes("Hello, World!"), 0, 1);
}
}
};
}
}
I tried connecting to the server using this address:
http://127.0.0.1:8000/C:/pathtohtmlfile/htmlfile.html
However, the connection times out. I am not sure if it is a problem with the C# code or with something else.

Raymond Zuo's solution really works. But the main thing not to forget are capabilities in Packages.appxmanifest. In order to run the server in Private networks one should add:
<Capability Name="privateNetworkClientServer" />
And in order to run the server in Public network:
<Capability Name="internetClientServer" />

If you want to host a server in uwp app, be sure these things:
your device which run this code (Device A) and device which your web browser run (Device B) must at a same LAN. And you cannot use the browser in Device A to access your service.
use WIFI to access your service.
your app must be at the state of running.
you should write a method to get ip address, but not 127.0.0.1:
public static string FindIPAddress()
{
List<string> ipAddresses = new List<string>();
var hostnames = NetworkInformation.GetHostNames();
foreach (var hn in hostnames)
{
//IanaInterfaceType == 71 => Wifi
//IanaInterfaceType == 6 => Ethernet (Emulator)
if (hn.IPInformation != null &&
(hn.IPInformation.NetworkAdapter.IanaInterfaceType == 71
|| hn.IPInformation.NetworkAdapter.IanaInterfaceType == 6))
{
string ipAddress = hn.DisplayName;
ipAddresses.Add(ipAddress);
}
}
if (ipAddresses.Count < 1)
{
return null;
}
else if (ipAddresses.Count == 1)
{
return ipAddresses[0];
}
else
{
return ipAddresses[ipAddresses.Count - 1];
}
}
It is possible to host a web service on phone/tablet.

It is possible to host a web service in a Window Universal App. I followed the example from http://www.dzhang.com/blog/2012/09/18/a-simple-in-process-http-server-for-windows-8-metro-apps , also followed the three first steps from Raymond Zuo's solution and finally I also put the firewall down. Unfortunately, I was not able to run on localhost even though I followed the answers from here Cannot connect to localhost in windows store application . I am currently doing java http requests to the Universal Platform App. Definitely, server and client seem to be required to run on different hosts.

Related

C# - Detect public ip adress change, VPN issue

With following code I am able to track public IP changes of my desktop application. This should be able to track if either the public IP changed or the user enabled a VPN to change his public IP. This code is run on application launch and used once again when a check is needed:
public class PublicIP
{
IPAddress last_ip=null;
DateTime timestamp_lastipchange;
public void UpdateIP()
{
List<string> hosts = new List<string>()
{
"https://api.ipify.org",
"https://ipinfo.io/ip",
"https://checkip.amazonaws.com",
"https://wtfismyip.com/text",
"http://icanhazip.com"
};
using(WebClient webclient = new WebClient())
{
foreach(string host in hosts)
{
//Download each string from hosts until an IP could be fetched
try{
var newip = IPAddress.Parse(webclient.DownloadString(service)); //Downloading the string
if(!newip.IsEqual(last_ip) && last_ip!=null) timestamp_lastipchange = DateTime.Now; //Check if the ip changed, if the last known ip does not exists skipp this step
last_ip = newip; //Save last known ip
return;
}
catch { }
}
}
}
}
This approach seems to work pretty well, however during UnitTesting some workflows do not fetch a new IP:
IP change by switching networks: change gets successfully detected
IP changed by provider: change gets successfully detected
VPN was enabled when the application was launched and is then turned off:
change gets successfully detected
VPN was disabled on application start and is turned on during runtime:
change does not get detected. Webclient.DownloadString() still returns the same IP as if the VPN was not enabled.
I am not really sure what is happening in workflow nr 4. Do I have to manually select the new network interface (VPN)? Or is this a caching problem on the client/server side?
WebClient is high-level and might using static pool behind-the-scene (and also deprecated). You might try using HttpClient instead, because HttpClient handle connection via its message handler, and the default one is not static, which means this should work:
using(var httpClient = new HttpClient())
{
var newip = IPAddress.Parse(webclient.GetStringAsync(service)
.ConfigureAwait(false).GetAwaiter().GetResult());
// ...
}

Access Docker API on Windows via Named Pipes

According to the Docker for Windows FAQ, " clients can connect to the Docker Engine through a named pipe: npipe:////./pipe/docker_engine"
I have been trying to connect to the API via named pipes to no avail:
public class DockerNamedPipeTest
{
private const string PIPE_PATH = "docker_engine";
public void Test()
{
using (NamedPipeClientStream pipeClient =
new NamedPipeClientStream(
".",
PIPE_PATH,
PipeDirection.InOut,
PipeOptions.WriteThrough,
TokenImpersonationLevel.Impersonation))
{
pipeClient.Connect(30);
Send(pipeClient);
Receive(pipeClient);
}
}
public void Send(NamedPipeClientStream pipeClient)
{
if (pipeClient.IsConnected)
{
byte[] buffer = Encoding.UTF8.GetBytes("GET /containers/json");
pipeClient.Write(buffer, 0, buffer.Length);
pipeClient.WaitForPipeDrain();
pipeClient.Flush();
}
}
public void Receive(NamedPipeClientStream pipeClient)
{
string result = string.Empty;
if (pipeClient.IsConnected && pipeClient.CanRead)
{
do
{
byte b = (byte)pipeClient.ReadByte(); // <-- Hangs here
result += Convert.ToChar(b).ToString();
}
while (!pipeClient.IsMessageComplete);
}
Console.WriteLine(result);
}
}
Can anyone tell me what I am doing wrong?
Microsoft's .NET client library for Docker supports named pipes, have you looked at that?
Here's an example:
using Docker.DotNet;
DockerClient client = new DockerClientConfiguration(new Uri("npipe://./pipe/docker_engine"))
.CreateClient();
It turns out that the answer can be found inside the source of the Docker.DotNet code, specifically in the DockerPipeStream.cs class in the method called CloseWrite():
(https://github.com/Microsoft/Docker.DotNet/blob/master/src/Docker.DotNet/DockerPipeStream.cs)
// The Docker daemon expects a write of zero bytes to signal the end of writes. Use native
// calls to achieve this since CoreCLR ignores a zero-byte write.
I adapted this method to my code and the code no longer hangs.
I now get a 400 Bad Request but at least now I know why the communication with the docker daemon was hanging. It would have been nice if the Docker for Windows FAQ had mentioned this nuance.

Unable to get attendance data of employees from biometric devices using cloud based windows services even if services is running correctly

This is small portion of window service code for fetching real-time attendance data from Biometric Device from cloud. Service is working but unable to get data from Device.This service is taking data from device and storing inside project folder making .log files.But when punched the card on device i get nothing.i am confusion on app.config files.There is local host(127.0.0.1:8080) as server in sdk of manufacturer which i got(but they are saying this is cloud based sdk).What should be server list in this case? Please help me.I am totally new in this WebSocketServer.
private void webSocketServer_NewMessageReceived(WebSocketSession session, string message) this method is used for registering new devices but this is not firing when i punched card to device.I am not pasting all codes here within this method.
using SuperWebSocket;
using SuperSocket.SocketBase;
public class WebSocketLoader
{
private static WebSocketServer webSocketServer;
public static Dictionary<string, string> _registeredDevices;
private WebSocketLoader(IWorkItem server)
{
var wsServer = server as WebSocketServer;
webSocketServer = wsServer;
}
public static WebSocketSession GetSessionByID(string sn)
{
if (_registeredDevices.ContainsKey(sn))
{
return webSocketServer.GetAppSessionByID(_registeredDevices[sn]);
}
else
return null;
}
public static void Setup(IWorkItem server)
{
var webSocketLoader = new WebSocketLoader(server);
webSocketLoader.AddNewMessageReceived();
webSocketLoader.AddNewSessionConnected();
webSocketLoader.AddSessionClosed();
_registeredDevices = new Dictionary<string, string>();
_registeredDevices.Clear();
}
public void AddNewMessageReceived()
{
webSocketServer.NewMessageReceived += new SessionHandler<WebSocketSession, string>(webSocketServer_NewMessageReceived);
}
public void AddNewSessionConnected()
{
webSocketServer.NewSessionConnected += new SessionHandler<WebSocketSession>(webSocketServer_NewSessionConnected);
}
private void webSocketServer_NewSessionConnected(WebSocketSession session)
{
Console.WriteLine(webSocketServer.GetAllSessions().Count());
LogHelper.Receive("NewConnected[" + session.RemoteEndPoint + "]");
}
private void webSocketServer_SessionClosed(WebSocketSession session, CloseReason reason)
{
LogHelper.Receive("Closed[" + session.RemoteEndPoint + "],Reason:" + reason);
}
private void webSocketServer_NewMessageReceived(WebSocketSession session, string message)
{
Console.WriteLine(webSocketServer.GetAllSessions().Count());
LogHelper.Receive("MessageReceived[" + session.RemoteEndPoint + "],Message:" + message);
}
}
App.config file contains following line
<RedisConfig WriteServerList="127.0.0.1:8080" ReadServerList="127.0.0.1:8080" MaxWritePoolSize="10000" MaxReadPoolSize="10000" DB="1" AutoStart="true" LocalCacheTime="180" RecordeLog="false">
127.0.0.1 meant for localhost. You need to update a valid IP and PORT in the biometric machine. Then if you use that IP & Port your code may work. Make sure the machine is connected in the same network.
In general, biometric machines can be not be associated with the public IP. Hence, TCP/IP communication with the machines installed in the remote location can not be done through cloud application.
For cloud communication from biometric machine, web api supported biometric machines can be used.

Unable to read from Serial Port using C# Mono (RaspberryPi)

I'm attempting to write a C# library which looks at all available USB serial ports on a Raspberry Pi so that I can enumerate, identify and communicate with a set of Arduinos connected to the Pi via a USB hub.
I am able to make this work on my windows machine (several Arduinos connected to my desktop computer) and have even been able to make it work on my Pi however, I am struggling to understand how to generalize the fix.
If I attempt to run the program by itself on the Pi, I am able to open the serial port and send data however, I cannot receive anything from the Arduinos: I get timeout exceptions. I understand that Mono's implementation of SerialPort is limited and I must use SerialPort.ReadByte() instead of Readline() and the data received events (my solution is based on code from HowToSystemIOPorts). My Serial port enumeration is using a method outlined in another stack exchange response here.
My timeout is currently set to 4 seconds, which is several orders of magnitude longer than I expect to receive the message.
After a lot of googling, I came across mention of using minicom to initialize the serial port here, which to my surprise allowed me to receive data from the Arduino. The biggest drawback is that I need to initialize the port using minicom and leave the process opening each time I boot the Pi. I also can't seem to figure out how to make this work with multiple Arduinos.
Here is what I have tried so far:
Updated the Pi firmware and software to their latest versions
Attempted to use both an Arduino MEGA 2560 R3 and Arduino UNO
Changed the owner of the tty* ports (ttyACM0 and ttyUSB0 in this case) to both my user and group
Successfully configured the port via minicom, left the process running and start the program and read/wrote data. A manual process which only seems to work for one Arduino at a time
Successfully run the program in Windows without fault
Verified the Arduinos are recognized by the Pi running "dmesg | grep tty"
Here is what I hope to solve:
Automatic setup/initialization of the Arduino serial ports. Whether through a shell script run before the main program or within Mono code so that the code below can run as intended.
Here is my connection code:
public bool StartArduinoComms()
{
string[] ports = GetPortNames();
foreach (string port in ports)
{
mLogger.LogMessage(ProsthesisCore.Utility.Logger.LoggerChannels.Arduino, string.Format("Found serial port {0}", port));
}
bool foundCorrectArduino = false;
var idPacket = new ArduinoMessageBase();
idPacket.ID = ArduinoMessageValues.kIdentifyValue;
string jsonOutput = Newtonsoft.Json.JsonConvert.SerializeObject(idPacket);
foreach (string port in ports)
{
SerialPort serialPort = new SerialPort(port, kArduinoCommsBaudRate);
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
//Only check unopened ports
if (!serialPort.IsOpen)
{
serialPort.Open();
//Disable telemtry just incase
var toggle = new { ID = ArduinoMessageValues.kTelemetryEnableValue, EN = false };
string disableTelem = Newtonsoft.Json.JsonConvert.SerializeObject(toggle);
serialPort.Write(disableTelem);
//Discard any built up data
serialPort.DiscardInBuffer();
serialPort.Write(jsonOutput);
serialPort.ReadTimeout = kIDTimeoutMilliseconds;
string response = string.Empty;
for (int i = 0; i < kNumRetries; ++i)
{
try
{
//This is guaranteed to timeout if not configured through minicom
response = ReadLine(serialPort);
break;
}
//Catch case where the serial port is unavailable. MOve to next port
catch (TimeoutException)
{
continue;
}
}
if (!string.IsNullOrEmpty(response))
{
//Perform response validation
}
else
{
//Got no response
}
if (!foundCorrectArduino)
{
serialPort.Close();
}
}
}
return foundCorrectArduino;
}
/// <summary>
/// From https://stackoverflow.com/questions/434494/serial-port-rs232-in-mono-for-multiple-platforms
/// </summary>
/// <returns></returns>
private static string[] GetPortNames()
{
int p = (int)Environment.OSVersion.Platform;
List<string> serial_ports = new List<string>();
// Are we on Unix?
if (p == 4 || p == 128 || p == 6)
{
string[] ttys = System.IO.Directory.GetFiles("/dev/", "tty*");
foreach (string dev in ttys)
{
//Arduino MEGAs show up as ttyACM due to their different USB<->RS232 chips
if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM"))
{
serial_ports.Add(dev);
}
}
}
else
{
serial_ports.AddRange(SerialPort.GetPortNames());
}
return serial_ports.ToArray();
}
Have a look at stty command. It will let you set/read teminal settings
http://linux.about.com/od/lna_guide/a/gdelna38t01.htm will give a rundown on it's use.
It would be easier to call out to than minicom, and the settings stay on the device.
I have done something like the same as you before.
I had to read and write data through USB Serial adapter, and didnt use minicom.
It may not be god code but i found that inorder to read the data I could create a new thread and have that check for data, my code include a lot of stuff but basicly i did this:
System.Threading.Thread newThread;
newThread = new System.Threading.Thread(this.check_get_data);
and the check_get_data method
public void check_get_data ()
{
byte tmpByte = 0;
while (m_objSerialPort.BytesToRead != 0) {
tmpByte = (byte)m_objSerialPort.ReadByte ();
DoSomethingWithByte(tmpByte);
Thread.Sleep(20);
}
}
this is currently running with two usbserials. dont know if it helps but hope you find your solution

How to Push data from C# to ZeroMQ and Pull from Node.JS or vice-versa?

Scenario:
I am trying to send a data (say String type) from C# сonsole application to Node.JS server through ZeroMQ.
Information:
Using clrzmq for c# and ZeroMQ libs for C# and Node.JS respectively
I am able to perform push-pull from Node.JS, also push - pull from C#.
So, one thing is confirmed that ZeroMQ - The Intelligent Transport Layer is installed on the machine (Windows 7 64-bit)
Issue:
I am not able to push data from C# Console app to Node.JS app (even tried vice-versa), both are on the same machine and on the same address i.e tcp://127.0.0.1:2222
Node.js code:
var zmq = require('zeromq.node');
var pull_socket = zmq.socket('pull');
pull_socket.connect('tcp://127.0.0.1:2222');
pull_socket.on('message', function (data) {
console.log('received data:\n');
console.log(data);
});
C# code:
namespace DataServiceEngine
{
class Program
{
static void Main(string[] args)
{
//clsApp App = new clsApp();
//App.appId = "001";
//App.name = "Back Office";
//Console.WriteLine("appId :" + App.appId + "\n");
//Console.WriteLine("name:" + App.name + "\n");
try
{
// ZMQ Context and client socket
using (var context = new Context(1))
{
using (Socket client = context.Socket(SocketType.PUSH))
{
client.Connect("tcp://127.0.0.1:2222");
string request = "Hello";
for (int requestNum = 0; requestNum < 10; requestNum++)
{
Console.WriteLine("Sending request {0}...", requestNum);
client.Send(request, Encoding.Unicode);
string reply = client.Recv(Encoding.Unicode);
Console.WriteLine("Received reply {0}: {1}", requestNum, reply);
}
}
}
}
catch (ZMQ.Exception exp)
{
Console.WriteLine(exp.Message);
}
}
}
}
Question: Can anyone tell me what may be the reason or where am I doing wrong?
I had the same issue (but I issued a communication Node.JS -> Node.JS). To solve the problem I used to do sendersocket.connect("tcp://"+host+":"+port); at the sender and receiversocket.bindSync("tcp://*:"+port); at the receiver.
Hope this fix your problem.

Categories

Resources