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
Related
If I launch my app without command line parameters, then supply a computer to connect to, everything works ok.
If I configure debug mode with a command line parameter, and launch the application, it works ok.
If I launch the application with command line parameters outside of visual studio, then there are issues...
If I do not Ping the machine to make sure that it is there (passed on the command line) by commenting out the code that does it, there are no issues...
If I leave it the code to ping a machine, I have issues when running from the command line with parameters...
I get the same issues if I search AD for the machine...
The errors I am getting from ping appears to be a DNS issue as it returns host not found.
The errors I am getting from the AD check is Network path not found.
I have launched a "MessageBox.Show("\""+Host\"\"");" just before doing the check and the parameter being passed is correct.
Any ideas?
I'm running Visual Studio 2015 and compiling using AnyCPU and .Net 4.6.1
Here is my PingComputer and ComputerExistsInAD code:
public static bool PingComputer(string SystemName, int Timeout = 5000)
{
try { return (new Ping()).Send(SystemName, Timeout).Status == IPStatus.Success; } catch { }
return false;
}
public static bool ComputerExistsInAD(string SystemName)
{
try
{
PrincipalContext Context = new PrincipalContext(ContextType.Domain, Environment.UserDomainName);
ComputerPrincipal Principal = new ComputerPrincipal(Context);
Principal.Name = SystemName;
PrincipalSearcher Searcher = new PrincipalSearcher();
Searcher.QueryFilter = Principal;
return Searcher.FindOne() != null;
}
catch { }
return false;
}
Seems to be an issue with .Net 4.6.1... I went back to 4.5.2, and now it works without any other changes...
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())
{
}
}
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);
...
I'm building a small web application with ASP.NET MVC 2, using db4o as a datastore.
I have added an HttpModule—as per the example here—to give the application access to the db4o database, and everything is working perfectly on my development machine under the VS2008 ASP.NET Development Server.
However, when I deploy the app to my web host and try to access it, I get a DatabaseFileLockedException at the line where the HttpModule tries to open the database file. But there should be nothing else accessing the file; indeed on first run of the app it will only just have been created when this exception gets thrown.
The web host's servers are running IIS 7 on Windows Server 2008, and the application is running under Full Trust. It is a sub-application, in case that makes any difference.
I can't work out why this error is occurring on the live server, but not locally on my development server. Can anyone help me out or suggest what I should do next?
That's a mistake in the example-code. It assumes that the HttpModule.Init is only called once, which isn't necessarily true. Depending how your application is configured, it can be called multiple times. To fix this, check in the HttpModule-Handler if the instance is already there:
using System;
using System.Configuration;
using System.Web;
using Db4objects.Db4o;
namespace Db4oDoc.WebApp.Infrastructure
{
public class Db4oProvider : IHttpModule
{
private const string DataBaseInstance = "db4o-database-instance";
private const string SessionKey = "db4o-session";
// #example: open database when the application starts
public void Init(HttpApplication context)
{
if (null==HttpContext.Current.Application[DataBaseInstance])
{
HttpContext.Current.Application[DataBaseInstance] = OpenDatabase();
}
RegisterSessionCreation(context);
}
private IEmbeddedObjectContainer OpenDatabase()
{
string relativePath = ConfigurationSettings.AppSettings["DatabaseFileName"];
string filePath = HttpContext.Current.Server.MapPath(relativePath);
return Db4oEmbedded.OpenFile(filePath);
}
// #end example
// #example: close the database when the application shuts down
public void Dispose()
{
IDisposable toDispose = HttpContext.Current.Application[DataBaseInstance] as IDisposable;
if (null != toDispose)
{
toDispose.Dispose();
}
}
// #end example
// #example: provide access to the database
public static IObjectContainer Database
{
get { return (IObjectContainer)HttpContext.Current.Items[SessionKey]; }
}
// #end example
// #example: A object container per request
private void RegisterSessionCreation(HttpApplication httpApplication)
{
httpApplication.BeginRequest += OpenSession;
httpApplication.EndRequest += CloseSession;
}
private void OpenSession(object sender, EventArgs e)
{
IEmbeddedObjectContainer container =
(IEmbeddedObjectContainer)HttpContext.Current.Application[DataBaseInstance];
IObjectContainer session = container.OpenSession();
HttpContext.Current.Items[SessionKey] = session;
}
private void CloseSession(object sender, EventArgs e)
{
if (HttpContext.Current.Items[SessionKey] != null)
{
IObjectContainer session = (IObjectContainer)HttpContext.Current.Items[SessionKey];
session.Dispose();
}
}
// #end example
}
}
As alternative you could use the Application_Start from the Global.apsx, which is called only once for sure.
You have another problem here.
When AppPools restart there can be an overlap when the old AppPool is finishing request and the new AppPool is servicing new requests.
During this time you will have two processes trying to access the same db4o file
To get around this you can use something like the hack below.
Note the use of Db4oFactory.OpenServer instead of Db4oEmbedded.OpenFile. This allows the use of transactions on a more fine grained basis.
public IObjectServer OpenServer()
{
Logger.Debug("Waiting to open db4o server.");
var attempts = 0;
do
{
try
{
return Db4oFactory.OpenServer(fileName, 0);
}
catch (DatabaseFileLockedException ex)
{
attempts++;
if (attempts > 10)
{
throw new Exception("Couldn't open db4o server. Giving up!", ex);
}
Logger.Warn("Couldn't open db4o server. Trying again in 5sec.");
Thread.Sleep(5.Seconds());
}
} while (true);
}
Hope this helps
Sounds like permission issues if it works on dev. Stick a notepad file in the same directory and try to open that with some bare bones file code. I bet you'll have the same issue.
For a project I have to start an application in C#, rip out the AutomationElement tree related to the process, and then close the application and output the tree. I'm doing this by opening the application using Process.Start. Then I'm finding the AutomationElements related to the spawned process and walking the tree using a combination of TreeWalker and AutomationElement's FindFirst and FindAll methods.
This runs fine on my computer and runs correctly using NUnit locally. It also runs on the other people in my groups computers. The problem is that it never runs on our central testing server that's running Hudson. After some hours of debugging, I had a test on Hudson start the application and then print the first level of the AutomationTree. On my computer, this prints all of the windows I have on my desktop. On Hudson, this only prints the Desktop.
Thinking there might be multiple desktops, I tried using TreeWalker's GetNextSibling function on the RootElement. It still only reported one desktop.
Here's the code I'm using to start a process.
public bool connect(string[] args)
{
if (this.process != null) {
Console.WriteLine("ERROR: Process already connected");
return false;
}
if (!File.Exists(sApplicationPath)) {
Console.WriteLine(sApplicationPath + " does not exist");
return false;
}
// Turn the command arguments into a single string
string arguments = "";
foreach (string arg in args) {
arguments += arg + " ";
}
try {
// Start the application
ProcessStartInfo processStartInfo =
new ProcessStartInfo(sApplicationPath);
processStartInfo.Arguments = arguments;
this.process = Process.Start(processStartInfo);
// Must be a positive integer (non-zero)
if ( !( iInitialDelay > 0 ) ) {
Console.WriteLine("Invalid initial delay. " +
"Defaulting to 5 seconds.");
this.iInitialDelay = 5000;
}
Thread.Sleep(this.iInitialDelay);
} catch (Exception ex) {
Console.WriteLine("WGApplication.connect: " + ex.Message);
return false;
}
// Check if the process still exists
try {
/** This part does not return an error, so I think that means the process exists and is started */
Process check = Process.GetProcessById(process.Id);
} catch (ArgumentException ex) {
Console.WriteLine("The process expired before connection was complete");
Console.WriteLine("Make sure the process is not open anywhere else");
Console.WriteLine("and that it is able to execute on the host machine.");
return false;
}
// Check if the base automation element exists to verify open
AutomationElement rootWindow =
AutomationElement.RootElement.FindChildProcessById(process.Id);
/** This part returns null, so it can't find the window associated with this process id */
if (this.process == null) {
return false;
} else if (rootWindow == null) {
// A root window with this process id has not been found
Console.WriteLine("Cannot find the root window of the created " +
"process. Unknown error.");
return false;
} else {
// Everything is good to go
return true;
}
}
sApplicationPath is set to the absolute path of the executable. iInitialDelay is a delay to make sure the application has time to start. I'm running this on 'C:\Windows\System32\notepad.exe' on Windows Vista SP2 and compiling it with the v3.5 C# compiler.
FindChildProcessById is defined as follows:
public static AutomationElement FindChildProcessById(
this AutomationElement element, int processId)
{
var result = element.FindChildByCondition(
new PropertyCondition(AutomationElement.ProcessIdProperty,
processId));
return result;
}
Remember that this compiles and works on my computer. My test program on Hudson said that the RootElement had no children at all.
So I start the application, confirm it exists, and then I can't find any windows associated with the process. I can't find any windows associated with anything except the desktop.
Is this a problem with Hudson? Does Hudson work in some specific way that this code wouldn't work on it? Is it a problem with my code? The Hudson server is running on a Windows Server 2003 computer. Any help would be appreciated. I know this is a very specific problem which is a reason why I can't find any solutions online.
Is Hudson running as a service? If so, it may not have the necessary rights to show windows.