When programmatically creating a new IIS web site, how can I add it to an existing application pool? - c#

I have successfully automated the process of creating a new IIS website, however the code I've written doesn't care about application pools, it just gets added to DefaultAppPool. However I'd like to add this newly created site to an existing application pool.
Here is the code I'm using to create the new website.
var w3Svc = new DirectoryEntry(string.Format("IIS://{0}/w3svc", webserver));
var newsite = new object[] { serverComment, new object[] { serverBindings }, homeDirectory };
var websiteId = w3Svc.Invoke("CreateNewSite", newsite);
site.Invoke("Start", null);
site.CommitChanges();
<update>
Although this is not directly related to the question, here are some sample values being used above. This might help someone understand exactly what the code above is doing more easily.
webServer: "localhost"
serverComment: "testing.dev"
serverBindings: ":80:testing.dev"
homeDirectory: "c:\inetpub\wwwroot\testing\"
</update>
If I know the name of the application pool that I'd like this web site to be in, how can I find it and add this site to it?

You have to assign the AppPool on the virtual dir (not the webserver) and set the AppIsolated property to 2 which mean pooled-process ;)
http://msdn.microsoft.com/en-us/library/ms525598%28v=VS.90%29.aspx
Relevant code sample from link:
static void AssignVDirToAppPool(string metabasePath, string appPoolName)
{
// metabasePath is of the form "IIS://<servername>/W3SVC/<siteID>/Root[/<vDir>]"
// for example "IIS://localhost/W3SVC/1/Root/MyVDir"
// appPoolName is of the form "<name>", for example, "MyAppPool"
Console.WriteLine("\nAssigning application {0} to the application pool named {1}:", metabasePath, appPoolName);
try
{
DirectoryEntry vDir = new DirectoryEntry(metabasePath);
string className = vDir.SchemaClassName.ToString();
if (className.EndsWith("VirtualDir"))
{
object[] param = { 0, appPoolName, true };
vDir.Invoke("AppCreate3", param);
vDir.Properties["AppIsolated"][0] = "2";
Console.WriteLine(" Done.");
}
else
Console.WriteLine(" Failed in AssignVDirToAppPool; only virtual directories can be assigned to application pools");
}
catch (Exception ex)
{
Console.WriteLine("Failed in AssignVDirToAppPool with the following exception: \n{0}", ex.Message);
}
}
Note that if you are not explicitly adding a new virtual directory to the application, the metabasePath will simply be "IIS://<servername>/W3SVC/<siteID>/Root"

You need to get the AppPoolfrom IIS://{0}/W3SVC/AppPools, and attach it to the site's AppPoolId. Something like:
var appPool = new DirectoryEntry(
string.Format("IIS://{0}/W3SVC/AppPools/{1}", webServer, appPoolName)
);
site.Properties["AppPoolId"].Value = appPool;

site.Properties["AppPoolId"][0]= "poolname";

Related

Quartz.net as service can't configure the quartz_job.xml

