check the status of IIS Application Pool - c#

I am developing a windows service which will gets the IIS Application Pool status information in every 5 min and stored in database or text file ... like running or stopped.
Getting below exception message:
An exception of type 'System.UnauthorizedAccessException' occurred in Microsoft.Web.Administration.dll but was not handled in user code Additional information: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
Below is the code I have tried:
static void Main(string[] args)
{
const double interval60Minutes = 5 * 5 * 1000; // milliseconds to one hour
Timer checkForTime = new Timer(interval60Minutes);
checkForTime.Elapsed += new ElapsedEventHandler(checkForTime_Elapsed);
checkForTime.Enabled = true;
Console.WriteLine("Waiting..");
Console.ReadLine();
}
public static void checkForTime_Elapsed(object sender, ElapsedEventArgs e)
{
GetApplicationPoolNames();
}
public static string GetApplicationPoolNames()
{
ServerManager manager = new ServerManager();
string status;
//string DefaultSiteName = System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName();
//Site defaultSite = manager.Sites[DefaultSiteName];
string appVirtaulPath = HttpRuntime.AppDomainAppVirtualPath;
string mname = System.Environment.MachineName;
string appPoolName = string.Empty;
manager = ServerManager.OpenRemote(mname);
ObjectState result = ObjectState.Unknown;
ApplicationPoolCollection applicationPoolCollection = manager.ApplicationPools;
foreach (ApplicationPool applicationPool in applicationPoolCollection)
{
//result = manager.ApplicationPools[appPoolName].State;
result = applicationPool.State; *// here exception occures*
Console.WriteLine("State : " + result);
Console.ReadLine();
}
}
What is wrong in the code? If there are any other ways to achieve this please provide as that will also help me to understand the main cause of exception message.
Any help is appreciated.
Thanks.

The asked question was too old but thought to share the solution which might help someone to resolve this kind of error/exception occurs when trying to get/read the IIS App Pool info of the server.
To resolve the Unauthorized Access Exception while trying to access the IIS info, First provide server credentials using DirectoryEntry Class like below -
DirectoryEntries appPools = new DirectoryEntry("IIS://" + ServerName + "/W3SVC/AppPools", UName, Pwd).Children;
This will give the access of IIS of the respective server.
So, The complete GetApplicationPoolNames() method after modification is -
public static string GetApplicationPoolNames()
{
// Get Server Credentials and Server Name from config file
string UName = ConfigurationManager.AppSettings["User"];
string Pwd = ConfigurationManager.AppSettings["Pass"];
string ServerName = DT.Rows[i]["ServerName"].ToString().Trim(); //Server Names from db
DirectoryEntries appPools = null;
try
{
appPools = new DirectoryEntry("IIS://" + ServerName + "/W3SVC/AppPools", UName, Pwd).Children;
}
catch(Exception ex)
{
log.ErrorFormat("serviceLogic -> InsertStatus() -> IIS Pool App Region -> DirectoryEntries -> Error: ", ex.Message.ToString());
}
log.Info("IIS App Pool Section Started for " + System.Environment.MachineName.ToString());
try
{
foreach (DirectoryEntry appPool in appPools)
{
log.Info("App Pool : " + appPool.Name.ToString());
int intStatus = 0;
string status = "";
try
{
if (appPool.Name.ToString().ToLower().Trim() == DT.Rows[i]["AppPoolSrvName"].ToString().ToLower().Trim())
{
log.Info("Process Started for App Pool : " + appPool.Name.ToString());
intStatus = (int)appPool.InvokeGet("AppPoolState");
switch (intStatus)
{
case 2:
status = "Running";
break;
case 4:
status = "Stopped";
break;
default:
status = "Unknown";
break;
}
//Store status info to db or file Logic goes here..
//Start App pool, If any application pool status is not Running.
if (status != "Running")
appPool.Invoke("Start", null);
log.Info("Process Completed for App Pool : " + appPool.Name.ToString());
}
}
catch (Exception ex)
{
log.ErrorFormat("serviceLogic -> InsertStatus() -> IIS Pool App Region -> Error: ", ex.Message);
}
}
}
catch (Exception ex)
{
log.ErrorFormat("serviceLogic -> InsertStatus() -> IIS Pool App Region -> DirectoryEntries -> Error: ", ex.Message);
}
}

Related

How to access the username and password from appsettings file to program.cs in c# [duplicate]

