I am trying to host a webserver with WPF on the local wifi network and expose a webservice that another device (in my case, an Android) can call while connected to the same wifi network. I have created an inbound rule on the firewall for the port I am using. The webservice call only goes through when the windows app is launched using "Run as Administrator"
Is there a way I can do the same without Admin privileges?
Here is my code -
public class SelfHost
{
WebServiceHost Host;
public void HostServer()
{
var hostIPadd = Util.GetLocalHostIP(); //This returns something like "http://192.168.1.2"
Values.SERVER_PORT_VALUE = "55000";
var uri = new Uri(hostIPadd + ":" + Values.SERVER_PORT_VALUE);
Host = new WebServiceHost(new Service{...}, uri);
//Start host
ServiceEndpoint ep = Host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
Host.Open();
}
}
public partial class MyWindow : Window
{
public MyWindow()
{
InitializeComponent();
StartHost();
}
private void StartHost()
{
var host = new SelfHost();
var thServer = new System.Threading.Thread(host.HostServer);
thServer.IsBackground = true;
thServer.Start();
}
}
I have created an inbound rule in the firewall with these properties
Protocol type - TCP
Local port - Specific Ports - 55000
Profiles - Public
Action - "Allow the connection"
Programs - "All programs that meet the specified conditions"
I don't quite know why the firewall ignores this exception if the app is not running in Admin. The WebServiceHost object runs fine even if it is not in Admin mode, no errors.
But the webservice call never reaches the server and the request times out.
nothing to do with the firewall, you can't open an http link in a wpf app - for security reasons
see that
Related
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());
// ...
}
I'm trying to communicate with a modbus device in my network at ip 192.168.1.76. My host computer address is 192.168.1.132. I'm not able to connect to or listen to device ip.
basically i'm using NModbus4 library. I've created a ModbusTCPSlave and attached the tcp listener to it. then i assigned ModbusSlaveRequestReceived event to that slave. but it gives nothing in return when i try to change register values directly from Modscan software.
Main()
{
var masterEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.132"), 502);
var listener = new TcpListener(IPAddress.Any, 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, new TcpListener(masterEndpoint), 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();
}
private static void Modbus_Request_Event(object sender, Modbus.Device.ModbusSlaveRequestEventArgs e)
{
//disassemble packet from master
byte fc = e.Message.FunctionCode;
byte[] data = e.Message.MessageFrame;
byte[] byteStartAddress = new byte[] { data[3], data[2] };
byte[] byteNum = new byte[] { data[5], data[4] };
Int16 StartAddress = BitConverter.ToInt16(byteStartAddress, 0);
Int16 NumOfPoint = BitConverter.ToInt16(byteNum, 0);
Console.WriteLine(fc.ToString() + "," + StartAddress.ToString() + "," + NumOfPoint.ToString());
}
I expect to get function code, start address and number of points in console application when any register value is changed
I copied your code. Changed the IP address to my "server" and it worked.
So, the issue you are having is either in the setup of your "server" or in the PLC program.
I thought that I had to do some port forwarding on my router. I did not. It did not make a difference.
Server setup:
Your "server"'s IP address needs to be static. Whether your 'server' is your development system or not. And don't forget when you deploy... Server's IP address has to be static as well (not that it wouldn't be...just saying)
Add an inbound Firewall rule to allow connections to the port, in this case 502, otherwise you'll have to allow access every time you launch/start a test.
PLC program
I am using Click PLC's by Koyo. Not sure if this is the rule for all PLC's or not; but, we had to add a line of code to "write" the values we wanted to pick up off the TCP stream. Without the write, the PLC was not sending out a request to join the TcpListener.
Last:
The code to start your listener only needs to be this:
var listener = new TcpListener(IPAddress.Parse("192.168.1.244"), 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, listener, 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();
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.
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.
As mentioned in this article, in .net it's possible to bind a web service to all ip addresses using the "address" 0. However, this doesn't seem to work with mono (version 2.10.8.1).
Here is my example code:
Client:
string ipAddressOfTheService = "192.168.0.23";
EndpointAddress address = new EndpointAddress(string.Format("net.tcp://{0}:8081/myService", ipAddressOfTheService));
NetTcpBinding binding = new NetTcpBinding();
ServiceProxy proxy = new ServiceProxy(binding, address);
if(proxy.CheckConnection())
{
MessageBox.Show("Service is available");
}
else
{
MessageBox.Show("Service is not available");
}
ServiceProxy:
public class ServiceProxy : ClientBase<IMyService>, IMyService
{
public ServiceProxy(Binding binding, EndpointAddress address)
: base(binding, address)
{
}
public bool CheckConnection()
{
bool isConnected = false;
try
{
isConnected = Channel.CheckConnection();
}
catch (Exception)
{
}
return isConnected;
}
}
IMyService:
[ServiceContract]
public interface IMyService
{
[OperationContract]
bool CheckConnection();
}
MyService:
class MyService : IMyService
{
public bool CheckConnection()
{
Console.WriteLine("Check requested!");
return true;
}
}
ServiceHost:
class MyServiceHost
{
static void Main(string[] args)
{
Uri baseAddress = new Uri(string.Format("net.tcp://0:8081/myService");
using (ServiceHost host = new ServiceHost(typeof(MonitoringService), baseAddress))
{
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
host.AddServiceEndpoint(typeof(IMyService), binding, baseAddress);
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
host.Close();
}
}
}
If I run this (service and client) on a windows PC using .net all works fine.
On my Linux machine (Raspberry Pi, Debian soft-float) the service start without any problems, however the client cant connect.
If I host the service with its ip address instead of the "0" address everything works correct.
Is this just another bug in mono or do i have to bind to any other ip address instead of the 0?
If it's a bug in mono, are there any workarounds?
(By the way, I'm still searching for an workaround for the port sharing problems with mono/net.tcp, if anyone could help here -> net.tcp port sharing and mono)
Try using + or * instead of 0 to bind to all addresses.
Edit: Or try 0.0.0.0
Edit2: Looks like a bug in Mono. You can report it at https://bugzilla.xamarin.com/index.cgi
I had similar problem in Ubuntu Server 16.04 LTS & Mono JIT compiler version 5.0.1.1 (2017-02/5077205 Thu May 25 09:19:18 UTC 2017).
I got it resolved by adding the following line in /etc/hosts:
0.0.0.0 IP4Any
Then ofcourse, bind the service to IP4Any.
Tutorial to make WCF work through NetTcpBinding on Mono
To use IP address for WCF in Mono u need to write domain name in file /etc/hosts. Then u will be able to use IP address for connecting host and client.
How to write domain:
Open file /etc/hosts on host and add IP.address.of.host HostName