Check for internet connection constantly - c#

How can I check for an internet connection constantly in my application and respond if the connection is not available?
Currently I am using:
while(true) {
if(HasConnection()) {
//doSomething..
}
//stop app by 1sec
}
but it seems rather inelegant.

The accepted answer to this question on superuser describes the way the Windows determines if it has network access. You could use a similar method, but I would spawn a separate thread when your application starts that is responsible for doing the check. Have the separate thread perform the check in whatever manner you feel is the best and raise an event if the connection status changes.

You're looking for the NetworkAvailabilityChanged event.
To check for internet connectivity, you can ping a reliable website, such as Google.com.
Note that it is not possible to be notified of every change in internet connectivity (such as an ISP outage).

Use the following code:
public static class LocalSystemConnection
{
[DllImport("wininet.dll", SetLastError=true, CallingConvention = CallingConvention.ThisCall)]
extern static bool InternetGetConnectedState(out ConnectionStates lpdwFlags, long dwReserved);
/// <summary>
/// Retrieves the connected state of the local system.
/// </summary>
/// <param name="connectionStates">A <see cref="ConnectionStates"/> value that receives the connection description.</param>
/// <returns>
/// A return value of true indicates that either the modem connection is active, or a LAN connection is active and a proxy is properly configured for the LAN.
/// A return value of false indicates that neither the modem nor the LAN is connected.
/// If false is returned, the <see cref="ConnectionStates.Configured"/> flag may be set to indicate that autodial is configured to "always dial" but is not currently active.
/// If autodial is not configured, the function returns false.
/// </returns>
public static bool IsConnectedToInternet(out ConnectionStates connectionStates)
{
connectionStates = ConnectionStates.Unknown;
return InternetGetConnectedState(out connectionStates, 0);
}
/// <summary>
/// Retrieves the connected state of the local system.
/// </summary>
/// <returns>
/// A return value of true indicates that either the modem connection is active, or a LAN connection is active and a proxy is properly configured for the LAN.
/// A return value of false indicates that neither the modem nor the LAN is connected.
/// If false is returned, the <see cref="ConnectionStates.Configured"/> flag may be set to indicate that autodial is configured to "always dial" but is not currently active.
/// If autodial is not configured, the function returns false.
/// </returns>
public static bool IsConnectedToInternet()
{
ConnectionStates state = ConnectionStates.Unknown;
return IsConnectedToInternet(out state);
}
}
[Flags]
public enum ConnectionStates
{
/// <summary>
/// Unknown state.
/// </summary>
Unknown = 0,
/// <summary>
/// Local system uses a modem to connect to the Internet.
/// </summary>
Modem = 0x1,
/// <summary>
/// Local system uses a local area network to connect to the Internet.
/// </summary>
LAN = 0x2,
/// <summary>
/// Local system uses a proxy server to connect to the Internet.
/// </summary>
Proxy = 0x4,
/// <summary>
/// Local system has RAS (Remote Access Services) installed.
/// </summary>
RasInstalled = 0x10,
/// <summary>
/// Local system is in offline mode.
/// </summary>
Offline = 0x20,
/// <summary>
/// Local system has a valid connection to the Internet, but it might or might not be currently connected.
/// </summary>
Configured = 0x40,
}

if you only need to know if at least one connection is available you can try this:
InternetGetConnectedStateEx()
http://msdn.microsoft.com/en-us/library/aa384705%28v=vs.85%29.aspx

if you want to check continuously then use timer
private Timer timer1;
public void InitTimer()
{
timer1 = new Timer();
timer1.Tick += new EventHandler(timerEvent);
timer1.Interval = 2000; // in miliseconds
timer1.Start();
}
private void timerEvent(object sender, EventArgs e)
{
DoSomeThingWithInternet();
}
private void DoSomeThingWithInternet()
{
if (isConnected())
{
// inform user that "you're connected to internet"
}
else
{
// inform user that "you're not connected to internet"
}
}
public static bool isConnected()
{
try
{
using (var client = new WebClient())
using (client.OpenRead("http://clients3.google.com/generate_204"))
{
return true;
}
}
catch
{
return false;
}
}