This question already has answers here:
Getting value from appsettings.json in .net core
(23 answers)
Closed 1 year ago.
I am implementing a console application to build application pool status.I referred check the status of IIS Application Pool of getting the username and password from database,I wanted to get them from appsettings.json.
The problem I am having is the value (the username jandi) doesn't pass to the program.cs, it passes a null value.
I have included my code.
program.cs
using Serilog;
using System;
using System.Configuration;
using System.DirectoryServices;
using System.Timers;
namespace processstatus
{
class Program
{
static void Main(string[] args)
{
const double interval60Minutes = 5 * 5 * 1000; // milliseconds to one hour
Timer checkForTime = new Timer(interval60Minutes);
checkForTime.Elapsed += new ElapsedEventHandler(checkForTime_Elapsed);
checkForTime.Enabled = true;
Console.WriteLine("Waiting..");
Console.ReadLine();
}
public static void checkForTime_Elapsed(object sender, ElapsedEventArgs e)
{
GetApplicationPoolNames();
}
public static string GetApplicationPoolNames()
{
string UName = ConfigurationManager.AppSettings["User"];
string Pwd = ConfigurationManager.AppSettings["Pass"];
string ServerName = ConfigurationManager.AppSettings["Server"];
DirectoryEntries appPools = null;
try
{
appPools = new DirectoryEntry("IIS://" + ServerName + "/W3SVC/AppPools", UName, Pwd).Children;
}
catch (Exception ex)
{
Log.Error("serviceLogic -> InsertStatus() -> IIS Pool App Region -> DirectoryEntries -> Error: ", ex.Message.ToString());
}
Log.Information("IIS App Pool Section Started for " + System.Environment.MachineName.ToString());
try
{
foreach (DirectoryEntry appPool in appPools)
{
Log.Information("App Pool : " + appPool.Name.ToString());
int intStatus = 0;
string status = "";
try
{
if (appPool.Name.ToString().ToLower().Trim() == ConfigurationManager.AppSettings["Server"].ToString().ToLower().Trim())
{
Log.Information("Process Started for App Pool : " + appPool.Name.ToString());
intStatus = (int)appPool.InvokeGet("AppPoolState");
switch (intStatus)
{
case 2:
status = "Running";
break;
case 4:
status = "Stopped";
break;
default:
status = "Unknown";
break;
}
//Store status info to db or file Logic goes here..
//Start App pool, If any application pool status is not Running.
if (status != "Running")
appPool.Invoke("Start", null);
Log.Information("Process Completed for App Pool : " + appPool.Name.ToString());
}
}
catch (Exception ex)
{
Log.Error("serviceLogic -> InsertStatus() -> IIS Pool App Region -> Error: ", ex.Message);
}
}
}
catch (Exception ex)
{
Log.Error("serviceLogic -> InsertStatus() -> IIS Pool App Region -> DirectoryEntries -> Error: ", ex.Message);
}
return "Message";
}
}
}
Appsettings.json file
{
"AppSettings": {
"User": "jandi",
"Pass": "jandi123",
"Server": "abc"
}
}
Can someone please let me know the error in the above code?
For .NET Core console apps, you can use Microsoft.Extensions.Configuration to read appsettings.json files, as has been already pointed out in the comments. I've used this a couple of times and it seems to work just fine. You can then use something like this in your Program class:
private static IConfiguration _configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", true, true)
.Build();
You can then read the appsettings variables via the _configuration variable.

How To Tell If WCF Service Is Running At Host?

