Which Communication technique is better for talking between two applications - c#

C#WinForms: There are a couple of ways for two applications to talk together, I am not very knowledgeable in this area but things like MSMQ and Named Pipes comes to my mind but not sure what is the best. So here is the scenario, what do you think is the best approach:
Let's say I write a windows service that backs up some files to somewhere on occasion.
User opens some my Application XYX and I want him to be notified that hey there is new backup file for you over there.
That's all. This was the scenario.

Use MSMQ as it is very simple to implement and you could play with objects. Producer and Consumer then can interact with each other very simply.These two applications(Producer, COnsumer) can be on the same machine, across a network, or even on different machines that aren't always connected. MSMQ is considered failsafe in that it will retry sending a message if the first transmission fails. This allows you to be very confident that your application messages will arrive at their destination.
More Details

We just used Named Pipes for a similar purpose on a recent project. Code turned out to be really simple. I can't claim credit for this particular code but here it is:
/// <summary>
/// This will attempt to open a service to listen for message requests.
/// If the service is already in use it means that another instance of this WPF application is running.
/// </summary>
/// <returns>false if the service is already in use by another WPF instance and cannot be opened; true if the service sucessfully opened</returns>
private bool TryOpeningTheMessageListener()
{
try
{
NetNamedPipeBinding b = new NetNamedPipeBinding();
sh = new ServiceHost(this);
sh.AddServiceEndpoint(typeof(IOpenForm), b, SERVICE_URI);
sh.Open();
return true;
}
catch (AddressAlreadyInUseException)
{
return false;
}
}
private void SendExistingInstanceOpenMessage(int formInstanceId, int formTemplateId, bool isReadOnly, DateTime generatedDate, string hash)
{
try
{
NetNamedPipeBinding b = new NetNamedPipeBinding();
var channel = ChannelFactory<IOpenForm>.CreateChannel(b, new EndpointAddress(SERVICE_URI));
channel.OpenForm(formInstanceId, formTemplateId, isReadOnly, generatedDate, hash);
(channel as IChannel).Close();
}
catch
{
MessageBox.Show("For some strange reason we couldnt talk to the open instance of the application");
}
}
In our OnStartup we just had
if (TryOpeningTheMessageListener())
{
OpenForm(formInstanceId, formTemplate, isReadOnly, generatedDate, hash);
}
else
{
SendExistingInstanceOpenMessage(formInstanceId, formTemplate, isReadOnly, generatedDate, hash);
Shutdown();
return;
}

There are many ways to achieve what you have asked;
As Damith said make an entry to database and read from it.
Make an entry in a file and read from it.
Use WCF - Windows Communication Foundation and set the configuration to use the MSMQ bindings. Read WCF & MSMQ article to get you started.

Related

TCPClient & Sockets failing to connect to the Server

I have a very strange problem with my connection to a server on a TCPListener/TCPClient basis. At some point during testing I am unable to connect to my server-application anymore, every try it times out. Netstats on both sides show, that my application listens on the right port, and the client is trying to connect to the right ip and port, but it does not advance further than "SYN_SENT". The server just displays "LISTENING" all the time. All I can do is restart my PC, which temporarily fixes this problem. But after some connections, it starts all over again.
Up to now I tested TCPClient and Sockets class to connect to the server but both show this behaviour, what is not surprising, as TCPClient is a wrapper around the Sockets Class afaik.
Firewall is checked on both sides, things like Remote Desktop work perfectly fine, and is not blocking the Connection of my Application. There are no connections left to close or something, already cheked everything I know (maybe not that much ;) )
So whats the problem?
Edit:
A Method that needs to connect to my Server:
public int GetSomeDataFromServer(string blargh)
{
int ret;
try
{
using(ConnectionTCPStream ctp = new ConnectionTCPStream())
{
if(ctp.EstSecConnWithServ())
{
ret = CKSHandler(ctp, blargh);
}
else
{ ret = (int)ErrFlags.ServerDeniedConnection; }
}
return ret;
}
catch(Exception)
{
InternalError = ErrFlags.ServerUnreachable;
return (int)ErrFlags.ServerUnreachable;
}
}
The Constructor of my Class that is dealing with the Connections:
public ConnectionTCPStream()
{
Client = new TcpClient("VeryImportantAdress", 49778); //it fails right here!
rsaCrypt = new RSACH() { RSAForeignPubKey = "An 8192-Bit long RSA Public key." };
AESPASS = AESThenHMAC.CreatePassword(200);
}
Sounds like you are using up all your connections or some other resource.
What do you see when you do a netstat -an ? Do you see a bunch of open ports?
There an Article Here that could possibly help you here
Some other resource may be killing you, might be worth having an SA fire up a resource monitor to check the health of the host when you run into this situation.
If there's no errors being thrown, it makes your life that much harder. The problem typically happens when you don't cleanly clean up your socket disconnects.
The answer is the firewall which changed its mind every now and then. I couldn't test that before because i had no access to it. Now i have changed settings while i had this blockade and it worked fine again. So the answer is: Always have access to the firewall and don't forget to check it.