I know this is an old question but this works great for me.
System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
private async void NetworkChange_NetworkAvailabilityChanged(object sender, System.Net.NetworkInformation.NetworkAvailabilityEventArgs e)
{
//code to execute...
}
I subscribe to the event to a listener and it constantly checks for connection. this you can add a If statement such as:
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
//Send Ping...
}
else
{
//other code....
}

How will you know if you have an Internet Connection? Is it enough that you can route packets to a nearby router? Maybe the machine has only a single NIC, a single gateway, and perhaps that Gateway's connection goes down but the machine can still route to the gateway and local network?
Maybe the machine has a single NIC and a dozen gateways; maybe they come and go all the time, but one of them is always up?
What if the machine has multiple NICs, but only a single gateway? Perhaps it can route to some subset of the Internet, but still has an excellent connection to a local network not connected to the Internet?
What if the machine has muliple NICs, multiple gateways, but for administrative policy reasons, still only portions of the Internet are routeble?
Do you really only care if clients have connectivity to your servers?
What kind of latency between packets is acceptable? (30ms is good, 300ms is pushing the limits of human endurance, 3000ms is intolerable long time, 960000ms is what would be required for a connection to a solar probe.) What kind of packet loss is acceptable?
What are you really trying to measure?

This would be a start but as sarnold has mentioned there are a lot of things you need to consider

You can test internet connectivity by pinging to some website like:
public bool IsConnectedToInternet
{
try
{
using (System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping())
{
string address = #"http://www.google.com";// System.Net.NetworkInformation.PingReply pingReplay = ping.Send(address);//you can specify timeout.
if (pingReplay.Status == System.Net.NetworkInformation.IPStatus.Success)
{
return true;
}
}
}
catch
{
#if DEBUG
System.Diagnostics.Debugger.Break();
#endif//DEBUG
}
return false;
}

This code will life-saving for you.. it not only checks real internet connection but also handle the exception with indication on the console window...
after every 2 seconds
using System;
using System.Net;
using System.Threading;
using System.Net.Http;
bool check() //Checking for Internet Connection
{
while (true)
{
try
{ var i = new Ping().Send("www.google.com").Status;
if (i == IPStatus.Success)
{ Console.WriteLine("connected");
return true;
}
else { return false; }
}
catch (Exception)
{
Console.WriteLine("Not Connected");
Thread.Sleep(2000);
continue;
}
}
};
check();

using the NetworkChange.NetworkAvailabilityChanged is the most misleading answer. It check the network availablity change not the internet connection change.
we can monitor the internet connection using Windows NLM API.
using System;
using System.Runtime.InteropServices.ComTypes;
using NETWORKLIST;
namespace Components.Network.Helpers
{
public class InternetConnectionChecker : INetworkListManagerEvents, IDisposable
{
private int _cookie;
private IConnectionPoint _connectionPoint;
private readonly INetworkListManager _networkListManager;
public InternetConnectionChecker()
{
_networkListManager = new NetworkListManager();
}
public bool IsConnected()
{
return _networkListManager.IsConnectedToInternet;
}
public void StartMonitoringConnection()
{
try
{
var container = _networkListManager as IConnectionPointContainer;
if (container == null)
throw new Exception("connection container is null");
var riid = typeof(INetworkListManagerEvents).GUID;
container.FindConnectionPoint(ref riid, out _connectionPoint);
_connectionPoint.Advise(this, out _cookie);
}
catch (Exception e)
{
}
}
public void ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
{
if (_networkListManager.IsConnectedToInternet)
{
// do something based on internet connectivity
}
}
public void Dispose()
{
_connectionPoint.Unadvise(_cookie);
}
}
}

Related

Photon does not show me any logs when connecting