I have a C# application that is self hosting a WCF service. I want to add a button click event in the application that lets the user know if the service is running/being hosted. Is there a way to detect if the service is running/hosted?
In case someone wants to see it, here is the code I am using to start hosting the service:
private static void RunService()
{
System.ServiceModel.ServiceHost host = new System.ServiceModel.ServiceHost(typeof(AccountingOperationsService.AccountingOperationsService));
System.ServiceModel.Description.ServiceDebugBehavior debug = host.Description.Behaviors.Find<System.ServiceModel.Description.ServiceDebugBehavior>();
// if not found - add behavior with setting turned on
if (debug == null)
{
host.Description.Behaviors.Add(
new System.ServiceModel.Description.ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
}
else
{
// make sure setting is turned ON
if (!debug.IncludeExceptionDetailInFaults)
{
debug.IncludeExceptionDetailInFaults = true;
}
}
try
{
host.Open();
}
catch (Exception ex)
{
string errorMessage = ex.Message + Environment.NewLine;
errorMessage += ex.StackTrace + Environment.NewLine;
DevExpress.XtraEditors.XtraMessageBox.Show(errorMessage, "Error Starting Service", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Perhaps, you need create method Ping in wcf service.
public bool Ping()
{
return true;
}
and in application call Ping
bool itsWork;
try
{
itsWork = service.Ping();
}
catch(Exception ex){}

ClickOnce + Restart = Opens Browser?

I'm deploying a ClickOnce Application and want to restart the application after it was updated. Therefore I wrote following code:
private async void updateCheck()
{
using (var releaser = await _asyncLock.LockAsync())
{
UpdateCheckInfo info = null;
bool updateAvailable = false;
if (ApplicationDeployment.IsNetworkDeployed)
{
ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
ad.UpdateCompleted += new System.ComponentModel.AsyncCompletedEventHandler(Ad_UpdateCompleted);
try
{
updateAvailable = ad.CheckForUpdate(false);
info = ad.CheckForDetailedUpdate();
}
catch (DeploymentDownloadException dde)
{
MessageBox.Show("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
return;
}
catch (InvalidDeploymentException ide)
{
MessageBox.Show("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
return;
}
catch (InvalidOperationException ioe)
{
MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
return;
}
if (/*info.UpdateAvailable*/ updateAvailable)
{
Boolean doUpdate = true;
if (!info.IsUpdateRequired)
{
MessageBoxResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButton.OKCancel);
if (!(MessageBoxResult.OK == dr))
{
doUpdate = false;
}
}
else
{
// Display a message that the app MUST reboot. Display the minimum required version.
MessageBox.Show("This application has detected a mandatory update from your current " +
"version to version " + info.MinimumRequiredVersion.ToString() +
". The application will now install the update and restart.",
"Update Available", MessageBoxButton.OK,
MessageBoxImage.Information);
}
if (doUpdate)
{
try
{
//ad.Update();
ad.UpdateAsync();
}
catch (DeploymentDownloadException dde)
{
MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
return;
}
}
}
}
}
}
private void Ad_UpdateCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error == null)
{
MessageBox.Show("The application has been upgraded, and will now restart.");
String ApplicationEntryPoint = ApplicationDeployment.CurrentDeployment.UpdatedApplicationFullName;
Process.Start(ApplicationEntryPoint);
Application.Current.Shutdown();
}
}
Unfortunate in UpdatedApplicationFullName a URL to the Website where the deployment packages are stored. So Process.Start(ApplicationEntryPoint) opens a Browser Window and tries to download the package once again.
The behaviour I want is that the Process.Start(...) opens the new updated application.
Has anyone an idea what I'm doing wrong?
Thanks.

Problems with OleDbConnection when opening a c# form with command prompt or hyperlink, but not Windows Explorer

I have a c# program which does the following on form load:
Creates an OleDbConnection to a database in the same folder as the program
Gets the computer name
Gets the username
Fills in some textbox fields on the form with data obtained from the database
When I open the form using Windows explorer, shortcut, or debugging in visual studio express 2013, it does all of this without any issues. When trying to open it with a command prompt or with a hyperlink, the database connection is not established, but no error messages appear. The textbox fields are filled with "not found" as a result of my try-catch statements around the oledb commands. The same try-catch statement should print ex.message to a text file, but that does not happen either. As stated before, this all runs flawlessly when running from debug mode in vs or running the program by opening it in Windows explorer, so I'm not sure how to debug this.
2 questions - Is there a known problem with opening c# forms which try to establish OleDb connections with access databases on form load when launching the program from command prompt or a shortcut? If so, are there any workarounds? Given that it runs fine in debug mode in vs, and my catch statements seem to be terminating prematurely without error messages, is there any other way to debug and find out exactly where the problem occurs?
I left off some of the irrelevant lines of code to make this shorter.
private void Form1_Load(object sender, EventArgs e)
{
userData = onLoad.loadDb(out userNotFound);
ComputerName = onLoad.getComputer();
// Session Notification
WTSRegisterSessionNotification(this.Handle, NotifyForThisSession);
// Initialize Hooks
initialize_Hooks();
if (userData.Count < 4)
{
for(int i = 0; i<4; i++) { userData.Add("Not Found"); }
}
// globals:
FullID = userData[0];
ID = userData[2];
firstName = userData[1];
lastName = userData[0];
nanid = userData[3];
fullName = firstName + " " + lastName;
// Fill in Form
label1.Text = fullName;
label2.Text = ID;
label3.Text = nanid;
}
public class onLoad
{
public static string getUser() // returns Environment.UserName
public static string getComputer() // returns System.Environment.MachineName;
public static List<string> loadDb(out bool userNotFound)
{
List<string> rList = new List<string>();
string strAccessConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=db.mdb";
string strAccessSelect = "SELECT (//select statement which works fine when I open the program in explorer or vs debug)
DataSet myDataSet = new DataSet();
OleDbConnection myAccessConn = null;
try
{
myAccessConn = new OleDbConnection(strAccessConn);
}
catch(Exception ex)
{
for(int i = 0; i<4; i++) { rList.Add("Not Found"); }
error_handler.error_logger(ex.Message);
userNotFound = true;
return rList;
}
try
{
OleDbCommand myAccessCommand = new OleDbCommand(strAccessSelect, myAccessConn);
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter(myAccessCommand);
myAccessConn.Open();
myDataAdapter.Fill(myDataSet,"table1");
}
catch (Exception ex)
{
error_handler.error_logger(ex.Message);
userNotFound = true;
for(int i = 0; i<4; i++) { rList.Add("Not Found"); }
return rList;
}
finally
{
myAccessConn.Close();
}
try
{
DataRowCollection dra = myDataSet.Tables[0].Rows;
foreach (DataRow dr in dra)
{
code that conditions the data, works fine when running the program
}
}
catch(Exception ex)
{
string returnString = ex.Message;
error_handler.error_logger(ex.Message);
userNotFound = true;
for(int i = 0; i<4; i++) { rList.Add("Not Found"); }
return rList;
}
return rList;
}
}
class error_handler
{
public static string filename = "error.txt";
public static void error_logger(string error_message)
{
error_message = onLoad.getUser() + "\t" + DateTime.Now.ToString("MM/dd/yy hh:mm:ss") + "\t" + onLoad.getComputer() + "\t" + "Error: " + error_message;
if (!File.Exists(filename))
//writes error_message to a new text file or appends if it already exists. works fine when running from windows explorer or vs debug
}
}
I bet that shortcut passes in the working directory as a parameter. The documentation for File.Exists() states that when using a relative path the relative path information is interpreted as relative to the current working directory.
You can use the Directory.GetCurrentDirectory() function to determine if the path is set correctly.
If you are using files that you know are going to be in a path relative to the application I would use Application's path or at least set Environment.CurrentDirectory = Application's path.
Also take a look at the Environment.GetCommandLineArgs()[0]. That is probally being set by the shortcut.

C#: trying to set "ServerBindings" property of my website programatically, keeps crashing

I am trying to Configure my IIS programmatically following the steps on this
msdn guide
the only difference i made was switching to winforms instead of console..
and variables instead of function parameters.
however the code throws an exception when i try to set the singleproperty value...
here is my code..
string metabasePath = "IIS://localhost/W3SVC/1234", propertyName = "ServerBindings";
object newValue = " :8080:";
try
{
DirectoryEntry path = new DirectoryEntry(metabasePath);
//when i try to retrieve the old value,it returns a null
PropertyValueCollection propValues = path.Properties[propertyName];
MessageBox.Show("7");
//the code throws an exception after messagebox,
//kinda old school debuging
path.Properties[propertyName][0] = newValue;
path.CommitChanges();
lblerror.Text = "Done";
}
catch (Exception ex)
{
if ("HRESULT 0x80005006" == ex.Message)
lblerror.Text = " Property does not exist at ";
else
lblerror.Text = "Failed in SetSingleProperty "+ ex.Message.ToString();
}
The following 'helper' methods (SetServerBinding and RemoveServerBinding) should be of use:
static void Main(string[] args)
{
using(DirectoryEntry site = new DirectoryEntry("IIS://Localhost/W3SVC/1234"))
{
SetServerBinding(":8080:", site);
RemoveServerBinding(":8080:", site);
RemoveServerBinding("172.16.4.99:8087:somesite.com", site);
SetServerBinding("172.16.4.99:8087:somesite.com", site);
}
}
public static void SetServerBinding(string binding, DirectoryEntry site)
{
if(site.Properties["ServerBindings"].Contains(binding))
{
site.Properties["ServerBindings"].Remove(binding);
return;
}
site.Properties["ServerBindings"].Add(binding);
site.CommitChanges();
}
public static void RemoveServerBinding(string binding, DirectoryEntry site)
{
if (site.Properties["ServerBindings"].Contains(binding))
{
site.Properties["ServerBindings"].Remove(binding);
}
site.CommitChanges();
}

Categories