Programmatically get site status from IIS, gets back COM error - c#

I am trying to programmatically get my site status from IIS to see if it's stopped, but I kept getting the following error,
The object identifier does not represent a valid object. (Exception from HRESULT: 0x800710D8)
The application is using ServerManager Site class to access the site status. Here is the code,
//This is fine, gets back the site
var serverManager = new Microsoft.Web.Administration.ServerManager(ConfigPath);
var site = serverManager.Sites.FirstOrDefault(x => x.Id == 5);
if (site == null) return;
var appPoolName = site.Applications["/"].ApplicationPoolName;
//error!
var state = site.State;
I've test with static site to isolate the issue, making sure that the site is up and running, all configuration are valid, point to the valid application pool...etc.
Let me know if you need more details. Is it the COM thing?

I figured out where the problem is. Basically, there are two parts to the Server manager, the first part of the server manager allows you to read site details from configuration file, which is what I've been doing above. The problem with that is you will only able get the information that's in file and site state is not part of it.
The second part of the Server Manager allows you to connect to the IIS directly and it does this by interacting with the COM element. So what I should be doing is this:
ServerManager manager= ServerManager.OpenRemote("testserver");
var site = manager.Sites.First();
var status = site.State.ToString() ;

I had a similar problem but mine was caused by the delay needed to activate the changes from the call to CommitChanges on the ServerManager object. I found the answer I needed here:
ServerManager CommitChanges makes changes with a slight delay
It seems like polling is required to get consistent results. Something similar to this solved my problem (I got the exception when accessing a newly added application pool):
...
create new application pool
...
sman.CommitChanges();
int i = 0;
const int max = 10;
do
{
i++;
try
{
if (ObjectState.Stopped == pool.State)
{
write_log("Pool was stopped, starting: " + pool.Name);
pool.Start();
}
sman.CommitChanges();
break;
}
catch (System.Runtime.InteropServices.COMException e)
{
if (i < max)
{
write_log("Waiting for IIS to activate new config...");
Thread.Sleep(1000);
}
else
{
throw new Exception(
"CommitChanges timed out efter " + max + " attempts.",
e);
}
}
} while (true);
...

Related

Application Pool Status in C#

I am trying to get application pool status from within a web application. Application pool I am interested in is "ABC" but when I check for it by name I get nothing and when I inspect the available pools by name (i.e. manager.ApplicationPools) they show as Clr4ClassicAppPool, Clr4IntegratedAppPool, ... so I never find a match.
This is what I am using
public static int GetAppPoolStatus(string sAppPoolName)
{
int iRet = -1;
try
{
using (ServerManager manager = new ServerManager())
{
ApplicationPool appPool = manager.ApplicationPools.FirstOrDefault(ap => ap.Name == sAppPoolName);
if (appPool != null)
{
//Get the current state of the app pool
iRet = (int)appPool.State; // 0: Starting, 1: Started, 2: Stopping, 3: Stopped
}
else
{
}
}
}
catch (Exception ex)
{ }
return iRet;
}
The GAC version (7.9.0.0) was part of IIS Express, and is resolved by MSBuild when compiling your project if your project file does not explicitly point to %SystemRoot%\system32\inetsrv\Microsoft.Web.Administration.dll.
The ultimate solution (if not to uninstall IIS Express) is to add a reference explicitly to %SystemRoot%\system32\inetsrv\Microsoft.Web.Administration.dll to consume the right metadata at compile time. It has side effects, but still a reliable way. And at runtime, use assembly redirection to stick to version 7.0.0.0.
More tips can be found in this post

How to check database connection in MongoDB [duplicate]