I'm doing this tutorial and just wrote the first code block. The following is in the tutorial:
At this point, you can save the Launch Scene and hit Play. You should see in the Unity Console a good dozens of logs. Look specifically for "Connected to masterserver." log which indicated that indeed we are now connected and ready to join a room for example.
But I'm not getting any logs when running this line PhotonNetwork.ConnectUsingSettings(_gameVersion);.
public class Launcher : MonoBehaviour
{
#region Public Variables
#endregion
#region Private Variables
/// <summary>
/// Client version number, this number seperates users
/// </summary>
string _gameVersion = "1";
#endregion
#region Monobehavior callbacks
/// <summary>
/// Eary init method of monobehavior
/// </summary>
void Awake()
{
// #NotImportant
// Force Full LogLevel
PhotonNetwork.logLevel = PhotonLogLevel.Full;
PhotonNetwork.networkingPeer.DebugOut = ExitGames.Client.Photon.DebugLevel.ALL; // <---------- added this later but still no logs.
// #Critical
// we don't join the lobby. There is no need to join a lobby to get the list of rooms.
PhotonNetwork.autoJoinLobby = false;
// #Critical
// this makes sure we can use PhotonNetwork.LoadLevel() on the master client and all clients in the same room sync their level automatically
PhotonNetwork.automaticallySyncScene = true;
}
// Use this for initialization
void Start()
{
Connect();
}
/// <summary>
/// Start the connection process.
/// - If already connected, we attempt joining a random room
/// - if not yet connected, Connect this application instance to Photon Cloud Network
/// </summary>
public void Connect()
{
// we check if we are connected or not, we join if we are , else we initiate the connection to the server.
if (PhotonNetwork.connected)
{
// #Critical we need at this point to attempt joining a Random Room. If it fails, we'll get notified in OnPhotonRandomJoinFailed() and we'll create one.
PhotonNetwork.JoinRandomRoom();
}
else
{
// #Critical, we must first and foremost connect to Photon Online Server.
PhotonNetwork.ConnectUsingSettings(_gameVersion);
// <----------------------------- This is reached!
}
}
// Update is called once per frame
void Update()
{
}
#endregion
}
How can I enable full logging?
yes, the latest version of PUN now features logging settings in the Photon Settings themselves. So set it there. The updated tutorial and code should be up very soon on the website.

Enumerating composite device nodes

I have the following class that enumerates all COM ports on the local PC, finding and storing only those with a friendly name that starts with the given prefix.
Now, assuming I know such COM ports are part of a composite device and that the composite device also has a network adapter, how can I find the network adapter associated with the given device? I'm sure there must be a relatively simple way of doing this (both devices will have the same parent node I think), but I'm not sure what the non-interop method would be... Can anyone assist?
Here is the class:
/// <summary>
/// A class to enumerate all COM ports through USB.
/// </summary>
public class SerialPortUSB
{
/// <summary>
/// Structure to store a port name and details.
/// </summary>
public struct PortName
{
public string Port;
public string Fullname;
public bool HadPrefix;
};
/// <summary>
/// Function to return all ports with the given prefix.
/// </summary>
/// <param name="prefix"></param>
/// <returns></returns>
static public List<PortName> PortsWithPrefix(string prefix)
{
List<PortName> ports = new List<PortName>();
try
{
// Select all COM ports.
ManagementObjectSearcher searcher = new ManagementObjectSearcher( "root\\CIMV2",
"SELECT * FROM Win32_SerialPort");
// Now iterate results looking for those that start with the prefix.
foreach (ManagementObject item in searcher.Get())
{
string friendlyName = (string)item["Caption"];
if (!friendlyName.StartsWith(prefix))
{
continue;
}
// Construct an item for this.
PortName name = new PortName();
int start = friendlyName.LastIndexOf('(') + 1, end = friendlyName.LastIndexOf(')');
name.HadPrefix = true;
name.Port = friendlyName.Substring(start, end - start);
name.Fullname = friendlyName;
ports.Add(name);
}
}
catch (ManagementException e)
{
// Failed to find any...
}
// Return the list of ports.
return ports;
}
}
Thought I'd reply to my own, rather than deleting the question just in case someone else finds the answer useful.
It turns out the PNPDeviceID, a property present in both Win32_SerialPorts and Win32_NetworkAdapters contains an ID unique to the device, so it's possible to identify them both. The solution is first to enumerate the serial ports, then extract the unique part of the PNPDeviceID and then to find all network adapters that are LIKE '%value%', where value is part of the PNPDeviceID.
Turns out the number is the same for both, i.e.:
Serial Port PNPDeviceID = USB\VID_17DC&PID_0500&MI_02\8&18F2972&0&0002"
and
Network Adapter PNPDeviceID = USB\VID_17DC&PID_0500&MI_00\8&18F2972&0&0000"
, where the common ID is 18F2972.