When using
var properties = new NameValueCollection();
properties["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin";
properties["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin";
properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";
properties["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true";
properties["quartz.plugin.jobInitializer.scanInterval"] = "120";
// First we must get a reference to a scheduler
_schedulerFactory = new StdSchedulerFactory(properties);
_scheduler = _schedulerFactory.GetScheduler();
The windows service / quartz cannot resolve the path of quartz_jobs.xml.
If i run this as console it works fine.
public static void StartJobs()
{
try
{
_logger = LogManager.GetCurrentClassLogger();
var properties = new NameValueCollection();
properties["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin";
properties["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin";
properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";
properties["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true";
properties["quartz.plugin.jobInitializer.scanInterval"] = "120";
// First we must get a reference to a scheduler
_schedulerFactory = new StdSchedulerFactory(properties);
_scheduler = _schedulerFactory.GetScheduler();
// start the schedule
_scheduler.Start();
}
catch (Exception ex)
{
_logger.Error(ex);
throw new Exception(ex.Message);
}
}
If it's still not working, include the file as an embedded resource in the project, set the action to Copy always, to be sure. Then provide the full file path to the quartz property:
Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "quartz_jobs.xml")
I know this thread is from 2015, but i can't find any information regarding using quartz.net in a windows service. In my case, I am using .Net Core 2.1 Generic Host as a windows service with the quartz_jobs.xml which is referenced in my appsettings.json file. When the windows service starts up an looks for the quartz_job.xml it tries to find it in c:\windows\system32. But my quartz_job.xml is located where my executable is located. I tracked down Method ResolveFile in Quaztz\Util\FileUtil.cs of their repo where is says to put a "~" to for relative file. So I changed my appsettings.json to
"plugin": {
"jobInitializer": {
"type": "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins",
"fileNames": "~\\quartz_jobs.xml"
}
and now the windows service is able to read the quartz_jobs.xml. I would expect the if you change
properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";
to
properties["quartz.plugin.jobInitializer.fileNames"] = "~\\quartz_jobs.xml";
it should also work.

How to programmatically set App Pool Identity on IIS 8

I'm running Windows Server 2012 with IIS 8. I have IIS 6 Metabase Compatibility installed. I have been trying to figure out how to change the App Pool Identity for IIS 8 with .Net 4.5 - all of the examples I found are for IIS 6 and 7.
Here is what I have:
public class InternetInformationServices
{
public void SetApplicationPoolIdentity(string appPoolName, string domain, string username, string password)
{
try
{
string metabasePath = "IIS://Localhost/W3SVC/AppPools";
DirectoryEntry myAppPool;
DirectoryEntry apppools = new DirectoryEntry(metabasePath);
myAppPool = apppools.Children.Find(appPoolName, "IIsApplicationPool");
myAppPool.Invoke("AppPoolIdentityType", new Object[] { 3 });
myAppPool.Invoke("WAMUserName", new Object[] { domain + #"\" + username });
myAppPool.Invoke("WAMUserPass", new Object[] { password });
myAppPool.Invoke("SetInfo", null);
myAppPool.CommitChanges();
}
catch (Exception)
{
throw;
}
}
}
The code is able to find the App Pool, but as soon as I invoke it to set any of the following:
myAppPool.Invoke("AppPoolIdentityType", new Object[] { 3 });
myAppPool.Invoke("WAMUserName", new Object[] { domain + #"\" + username });
myAppPool.Invoke("WAMUserPass", new Object[] { password });
I get the following error on the inner exception:
Value does not fall within the expected range.
I'm not sure what I'm missing, or what is different with IIS 8.
Here's a way to get this type of code snippet for most things in the iis metabase. we use this process to script automation at my office.
I'll use your question about specifying credentials as an example:
open inetmgr first and then select your hostname and then open the config.
then select the system.applicationHost/applicationPools config section and expand the app pools collection, when done exit the window:
select the appropriate application pool, change the identitytype to specific user and set the user and pass.
Now click on Generate script, do not apply changes.
FINALLY: All the api goodness you wanted, including your sample code:
Try this ( from How can I change the username/password of an ApplicationPool in IIS from C#? )
myAppPool .Properties["AppPoolIdentityType"].Value = 3;
myAppPool .Properties["WAMUserName"].Value = Environment.MachineName + #"\" + username;
myAppPool .Properties["WAMUserPass"].Value = password;

Assign application pool to website in iis7 programmatically

I'm using the following method to create application pool and assign it to web site.
This is code for application pool creation:
WebSiteName = some website name which existed.
I see that all values are get where they should be in debug mode
private void ConfiugreAppPoolIIS7(targetMachine)
{
var mgr = ServerManager.OpenRemote(targetMachine);
if (AppPoolProp.ContainsKey("SomeTestAppPool"))
{
string reqAppPool = AppPoolProp["SomeTestAppPool"];
if (!mgr.ApplicationPools.Any(pool => pool.Name == reqAppPool))
{
ApplicationPool myApp = mgr.ApplicationPools.Add(reqAppPool);
myApp.AutoStart = true;
myApp.ManagedPipelineMode = ManagedPipelineMode.Classic;
myApp.ManagedRuntimeVersion = "V4.0";
myApp.ProcessModel.IdentityType = ProcessModelIdentityType.NetworkService;
myApp.Enable32BitAppOnWin64 = true;
mgr.CommitChanges();
foreach (Site site in mgr.Sites)
{
if(site.Name == WebSiteName)
{
site.Stop();
site.ApplicationDefaults.ApplicationPoolName = myApp.Name;
site.Start();
mgr.CommitChanges();
}
}
}
}
}
The result is, I see the Aplication pool created successfuly, and the Website created as well, but, I see in the advanced settings of my web site the default appplication pool is assigned.
Could you please help?
The problem has been fixed by fixing reference to right Microsoft.Web.Administration.dll
Cause of this server manage connected to express iis instead of my local iis.

Create Web IIS Virtual Directory using C# in particular web site

public void CreateVirtualDirectory(string nameDirectory, string realPath)
{
System.DirectoryServices.DirectoryEntry oDE;
System.DirectoryServices.DirectoryEntries oDC;
System.DirectoryServices.DirectoryEntry oVirDir;
try
{
oDE = new DirectoryEntry("IIS://" + this._serverName + "/W3SVC/1/Root");
//Get Default Web Site
oDC = oDE.Children;
//Add row
oVirDir = oDC.Add(nameDirectory, oDE.SchemaClassName.ToString());
//Commit changes for Schema class File
oVirDir.CommitChanges();
//Create physical path if it does not exists
if (!Directory.Exists(realPath))
{
Directory.CreateDirectory(realPath);
}
//Set virtual directory to physical path
oVirDir.Properties["Path"].Value = realPath;
//Set read access
oVirDir.Properties["AccessRead"][0] = true;
//Create Application for IIS Application (as for ASP.NET)
oVirDir.Invoke("AppCreate", true);
oVirDir.Properties["AppFriendlyName"][0] = nameDirectory;
//Save all the changes
oVirDir.CommitChanges();
}
catch (Exception ex)
{
throw ex;
}
}
This above function work fine _serverName = "localhost" but this always create virtual directory in Default Web Site in IIS. While I have another sample site created with name MySite on localhost:8080. so when I put _serverName = "localhost:8080" it gives me error.
This line:
oDE = new DirectoryEntry("IIS://" + this._serverName + "/W3SVC/1/Root");
Always assumes the default web site. The "1" is the ID of the website. Replace the "1" with the ID of the site you want to create the virtual directory in. You can find the site ID in the IIS here:
You can, if you desire, enumerate all of the websites programmatically using Directory Services as well to help you find the right ID:
DirectoryEntry w3svc = new DirectoryEntry("IIS://" + this._serverName + "/w3svc");
foreach(DirectoryEntry de in w3svc.Children)
{
if(de.SchemaClassName == "IIsWebServer")
{
var id = de.Name; //Name is the ID
var displayName = de.Properties["ServerComment"].Value.ToString();
}
}
Each WebSite has a different Id - the LDAP address of the "MySite" is probably something like this:
IIS://" + this._serverName + "/W3SVC/**2**/Root

Can I obtain the ClickOnce published Product Name from inside the application?

I have a ClickOnce Publish Name that is different from the assembly name. For discussion purposes, it is "App 6.0". I set it in the Properties for my project. Is there any way to get this value from inside the program?
Add a reference to Microsoft.Build.Tasks.v4.0.dll, then run this:
if (null != AppDomain.CurrentDomain.ActivationContext)
{
DeployManifest manifest;
using (MemoryStream stream = new MemoryStream(AppDomain.CurrentDomain.ActivationContext.DeploymentManifestBytes))
{
manifest = (DeployManifest)ManifestReader.ReadManifest("Deployment", stream, true);
}
// manifest.Product has the name you want
}
else
{
// not deployed
}
The DeployManifest can also provide other useful info from your manifest, like Publisher or SupportUrl.
The answer can be found in ClickOnce Run at Startup. Essentially, you use InPlaceHostingManager to get the ClickOnce manifest and read it. It bugs me that it is an asynchronous method, but this is the only thing that has worked thus far. Simplifications are much appreciated. See the webpage for a description of DeploymentDescription.
var inPlaceHostingManager = new InPlaceHostingManager(ApplicationDeployment.CurrentDeployment.UpdateLocation, false);
inPlaceHostingManager.GetManifestCompleted += ((sender, e) =>
{
try
{
var deploymentDescription = new DeploymentDescription(e.DeploymentManifest);
string productName = deploymentDescription.Product;
***DoSomethingToYour(productName);***
// - use this later -
//var commandBuilder = new StartMenuCommandBuilder(deploymentDescription);
//string startMenuCommand = commandBuilder.Command;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace);
}
});
ApplicationDeployment.UpdatedApplicationFullName Property

Categories