Process launcher launching process inside of a windows service but the application window is not opening [duplicate]

I currently have a single application that needs to be started from a windows service that i am coding in .net 3.5. This application is currently running as the user who ran the service, in my case the SYSTEM user. If running as the SYSTEM user it does not show the application to the users desktop. Thoughts? advice?
//constructor
private Process ETCHNotify = new Process();
//StartService()
ETCHNotify.StartInfo.FileName = baseDir + "\\EtchNotify.exe";
ETCHNotify.StartInfo.UseShellExecute = false;
//BackgroundWorkerThread_DoWork()
if (!systemData.GetUserName().Equals(""))
{
// start ETCHNotify
try {
ETCHNotify.Start();
}
catch (Exception ex)
{
systemData.Run("ERR: Notify can't start: " + ex.Message);
}
}
I only execute the try/catch if the function i have written GetUserName() (which determines the username of the user running explorer.exe) is not null
again to reiterate: desired functionality is that this starts ETCHNotify in a state that allows it to interact with the currently logged in user as determined by GetUserName()
Collage of some post found around (this and this)
Note that as of Windows Vista, services are strictly forbidden from interacting directly with a user:
Important: Services cannot directly interact with a user as of Windows
Vista. Therefore, the techniques mentioned in the section titled Using
an Interactive Service should not be used in new code.
This "feature" is broken, and conventional wisdom dictates that you shouldn't have been relying on it anyway. Services are not meant to provide a UI or allow any type of direct user interaction. Microsoft has been cautioning that this feature be avoided since the early days of Windows NT because of the possible security risks.
There are some possible workarounds, however, if you absolutely must have this functionality. But I strongly urge you to consider its necessity carefully and explore alternative designs for your service.
Use WTSEnumerateSessions to find the right desktop, then CreateProcessAsUser to start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFO structure) is correct.
However, I would strongly recommend against doing this. In some environments, such as Terminal Server hosts with many active users, determining which desktop is the 'active' one isn't easy, and may not even be possible.
A more conventional approach would be to put a shortcut to a small client app for your service in the global startup group. This app will then launch along with every user session, and can be used start other apps (if so desired) without any juggling of user credentials, sessions and/or desktops.
Ultimately in order to solve this i took the advice of #marco and the posts he mentioned. I have created the service to be entirely independent of the tray application that interacts with the user. I did however install the Tray application via registry 'start up' methods with the service. The Service installer will now install the application which interacts with the user as well... This was the safest and most complete method.
thanks for your help everyone.
I wasn't going to answer this since you already answered it, (and it's oh, what? going on 2.5 years OLD now!?) But there are ALWAYS those people who are searching for this same topic, and reading the answers...
In order to get my service to Interact with the Desktop, no matter WHAT desktop, nor, how MANY desktops, nor if the service was even running on the SAME COMPUTER as the desktop app!! None of that matters with what I got here... I won't bore you with the details, I'll just give you the meat and potatoes, and you and let me know if you want to see more...
Ok. First thing I did was create an Advertisement Service. This is a thread that the service runs, opens up a UDP socket to listen for broadcasts on the network. Then, using the same piece of code, I shared it with the client app, but it calls up Advertise.CLIENT, rather than Advertise.SERVER... The CLIENT opens the port I expect the service to be on, and broadcasts a message, "Hello... Is there anybody out there??", asking if they're there ANY servers listening, and if so, reply back to THIS IP address with your computer name, IP Address and port # where I can find the .NET remoting Services..." Then it waits a small amount of time-out time, gathers up the responses it gets, and if it's more than one, it presents the user with a dialog box and a list of services that responded... The Client then selects one, or, if only ONE responded, it will call Connect((TServerResponse) res); on that, to get connected up. At this point, the server is using Remoting Services with the WellKnownClientType, and WellKnownServerType to put itself out there...
I don't think you are too interested in my "Auto-Service locater", because a lot of people frown on UDP, even more so when your app start broadcasting on large networks. So, I'm assuming you'd be more interested in my RemotingHelper, that gets the client connected up to the server. It looks like this:
public static Object GetObject(Type type)
{
try {
if(_wellKnownTypes == null) {
InitTypeCache();
}
WellKnownClientTypeEntry entr = (WellKnownClientTypeEntry)_wellKnownTypes[type];
if(entr == null) {
throw new RemotingException("Type not found!");
}
return System.Activator.GetObject(entr.ObjectType, entr.ObjectUrl);
} catch(System.Net.Sockets.SocketException sex) {
DebugHelper.Debug.OutputDebugString("SocketException occured in RemotingHelper::GetObject(). Error: {0}.", sex.Message);
Disconnect();
if(Connect()) {
return GetObject(type);
}
}
return null;
}
private static void InitTypeCache()
{
if(m_AdvertiseServer == null) {
throw new RemotingException("AdvertisementServer cannot be null when connecting to a server.");
}
_wellKnownTypes = new Dictionary<Type, WellKnownClientTypeEntry>();
Dictionary<string, object> channelProperties = new Dictionary<string, object>();
channelProperties["port"] = 0;
channelProperties["name"] = m_AdvertiseServer.ChannelName;
Dictionary<string, object> binFormatterProperties = new Dictionary<string, object>();
binFormatterProperties["typeFilterLevel"] = "Full";
if(Environment.UserInteractive) {
BinaryServerFormatterSinkProvider binFormatterProvider = new BinaryServerFormatterSinkProvider(binFormatterProperties, null);
_serverChannel = new TcpServerChannel(channelProperties, binFormatterProvider);
// LEF: Only if we are coming form OUTSIDE the SERVICE do we want to register the channel, since the SERVICE already has this
// channel registered in this AppDomain.
ChannelServices.RegisterChannel(_serverChannel, false);
}
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IPawnStatServiceStatus)));
RegisterType(typeof(IPawnStatServiceStatus),m_AdvertiseServer.RunningStatusURL.ToString());
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IPawnStatService)));
RegisterType(typeof(IPawnStatService), m_AdvertiseServer.RunningServerURL.ToString());
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IServiceConfiguration)));
RegisterType(typeof(IServiceConfiguration), m_AdvertiseServer.RunningConfigURL.ToString());
}
[SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration, RemotingConfiguration=true)]
public static void RegisterType(Type type, string serviceUrl)
{
WellKnownClientTypeEntry clientType = new WellKnownClientTypeEntry(type, serviceUrl);
if(clientType != RemotingConfiguration.IsWellKnownClientType(type)) {
RemotingConfiguration.RegisterWellKnownClientType(clientType);
}
_wellKnownTypes[type] = clientType;
}
public static bool Connect()
{
// Init the Advertisement Service, and Locate any listening services out there...
m_AdvertiseServer.InitClient();
if(m_AdvertiseServer.LocateServices(iTimeout)) {
if(!Connected) {
bConnected = true;
}
} else {
bConnected = false;
}
return Connected;
}
public static void Disconnect()
{
if(_wellKnownTypes != null) {
_wellKnownTypes.Clear();
}
_wellKnownTypes = null;
if(_serverChannel != null) {
if(Environment.UserInteractive) {
// LEF: Don't unregister the channel, because we are running from the service, and we don't want to unregister the channel...
ChannelServices.UnregisterChannel(_serverChannel);
// LEF: If we are coming from the SERVICE, we do *NOT* want to unregister the channel, since it is already registered!
_serverChannel = null;
}
}
bConnected = false;
}
}
So, THAT is meat of my remoting code, and allowed me to write a client that didn't have to be aware of where the services was installed, or how many services were running on the network. This allowed me to communicate with it over the network, or on the local machine. And it wasn't a problem to have two or more people running the app, however, yours might. Now, I have some complicated callback code in mine, where I register events to go across the remoting channel, so I have to have code that checks to see if the client is even still connected before I send the notification to the client that something happened. Plus, if you are running for more than one user, you might not want to use Singleton objects. It was fine for me, because the server OWNS the objects, and they are whatever the server SAYS they are. So, my STATS object, for example, is a Singleton. No reason to create an instance of it for EVERY connection, when everyone is going to see the same data, right?
I can provide more chunks of code if necessary. This is, of course, one TINY bit of the overall picture of what makes this work... Not to mention the subscription providers, and all that.
For the sake of completeness, I'm including the code chunk to keep your service connected for the life of the process.
public override object InitializeLifetimeService()
{
ILease lease = (ILease)base.InitializeLifetimeService();
if(lease.CurrentState == LeaseState.Initial) {
lease.InitialLeaseTime = TimeSpan.FromHours(24);
lease.SponsorshipTimeout = TimeSpan.FromSeconds(30);
lease.RenewOnCallTime = TimeSpan.FromHours(1);
}
return lease;
}
#region ISponsor Members
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
public TimeSpan Renewal(ILease lease)
{
return TimeSpan.FromHours(12);
}
#endregion
If you include the ISponsor interface as part of your server object, you can implement the above code.
Hope SOME of this is useful.
When you register your service, you can tell it to allow interactions with the desktop. You can read this oldie link http://www.codeproject.com/KB/install/cswindowsservicedesktop.aspx
Also, don't forget that you can have multiple users logged in at the same time.
Apparently on Windows Vista and newer interacting with the desktop has been made more difficult. Read this for a potential solution: http://www.codeproject.com/KB/cs/ServiceDesktopInteraction.aspx

