Reputation: 34830
We're dynamically loading assemblies at startup and adding them as a reference:
BuildManager.AddReferencedAssembly(assembly);
The application supports installing new plugins at runtime. Following an install/uninstall action we are restarting the web application. I've tried:
HostingEnvironment.InitiateShutdown();
and
System.Web.HttpRuntime.UnloadAppDomain();
However, the new version of a plugin is not loaded - I believe this is due to how ASP.NET is aggressively caching referenced assemblies - especially ASP.NET MVC controllers.
In production this shouldn't be a problem since the plugin assembly version would be incremented each time. However, in development this is more of an issue since we don't wish to change the version number every time we make a slight change to a plugin.
How can we force the clearing of temp asp.net files, either programatically or using a post build event?
One solution is to "touch" global.asax but this seems a bit hacky to me.
Upvotes: 3
Views: 643
Reputation: 1038
I've used following piece of code to reset the application pool on demand. (Just connect this to a Controller Action).
Note : Since it's the application pool, you might want to check the impact to any other apps running on the same app pool.
public class IisManager
{
public static string GetCurrentApplicationPoolId()
{
// Application is not hosted on IIS
if (!AppDomain.CurrentDomain.FriendlyName.StartsWith("/LM/"))
return string.Empty;
// Application hosted on IIS that doesn't support App Pools, like 5.1
else if (!DirectoryEntry.Exists("IIS://Localhost/W3SVC/AppPools"))
return string.Empty;
string virtualDirPath = AppDomain.CurrentDomain.FriendlyName;
virtualDirPath = virtualDirPath.Substring(4);
int index = virtualDirPath.Length + 1;
index = virtualDirPath.LastIndexOf("-", index - 1, index - 1);
index = virtualDirPath.LastIndexOf("-", index - 1, index - 1);
virtualDirPath = "IIS://localhost/" + virtualDirPath.Remove(index);
var virtualDirEntry = new DirectoryEntry(virtualDirPath);
return virtualDirEntry.Properties["AppPoolId"].Value.ToString();
}
public static void RecycleApplicationPool(string appPoolId)
{
string appPoolPath = "IIS://localhost/W3SVC/AppPools/" + appPoolId;
var appPoolEntry = new DirectoryEntry(appPoolPath);
appPoolEntry.Invoke("Recycle");
}
public static void RecycleApplicationPool(string appPoolId, string username, string password)
{
string appPoolPath = "IIS://localhost/W3SVC/AppPools/" + appPoolId;
var appPoolEntry = new DirectoryEntry(appPoolPath, username, password);
appPoolEntry.Invoke("Recycle");
}
}
The overridden method is to cater for instances where you want to explicitly pass a user with Admin rights on the machine/server which hosts IIS instance.
And the controller action could be something like;
public string ResetAppPool()
{
var appPoolId = IisManager.GetCurrentApplicationPoolId();
if (appPoolId.Equals(string.Empty))
return "Application is not running inside an App Pool"; //May be not IIS 6 onwards
try
{
IisManager.RecycleApplicationPool(appPoolId); //Can only be used by Admin users
return string.Format("App pool {0} recycled successfully", appPoolId);
}
catch (Exception ex)
{
Logger.Error("Failed to recycle app pool : " + ex.StackTrace);
return string.Format("App pool {0} recycle failed", appPoolId);
}
}
Upvotes: 1