I use MongoDB drivers to connect to the database. When my form loads, I want to set up connection and to check whether it is ok or not. I do it like this:
var connectionString = "mongodb://localhost";
var client = new MongoClient(connectionString);
var server = client.GetServer();
var database = server.GetDatabase("reestr");
But I do not know how to check connection. I tried to overlap this code with try-catch, but to no avail. Even if I make an incorrect connectionString, I still can not get any error message.
To ping the server with the new 3.0 driver its:
var database = client.GetDatabase("YourDbHere");
database.RunCommandAsync((Command<BsonDocument>)"{ping:1}")
.Wait();
There's a ping method for that:
var connectionString = "mongodb://localhost";
var client = new MongoClient(connectionString);
var server = client.GetServer();
server.Ping();
full example for 2.4.3 - where "client.GetServer()" isn't available.
based on "Paul Keister" answer.
client = new MongoClient("mongodb://localhost");
database = client.GetDatabase(mongoDbStr);
bool isMongoLive = database.RunCommandAsync((Command<BsonDocument>)"{ping:1}").Wait(1000);
if(isMongoLive)
{
// connected
}
else
{
// couldn't connect
}
I've had the same question as the OP, and tried every and each solution I was able to find on Internet...
Well, none of them worked to my true satisfaction, so I've opted for a research to find a reliable and responsive way of checking if connection to a MongoDB Database Server is alive. And this without to block the application's synchronous execution for too long time period...
So here are my prerequisites:
Synchronous processing of the connection check
Short to very short time slice for the connection check
Reliability of the connection check
If possible, not throwing exceptions and not triggering timeouts
I've provided a fresh MongoDB Installation (version 3.6) on the default localhost URL: mongodb://localhost:27017. I've also written down another URL, where there was no MongoDB Database Server: mongodb://localhost:27071.
I'm also using the C# Driver 2.4.4 and do not use the legacy implementation (MongoDB.Driver.Legacy assembly).
So my expectations are, when I'm checking the connection to the first URL, it should give to me the Ok for a alive connection to an existing MongoDB server, when I'm checking the connection to the second URL it should give to me the Fail for a non-existing MongoDB server...
Using the IMongoDatabase.RunCommand method, queries the server and causes the server response timeout to elapse, thus not qualifying against the prerequisites. Furthermore after the timeout, it breaks with a TimeoutException, which requires additional exception handling.
This actual SO question and also this SO question have delivered the most of the start information I needed for my solution... So guys, many thanks for this!
Now my solution:
private static bool ProbeForMongoDbConnection(string connectionString, string dbName)
{
var probeTask =
Task.Run(() =>
{
var isAlive = false;
var client = new MongoDB.Driver.MongoClient(connectionString);
for (var k = 0; k < 6; k++)
{
client.GetDatabase(dbName);
var server = client.Cluster.Description.Servers.FirstOrDefault();
isAlive = (server != null &&
server.HeartbeatException == null &&
server.State == MongoDB.Driver.Core.Servers.ServerState.Connected);
if (isAlive)
{
break;
}
System.Threading.Thread.Sleep(300);
}
return isAlive;
});
probeTask.Wait();
return probeTask.Result;
}
The idea behind this is the MongoDB Server does not react (and seems to be non-existing) until a real attempt is made to access some resource on the server (for example a database). But retrieving some resource alone is not enough, as the server still has no updates to its state in the server's Cluster Description. This update comes first, when the resource is retrieved again. From this time point, the server has valid Cluster Description and valid data inside it...
Generally it seems to me, the MongoDB Server does not proactivelly propagate its Cluster Description to all connected clients. Rather then, each client receives the description, when a request to the server has been made. If some of you fellows have more information on this, please either confirm or deny my understandings on the topic...
Now when we target an invalid MongoDB Server URL, then the Cluster Description remains invalid and we can catch and deliver an usable signal for this case...
So the following statements (for the valid URL)
// The admin database should exist on each MongoDB 3.6 Installation, if not explicitly deleted!
var isAlive = ProbeForMongoDbConnection("mongodb://localhost:27017", "admin");
Console.WriteLine("Connection to mongodb://localhost:27017 was " + (isAlive ? "successful!" : "NOT successful!"));
will print out
Connection to mongodb://localhost:27017 was successful!
and the statements (for the invalid URL)
// The admin database should exist on each MongoDB 3.6 Installation, if not explicitly deleted!
isAlive = ProbeForMongoDbConnection("mongodb://localhost:27071", "admin");
Console.WriteLine("Connection to mongodb://localhost:27071 was " + (isAlive ? "successful!" : "NOT successful!"));
will print out
Connection to mongodb://localhost:27071 was NOT successful!
Here a simple extension method to ping mongodb server
public static class MongoDbExt
{
public static bool Ping(this IMongoDatabase db, int secondToWait = 1)
{
if (secondToWait <= 0)
throw new ArgumentOutOfRangeException("secondToWait", secondToWait, "Must be at least 1 second");
return db.RunCommandAsync((Command<MongoDB.Bson.BsonDocument>)"{ping:1}").Wait(secondToWait * 1000);
}
}
You can use it like so:
var client = new MongoClient("yourConnectionString");
var database = client.GetDatabase("yourDatabase");
if (!database.Ping())
throw new Exception("Could not connect to MongoDb");
This is a solution by using the try-catch approach,
var database = client.GetDatabase("YourDbHere");
bool isMongoConnected;
try
{
await database.RunCommandAsync((Command<BsonDocument>)"{ping:1}");
isMongoConnected = true;
}
catch(Exception)
{
isMongoConnected = false;
}
so when it fails to connect to the database, it will throw an exception and we can handle our bool flag there.
If you want to handle connection issues in your program you can use the ICluster.Description event.
When the MongoClient is created, it will continue to attempt connections in the background until it succeeds.
using MongoDB.Driver;
using MongoDB.Driver.Core.Clusters;
var mongoClient = new MongoClient("localhost")
mongoClient.Cluster.DescriptionChanged += Cluster_DescriptionChanged;
public void Cluster_DescriptionChanged(object sender, ClusterDescriptionChangedEventArgs e)
{
switch (e.NewClusterDescription.State)
{
case ClusterState.Disconnected:
break;
case ClusterState.Connected:
break;
}
}