How to determine that a WCF Service is ready?

I have the following scenario:
My main Application (APP1) starts a Process (SERVER1). SERVER1 hosts a WCF service via named pipe. I want to connect to this service (from APP1), but sometimes it is not yet ready.
I create the ChannelFactory, open it and let it generate a client. If I now call a method on the generated Client I receive an excpetion whitch tells me that the Enpoint was not found:
var factory = new ChannelFactory<T>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe//localhost/myservice");
factory.Open()
var Client = factory.CreateChannel();
Client.Foo();
If I wait a little bit before calling the service, everything is fine;
var Client = factory.CreateChannel();
Thread.Sleep(2000);
Client.Foo();
How can I ensure, that the Service is ready without having to wait a random amount of time?
If the general case is that you are just waiting for this other service to start up, then you may as well use the approach of having a "Ping" method on your interface that does nothing, and retrying until this starts responding.
We do a similar thing: we try and call a ping method in a loop at startup (1 second between retries), recording in our logs (but ultimately ignoring) any TargetInvocationException that occur trying to reach our service. Once we get the first proper response, we proceed onwards.
Naturally this only covers the startup warmup case - the service could go down after a successfull ping, or it we could get a TargetInvocationException for a reason other than "the service is not ready".
You could have the service signal an event [Edited-see note] once the service host is fully open and the Opened event of the channel listener has fired. The Application would wait on the event before using its proxy.
Note: Using a named event is easy because the .NET type EventWaitHandle gives you everything you need. Using an anonymous event is preferable but a bit more work, since the .NET event wrapper types don't give you an inheritable event handle. But it's still possible if you P/Invoke the Windows DuplicateHandle API yourself to get an inheritable handle, then pass the duplicated handle's value to the child process in its command line arguments.
If you're using .Net 4.0 you could use WS-Discovery to make the service announce its presence via Broadcast IP.
The service could also send a message to a queue (MSMQ binding) with a short lifespan, say a few seconds, which your client can monitor.
Have the service create a signal file, then use a FileSystemWatcher in the client to detect when it gets created.
Just while (!alive) try { alive = client.IsAlive(); } catch { ...reconnect here... } (in your service contract, you just have IsAlive() return true)
I have had the same issue and when using net.pipe*://localhost/serviceName*, I solved it by looking at the process of the self-hosted application.
the way i did that was with a utility class, here is the code.
public static class ServiceLocator
{
public static bool IsWcfStarted()
{
Process[] ProcessList = Process.GetProcesses();
return ProcessList.Any(a => a.ProcessName.StartsWith("MyApplication.Service.Host", StringComparison.Ordinal));
}
public static void StartWcfHost()
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var Process2 = new Process();
var Start2 = new ProcessStartInfo();
Start2.FileName = Path.Combine(path, "Service", "MyApplication.Service.Host.exe");
Process2.StartInfo = Start2;
Process2.Start();
}
}
now, my application isn't called MyApplication but you get my point...
now in my client Apps that use the host i have this call:
if (!ServiceLocator.IsWcfStarted())
{
WriteEventlog("First instance of WCF Client... starting WCF host.")
ServiceLocator.StartWcfHost();
int timeout=0;
while (!ServiceLocator.IsWcfStarted())
{
timeout++;
if(timeout> MAX_RETRY)
{
//show message that probably wcf host is not available, end the client
....
}
}
}
This solved 2 issues,
1. The code errors I had wend away because of the race condition, and 2
2. I know in a controlled manner if the Host crashed due to some issue or misconfiguration.
Hope it helps.
Walter
I attached an event handler to client.InnerChannel.faulted, then reduced the reliableSession to 20 seconds. Within the event handler I removed the existing handler then ran an async method to attempt to connect again and attached the event handler again. Seems to work.