What is the most efficient way to make an application handle hundreds of simultaneous file open requests from Windows Explorer in a single instance?

When I select a bunch of files in Explorer and right click open them (or press enter) I want all the files to be passed to a single instance of my application. I've used named pipes before to pass arguments from secondary instances to an existing global instance, but it seems like doing this for hundreds of program instances simultaneously (not to mention actually loading the application hundreds of times) is far from optimal. Is there a way to get explorer to concatenate the arguments on its own?
edit: I found a copy of the Paint.net 3.36 source code and it uses a memory mapped file to communicate between instances. That seems even more bloated than named pipes though (although it's not as likely to open hundreds of images for editing).
You can do it with shell extension.
Check out Creating Shortcut Menu Handlers
and
Create Namespace Extensions for Windows Explorer with the .NET Framework
I couldn't figure out the shell extension so I went with the named pipes. It seems to perform reasonably well, especially since there seems to be a limit in Windows 7 of how many files you can open with multi-select (although this will solve that: open-more-than-15-files-at-once-on-windows-7)
It took me forever to figure out how to get the timeout behavior to work (had to use a manual signal instead of AsyncWaitHandle). Hopefully this will save somebody some time:
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// The Original Code is the IDPicker project.
//
// The Initial Developer of the Original Code is Matt Chambers.
//
// Copyright 2011 Vanderbilt University
//
// Contributor(s):
//
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Collections.Generic;
/// <summary>
/// A handler for an application to consolidate arguments from multiple instances
/// (within a Timeout period) into a single instance.
/// </summary>
public sealed class SingleInstanceHandler
{
/// <summary>
/// Occurs when the Timeout period has elapsed: the single instance is launched with the consolidated argument list.
/// </summary>
public event EventHandler<SingleInstanceEventArgs> Launching;
/// <summary>
/// Time to wait in milliseconds for additional instances to add their arguments to the first instance's.
/// </summary>
public int Timeout { get; set; }
/// <summary>
/// Constructs a handler for an application to consolidate arguments from multiple instances
/// (within a Timeout period) into a single instance.
/// </summary>
/// <param name="uniqueID">A unique string for the application.</param>
public SingleInstanceHandler (string uniqueID)
{
var rng = new Random(uniqueID.GetHashCode());
byte[] ipcMutexGuidBytes = new byte[16];
byte[] ipcNamedPipeGuidBytes = new byte[16];
rng.NextBytes(ipcMutexGuidBytes);
rng.NextBytes(ipcNamedPipeGuidBytes);
ipcMutexGuid = new Guid(ipcMutexGuidBytes).ToString().Trim('{', '}');
ipcNamedPipeGuid = new Guid(ipcNamedPipeGuidBytes).ToString().Trim('{', '}');
Timeout = 500;
}
/// <summary>
/// Launch a new instance using 'args' or consolidate 'args' into a recent instance.
/// </summary>
public void Connect (string[] args)
{
if (Launching == null)
return; // nothing to do
// create global named mutex
using (ipcMutex = new Mutex(false, ipcMutexGuid))
{
// if the global mutex is not locked, wait for args from additional instances
if (ipcMutex.WaitOne(0))
waitForAdditionalInstances(args);
else
sendArgsToExistingInstance(args);
}
}
private void waitForAdditionalInstances (string[] args)
{
var accumulatedArgs = new List<string>(args);
while (true)
{
var signal = new ManualResetEvent(false);
using (var pipeServer = new NamedPipeServerStream(ipcNamedPipeGuid, PipeDirection.In, -1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
{
pipeServer.BeginWaitForConnection(x =>
{
// if timed out, stop waiting for a connection
if (signal.WaitOne(0))
{
signal.Close();
return;
}
pipeServer.EndWaitForConnection(x);
signal.Set();
}, null);
// no client connected to the pipe within the Timeout period
if (!signal.WaitOne(Timeout, true))
{
signal.Set();
break;
}
using (var sr = new StreamReader(pipeServer))
{
int length = Convert.ToInt32(sr.ReadLine());
for (int i = 0; i < length; ++i)
accumulatedArgs.Add(sr.ReadLine());
}
}
// new args have been added to accumulatedArgs, continue loop to listen for another client
}
Launching(this, new SingleInstanceEventArgs(accumulatedArgs.ToArray()));
}
private void sendArgsToExistingInstance (string[] args)
{
var pipeClient = new NamedPipeClientStream(".", ipcNamedPipeGuid, PipeDirection.Out);
// try to connect to the pipe server for the Timeout period
try
{
var sb = new StringBuilder();
sb.AppendLine(args.Length.ToString());
foreach (string arg in args)
sb.AppendLine(arg);
byte[] buffer = Encoding.ASCII.GetBytes(sb.ToString());
pipeClient.Connect(Timeout);
// can this ever happen? if it does, don't handle it like a timeout exception
if (!pipeClient.IsConnected)
throw new Exception("did not throw exception");
pipeClient.Write(buffer, 0, buffer.Length);
}
catch (Exception e)
{
if (!e.Message.ToLower().Contains("time"))
throw;
// no server was running; launch a new instance
Launching(this, new SingleInstanceEventArgs(args));
}
}
private string ipcMutexGuid;
private string ipcNamedPipeGuid;
private Mutex ipcMutex;
}
/// <summary>
/// Stores the consolidated argument list from one or more instances of an application.
/// </summary>
public sealed class SingleInstanceEventArgs : EventArgs
{
public SingleInstanceEventArgs (string[] args) { Args = args; }
/// <summary>
/// The consolidated argument list from one or more instances of an application.
/// </summary>
public string[] Args { get; private set; }
}
How to use it:
static void Main (string[] args)
{
var singleInstanceHandler = new SingleInstanceHandler(Application.ExecutablePath) { Timeout = 200 };
singleInstanceHandler.Launching += (sender, e) =>
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm(e.Args));
};
singleInstanceHandler.Connect(args);
}

How to tunnel an SSL connection correctly between two NetworkStreams?

HttpWebRequest doesn't support SOCKS proxies, so after a long research I've determined, that the best way to add SOCKS support for WebRequest and WebClient (without reinventing the wheel, like SocksHttpWebRequest does) was to create a temporary HTTP proxy which forwards any incoming request to the SOCKS proxy.
Forwarding an HTTP request is easy, and works like charm.
Forwarding an HTTPS request should be theoretically easy too:
The HttpWebRequest connects to our HTTP proxy, and sends the following:
CONNECT google.com:443 HTTP/1.0
Host: google.com
We connect to google.com:443 through the SOCKS proxy, and then send back the following to the client:
HTTP/1.0 200 Tunnel established
According to this document, at this point, we copy all the bytes between the streams, and when one closes the connection, we close the other one too.
However, copying from one NetworkStream to another doesn't seem to work like I expected. At one point, Read() seems to hang for no apparent reason. If I set timeouts, regardless how big ones, I get certificate errors.
The stripped down version of the code I'm using right now:
/// <summary>
/// In theory, forwards any incoming bytes from one stream to another.
/// </summary>
/// <param name="httpProxyStream">The HTTP proxy, which we opened for <code>HttpWebRequest</code>.</param>
/// <param name="socksProxyStream">The SOCKS proxy, which we connect to and forward the traffic from the HTTP proxy.</param>
private void TunnelRequest(NetworkStream httpProxyStream, NetworkStream socksProxyStream)
{
while (true)
{
try
{
if (httpProxyStream.DataAvailable)
{
CopyStreamToStream(httpProxyStream, socksProxyStream);
}
if (socksProxyStream.DataAvailable)
{
CopyStreamToStream(socksProxyStream, httpProxyStream);
}
}
catch
{
break;
}
}
}
/// <summary>
/// Copies the first stream's content from the current position to the second stream.
/// </summary>
/// <param name="source">The source stream.</param>
/// <param name="destionation">The destionation stream.</param>
/// <param name="flush">if set to <c>true</c>, <c>Flush()</c> will be called on the destination stream after finish.</param>
/// <param name="bufferLength">Length of the buffer.</param>
public static void CopyStreamToStream(Stream source, Stream destionation, bool flush = true, int bufferLength = 4096)
{
var buffer = new byte[bufferLength];
while (true)
{
int i;
try
{
i = source.Read(buffer, 0, bufferLength);
}
catch
{
break;
}
if (i == 0)
{
break;
}
destionation.Write(buffer, 0, i);
}
if (flush)
{
destionation.Flush();
}
}
The full class is available here: HttpToSocks.cs
I'm stuck on this piece of code for days now. The task is so simple, yet it just won't work... Please help me regain my sanity.
EDIT: I am aware that the while(true) is not my greatest line, but after lots of variations, this remained in the code to make sure it won't exit prematurely, and that's why I'm getting certificate errors.
EDIT 2: The problem has been fixed. The full class is available in the git repository, if anyone's interested.

Running windows service to watch service running grow memory (leak)

I have checked all posts here, but can't find a solution for me so far.
I did setup a small service that should only watch if my other services I want to monitor runs, and if not, start it again and place a message in the application eventlog.
The service itself works great, well nothing special :), but when I start the service it use around 1.6MB of RAM, and every 10 seconds it grow like 60-70k which is way to much to live with it.
I tried dispose and clear all resources. Tried work with the System.Timers instead of the actual solution, but nothing really works as I want it, memory still grows.
No difference in debug or release version and I am using it on .Net 2, don't know if it make a difference to you 3,3.5 or 4.
Any hint?!
using System;
using System.IO;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
namespace Watchguard
{
class WindowsService : ServiceBase
{
Thread mWorker;
AutoResetEvent mStop = new AutoResetEvent(false);
/// <summary>
/// Public Constructor for WindowsService.
/// - Put all of your Initialization code here.
/// </summary>
public WindowsService()
{
this.ServiceName = "Informer Watchguard";
this.EventLog.Source = "Informer Watchguard";
this.EventLog.Log = "Application";
// These Flags set whether or not to handle that specific
// type of event. Set to true if you need it, false otherwise.
this.CanHandlePowerEvent = false;
this.CanHandleSessionChangeEvent = false;
this.CanPauseAndContinue = false;
this.CanShutdown = false;
this.CanStop = true;
if (!EventLog.SourceExists("Informer Watchguard"))
EventLog.CreateEventSource("Informer Watchguard", "Application");
}
/// <summary>
/// The Main Thread: This is where your Service is Run.
/// </summary>
static void Main()
{
ServiceBase.Run(new WindowsService());
}
/// <summary>
/// Dispose of objects that need it here.
/// </summary>
/// <param name="disposing">Whether or not disposing is going on.</param>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
/// <summary>
/// OnStart: Put startup code here
/// - Start threads, get inital data, etc.
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
base.OnStart(args);
MyLogEvent("Init");
mWorker = new Thread(WatchServices);
mWorker.Start();
}
/// <summary>
/// OnStop: Put your stop code here
/// - Stop threads, set final data, etc.
/// </summary>
protected override void OnStop()
{
mStop.Set();
mWorker.Join();
base.OnStop();
}
/// <summary>
/// OnSessionChange(): To handle a change event from a Terminal Server session.
/// Useful if you need to determine when a user logs in remotely or logs off,
/// or when someone logs into the console.
/// </summary>
/// <param name="changeDescription"></param>
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
}
private void WatchServices()
{
string scName = "";
ServiceController[] scServices;
scServices = ServiceController.GetServices();
for (; ; )
{
// Run this code once every 10 seconds or stop right away if the service is stopped
if (mStop.WaitOne(10000)) return;
// Do work...
foreach (ServiceController scTemp in scServices)
{
scName = scTemp.ServiceName.ToString().ToLower();
if (scName == "InformerWatchguard") scName = ""; // don't do it for yourself
if (scName.Length > 8) scName = scName.Substring(0, 8);
if (scName == "informer")
{
ServiceController sc = new ServiceController(scTemp.ServiceName.ToString());
if (sc.Status == ServiceControllerStatus.Stopped)
{
sc.Start();
MyLogEvent("Found service " + scTemp.ServiceName.ToString() + " which has status: " + sc.Status + "\nRestarting Service...");
}
sc.Dispose();
sc = null;
}
}
}
}
private static void MyLogEvent(String Message)
{
// Create an eEventLog instance and assign its source.
EventLog myLog = new EventLog();
myLog.Source = "Informer Watchguard";
// Write an informational entry to the event log.
myLog.WriteEntry(Message);
}
}
}
Your code may throw an exceptions inside loop, but these exception are not catched. So, change the code as follows to catch exceptions:
if (scName == "informer")
{
try {
using(ServiceController sc = new ServiceController(scTemp.ServiceName.ToString())) {
if (sc.Status == ServiceControllerStatus.Stopped)
{
sc.Start();
MyLogEvent("Found service " + scTemp.ServiceName.ToString() + " which has status: " + sc.Status + "\nRestarting Service...");
}
}
} catch {
// Write debug log here
}
}
You can remove outer try/catch after investigating, leaving using statement to make sure Dispose called even if exception thrown inside.
At a minimum, you need to do this in your logging code since EventLog needs to be Dispose()d. Seems like this resource could be reused rather than new-ed on every call. You could also consider using in your main loop for the ServiceController objects, to make your code more exception-safe.
private static void MyLogEvent(String Message)
{
// Create an eEventLog instance and assign its source.
using (EventLog myLog = new EventLog())
{
myLog.Source = "Informer Watchguard";
// Write an informational entry to the event log.
myLog.WriteEntry(Message);
}
}
This should be moved into the loop, since you don't want to keep a reference to old service handles for the life of your service:
ServiceController[] scServices = ServiceController.GetServices();
You also want to dispose of your reference to EventLog and to the ServiceController instances. As Artem points out, watch out for exceptions that are preventing you from doing this.
Since memory is going up every 10 seconds, it has to be something in your loop.
If memory goes up whether or not you write to the EventLog, then that is not the main problem.
Does memory used ever come down? Ie does the garbage collector kick in after awhile? You could test the GC's effect by doing a GC.Collect() before going back to sleep (though I'd be careful of using it in production).
I am not sure I understand the problem exactly. Is the service you are going to be monitoring always the same. It would appear from your code that the answer is yes, and if that is the case then you can simply create the ServiceController class instance passing the name of the service to the constructor.
In your thread routine you want to continue looping until a stop is issued, and the WaitOne method call returns a Boolean, so a while loop seems to be appropriate. Within the while loop you can call the Refresh method on the ServiceController class instance to get the current state of the service.
The event logging should simple require a call one of the static method EventLog.WriteEntry methods, at minimum passing your message and the source 'Informer Watchguard'
The ServiceController instance can be disposed when you exit from the loop in the thread routine
All this would mean you are creating fewer objects that need to be disposed, and therefore less likely that some resource leak will exist.
Thanks to all suggestions.
Finally the service is stable now with some modifications.
#Steve: I watch many services all beginning with the same name "Informer ..." but I don't know exactly full names, that's why I go this way.

Categories