IPC Cannot Find the File Specified

using IPC over local TCP to communicate from Client to a Server thread. The connection itself doesn't seem to be throwing any errors, but every time I try to make one of the associated calls, I get this message:
System.Runtime.Remoting.RemotingException: Could not connect to an IPC Port: The System cannot Find the file specified
What I am attempting to figure out is WHY. Because this WAS working correctly, until I transitioned the projects in question (yes, both) from .NET 3.5 to .NET 4.0.
Listen Code
private void ThreadListen()
{
_listenerThread = new Thread(Listen) {Name = "Listener Thread", Priority = ThreadPriority.AboveNormal};
_listenerThread.Start();
}
private void Listen()
{
_listener = new Listener(this);
LifetimeServices.LeaseTime = TimeSpan.FromDays(365);
IDictionary props = new Hashtable();
props["port"] = 63726;
props["name"] = "AGENT";
TcpChannel channel = new TcpChannel(props, null, null);
ChannelServices.RegisterChannel(channel, false);
RemotingServices.Marshal(_listener, "Agent");
Logger.WriteLog(new LogMessage(MethodBase.GetCurrentMethod().Name, "Now Listening for commands..."));
LogEvent("Now Listening for commands...");
}
Selected Client Code
private void InitializeAgent()
{
try
{
_agentController =
(IAgent)RemotingServices.Connect(typeof(IAgent), IPC_URL);
//Note: IPC_URL was originally "ipc://AGENT/AGENT"
// It has been changed to read "tcp://localhost:63726/Agent"
SetAgentPid();
}
catch (Exception ex)
{
HandleError("Unable to initialize the connected agent.", 3850244, ex);
}
}
//This is the method that throws the error
public override void LoadTimer()
{
// first check to see if we have already set the agent process id and set it if not
if (_agentPid < 0)
{
SetAgentPid();
}
try
{
TryStart();
var tries = 0;
while (tries < RUNCHECK_TRYCOUNT)
{
try
{
_agentController.ReloadSettings();//<---Error occurs here
return;
} catch (RemotingException)
{
Thread.Sleep(2000);
tries++;
if (tries == RUNCHECK_TRYCOUNT)
throw;
}
}
}
catch (Exception ex)
{
HandleError("Unable to reload the timer for the connected agent.", 3850243, ex);
}
}
If you need to see something I haven't shown, please ask, I'm pretty much flying blind here.
Edit: I think the issue is the IPC_URL String. It is currently set to "ipc://AGENT/AGENT". The thing is, I have no idea where that came from, why it worked before, or what might be stopping it from working now.
Update
I was able to get the IPC Calls working correctly by changing the IPC_URL String, but I still lack understanding of why what I did worked. Or rather, why the original code stopped working and I needed to change it in the first place.
The string I am using now is "tcp://localhost:63726/Agent"
Can anyone tell me, not why the new string works, I know that...but Why did the original string work before and why did updating the project target to .NET 4.0 break it?