in c#.net how to send message to remote computer throught internet?

c#.net framework 4.0 client profile,Windows application..
i am developing a game which needs to send its current movements of the game through internet to remote computer where the same application(game) is installed.In Same way current movements of the game of remote computer should be send back...
How this could be possible ?
All the answers so far are using a TCP based approach. If you need high performance and low latency then you might find it better to use UDP instead.
TCP brings a lot of overhead with it to guarantee that packets will be resent if they are lost (and various other bits of functionality). UDP on the other hand leaves it up to you to deal with packets not arriving. If you have a game where losing the odd update isn't important you can achieve far better bandwidth use, latency and scalability by using UDP instead of TCP.
UDP still leaves you with all the issues of firewalls, security etc though.
If you need to have it work without worrying about firewalls being an issue then you want to choose a solution that uses HTTP over port 80.
To do that you need to implement a client-server behavior through TCP/IP
There are very different ways to do this
This code I've written could give you a start (it's an option, but not the only one, I leave it off to you to choose the method that suits you best)
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
static class ServerProgram
{
[STAThread]
static void Main()
{
ATSServer();
}
static void ATSServer()
{
TcpChannel tcpChannel = new TcpChannel(7000);
ChannelServices.RegisterChannel(tcpChannel);
Type commonInterfaceType = Type.GetType("ATSRemoteControl");
RemotingConfiguration.RegisterWellKnownServiceType(commonInterfaceType,
"RemoteATSServer", WellKnownObjectMode.SingleCall);
}
}
public interface ATSRemoteControlInterface
{
string yourRemoteMethod(string parameter);
}
public class ATSRemoteControl : MarshalByRefObject, ATSRemoteControlInterface
{
public string yourRemoteMethod(string GamerMovementParameter)
{
string returnStatus = "GAME MOVEMENT LAUNCHED";
Console.WriteLine("Enquiry for {0}", GamerMovementParameter);
Console.WriteLine("Sending back status: {0}", returnStatus);
return returnStatus;
}
}
class ATSLauncherClient
{
static ATSRemoteControlInterface remoteObject;
public static void RegisterServerConnection()
{
TcpChannel tcpChannel = new TcpChannel();
ChannelServices.RegisterChannel(tcpChannel);
Type requiredType = typeof(ATSRemoteControlInterface);
//HERE YOU ADJUST THE REMOTE TCP/IP ADDRESS
//IMPLEMENT RETRIEVAL PROGRAMATICALLY RATHER THAN HARDCODING
remoteObject = (ATSRemoteControlInterface)Activator.GetObject(requiredType,
"tcp://localhost:7000/RemoteATSServer");
string s = "";
s = remoteObject.yourRemoteMethod("GamerMovement");
}
public static void Launch(String GamerMovementParameter)
{
remoteObject.yourRemoteMethod(GamerMovementParameter);
}
}
Hope this Helps.
You should look into some middleware teknologies like WCF, Web service
this is object oriented and easy to develop when you first get the hang of it
You have a lot to consider for this.
You will need to think about security, firewall issues etc.
If that is all put to one side, then you can set up a tcp socket server / client approach.
A quick google will yield plenty of examples.
Check out the Microsoft example http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx
What have you tried?
You can use the System.Net and System.Net.Sockets namespaces to send TCP packets.