IPGlobalProperties.GetIPGlobalProperties

I wrote a test app to get all active ports on my network. Did some searching and found this was the easiest way. So I tried it and it work just fine. I then wrote another socket app with a sever and client side. It's pretty basic, has a create sever, join server and refresh button to get the active servers. The only time this method gets called is when you press the refresh button. If I open up the application 3 or more times and create a server with connected clients by the 4th one this method starts giving me this (Unknown error (0xc0000001)) error. Any idea why this could happen? Funny thing is I never get this on the initial application, the one I opened first. I don't know if somehow it get's a lock on this or something.
The exception gets thrown at this line:
IPEndPoint[] endPoints = properties.GetActiveTcpListeners();
Here's the method, it returns an object of List for all ports within a min and max range.
public static List<UserLocalSettings> ShowActiveTcpListeners(int min, int max)
{
List<UserLocalSettings> res = new List<UserLocalSettings>();
try
{
IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] endPoints = properties.GetActiveTcpListeners();
foreach (IPEndPoint e in endPoints)
{
if (e.Port > (min - 1) && e.Port < (max + 1))
{
UserLocalSettings tmpClnt = new UserLocalSettings();
tmpClnt.player_ip = e.Address.ToString();
tmpClnt.player_port = e.Port;
tmpClnt.computer_name = Dns.GetHostEntry(e.Address).HostName;
res.Add(tmpClnt);
}
}
}
catch (Exception ex1)
{
}
return res;
}
Here's a screen print of the exception:

Get All Processes With Their Corresponding App Domains

Is it possible to get a list of the running processes along with their corresponding app domains when running a program? I am aware mscoree.dll allows me to retrieve all App Domains of the current process using the ICorRuntimeHost.EnumDomains method. Is there a way to get this information without using an external API and just pure C# code? I understand mdbg has some functions that may help but I am not sure how to use this debugger. I am really looking for a solution using just C#.
Thanks
EDIT:
The goal is to show every process running along with their corresponding app domains on an html page. Ideally there would be a function that iterates through all running processes and retrieves this information.
Code that retrieves all app domains for current process:
private static List<AppDomainInf> GetAppDomains()
{
IList<AppDomain> mAppDomainsList = new List<AppDomain>();
List<AppDomainInf> mAppDomainInfos = new List<AppDomainInf>();
IntPtr menumHandle = IntPtr.Zero;
ICorRuntimeHost host = new CorRuntimeHost();
try
{
host.EnumDomains(out menumHandle);
object mTempDomain = null;
//add all the current app domains running
while (true)
{
host.NextDomain(menumHandle, out mTempDomain);
if (mTempDomain == null) break;
AppDomain tempDomain = mTempDomain as AppDomain;
mAppDomainsList.Add((tempDomain));
}
//retrieve every app domains detailed information
foreach (var appDomain in mAppDomainsList)
{
AppDomainInf domainInf = new AppDomainInf();
domainInf.Assemblies = GetAppDomainAssemblies(appDomain);
domainInf.AppDomainName = appDomain.FriendlyName;
mAppDomainInfos.Add(domainInf);
}
return mAppDomainInfos;
}
catch (Exception)
{
throw; //rethrow
}
finally
{
host.CloseEnum(menumHandle);
Marshal.ReleaseComObject(host);
}
}
using MdbgCore.dll located inside C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\MdbgCore.dll.:
CorPublish cp = new CorPublish();
foreach (CorPublishProcess process in cp.EnumProcesses())
{
foreach (CorPublishAppDomain appDomain in process.EnumAppDomains())
{
}
}

Categories