Determine if internet connection is available

I know that I am not the first to ask the question: How do I find out if my application is online or not?
I found this post: StackOverflow.
I want to do it with C# and .NET 3.5.
The recommendation is to ping the resource regularly. I am not very happy with that advice. I would rather detect a network change and THEN ping my service to check if it is online.
.NET provides two events for this purpose:
NetworkChange.NetworkAvailabilityChanged
NetworkChange.NetworkAddressChanged
The first event sounds good but it is fired only if the last network card which is online goes offline. I have several virtual network cards which have been installed by VMWare and those are always online.
The second event works but between plugging the network cable and the event, there are often 5 seconds wait time.
The Windows tray icon reacts more or less immediately when I am unplugging the cable.
What is the best way to be as fast as this tray icon?
My workaround would be to poll
NetworkInterface.GetAllNetworkInterfaces()
every 500ms and to throw my own event in case that the status of a network adapter changed.
There must be a better solution :)
I tried the link the Webleeuw suggested, but that code also needs between 4 and 10 seconds to notify me when I plug or unplug my cable.
Now, I wanted to know if it just my computer or installation and I wrote my own Observer class which is based on NetworkInterface.GetAllNetworkInterfaces().
And: It works with lightning speed. My app reacts now as quickly as does the tray.
The code is far from production code, it is just a quick hack. But this is what I will build upon now :)
using System;
using System.Net.NetworkInformation;
using Timer=System.Threading.Timer;
namespace NetworkCheckApp
{
public class NetworkStatusObserver
{
public event EventHandler<EventArgs> NetworkChanged;
private NetworkInterface[] oldInterfaces;
private Timer timer;
public void Start()
{
timer = new Timer(UpdateNetworkStatus, null, new TimeSpan(0, 0, 0, 0, 500), new TimeSpan(0, 0, 0, 0, 500));
oldInterfaces = NetworkInterface.GetAllNetworkInterfaces();
}
private void UpdateNetworkStatus(object o)
{
var newInterfaces = NetworkInterface.GetAllNetworkInterfaces();
bool hasChanges = false;
if (newInterfaces.Length != oldInterfaces.Length)
{
hasChanges = true;
}
if (!hasChanges)
{
for (int i = 0; i < oldInterfaces.Length; i++)
{
if (oldInterfaces[i].Name != newInterfaces[i].Name || oldInterfaces[i].OperationalStatus != newInterfaces[i].OperationalStatus)
{
hasChanges = true;
break;
}
}
}
oldInterfaces = newInterfaces;
if (hasChanges)
{
RaiseNetworkChanged();
}
}
private void RaiseNetworkChanged()
{
if (NetworkChanged != null)
{
NetworkChanged.Invoke(this, null);
}
}
}
}
Try this using NetworkChange class
using System.Net.NetworkInformation
private void Form5_Load(object sender, EventArgs e)
{
NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
}
private void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
if (e.IsAvailable)
{
MessageBox.Show("Available");
}
else
{
MessageBox.Show("Not available");
}
}
People here already told it but there is a diference between network availability and internet availability.
You can have network availability between your network interface and local router but havent internet availability between your local router and your Internet Service Provider (ISP).
There is another problem that testing by ping will tell you about internet availability but not about what network interface is providing it, i think the only way is force ping throught one interface but it isnot possible on windows.
Pinging your resource regularly is the only option that will give you a notification if the service goes offline, as well as if the client goes offline. Potentially you want to handle both situations.
The windows tray icon is very likely connected to the network card drivers, i.e. below the operating system level which is why it can react so fast.
Since the network card is only one of many links between your client and the service that it accesses on the Internet, the only reliable way to detect whether or not the Internet is available is to poll some service out on the Internet, much the same way that ping does. In TCP/IP networking, this is known as a keepalive, and many protocols will have this built into them as an option.
About the pinging: depending on how you wish to interpret the results, pinging doesn't seem watertight to me. What if the target times out once in a while, while the connection remains alive? I have yet to see the server that never fails to respond to a ping.
Checking every X millis if the network interface is still online (NetworkInterface.OperationalStatus property) seems more reliable if you'd ask me.
EDIT: This article deals with network address events on a lower level than the System.Net.NetworkInformation.NetworkChange class, or so it seems. On my pc it works very fast, so hopefully you'll be able to use that solution.
You can use ping, but I would also build a simple call to return a "yes" if it is online. That way you do know if the server is up and that it is running your code. Also I would only call or ping when a network resource is needed and not continually.
Doing a ping is definitely not the cleanest option, especially if it is a web server. Some hosts will disable response to ICMP traffic, so you may ping but not get a response. How about just handling the exception gracefully when it occurs?

Categories