如何使用 ServerManager 从类库中读取 IIS 站点,而不是 IIS express,或者提升的进程如何处理类库?

Posted

技术标签:

【中文标题】如何使用 ServerManager 从类库中读取 IIS 站点,而不是 IIS express,或者提升的进程如何处理类库?【英文标题】:How to use ServerManager to read IIS sites, not IIS express, from class library OR how do elevated processes handle class libraries? 【发布时间】:2012-01-18 01:38:59 【问题描述】:

我有一些使用Microsoft.Web.Administration.ServerManager 的实用程序方法,但我遇到了一些问题。出于说明目的,请使用以下无效的简单代码。

using(var mgr = new ServerManager())

    foreach(var site in mgr.Sites)
    
        Console.WriteLine(site.Name);
    

如果我将该代码直接放在控制台应用程序中并运行它,它将获取并列出 IIS express 网站。如果我从提升的命令提示符运行该应用程序,它将列出 IIS7 网站。有点不方便,但到目前为止还不错。

如果我将该代码放在控制台应用程序引用和调用的类库中,它总是会列出 IIS Express 站点,即使控制台应用程序已提升。

Google 引导我尝试以下方法,但没有成功。

//This returns IIS express
var mgr = new ServerManager();
//This returns IIS express
var mgr = ServerManager.OpenRemote(Environment.MachineName);
//This throws an exception
var mgr = new  ServerManager(@"%windir%\system32\inetsrv\config\applicationhost.config");

显然我误解了“提升”流程运行的方式。在提升的进程中执行的所有内容,甚至来自另一个 dll 的代码,不应该以提升的权限运行吗?显然不是?

感谢您的帮助!

【问题讨论】:

【参考方案1】:

确保添加对正确 Microsoft.Web.Administration 的引用,应该是位于 c:\windows\system32\inetsrv\ 下的 v7.0.0.0 看起来您正在添加对 IIS Express 的 Microsoft.Web.Administraiton 的引用,这将为您提供这种行为

【讨论】:

卡洛斯。谢谢回复!你是对的!我仔细检查了一下,不知何故类库中的引用搞砸了。我会发誓它有正确的参考,但不知何故它指向 GAC 中的 7.9.0.0。谢谢! 我怀疑安装 VS 2012 导致我遇到了同样的问题,也许它只是安装了 IIS express,实际上并不是直接原因。 我还注意到,即使您在 %windir%\system32\inetsrv\ 中运行对程序集的引用,但您在 IIS Express 进程中执行代码,它也只会返回 IIS Express 站点,但是当我在具有管理员权限的控制台应用程序中运行它时,我只能获得 IIS 7.5 站点(在 Windows 7 x64 上)。 我爱你。这让我发疯了。 谢谢。我有一个对 7.0.0.0 的引用(来自 inetmgr 目录),但 Visual Studio 却默默地从 GAC 将其切换为 7.9.0.0(IISExpress)。在我的 *.csproj 的程序集引用中设置 <SpecificVersion>True</SpecificVersion> 解决了这个问题。您可以通过在调试器中启动您的应用程序并查看 ServerManager.ApplicationPoolsSection.Configuration.ConfigFile.FilePath 以查看它是否包含 inetsrv 或 IISExpress 来判断 ServerManager 是使用 IIS 还是 IISExpress。【参考方案2】:

你的问题帮助我找到了 PowerShell 的答案,所以如果互联网正在搜索如何做到这一点:

$assembly = [System.Reflection.Assembly]::LoadFrom("$env:systemroot\system32\inetsrv\Microsoft.Web.Administration.dll")

# load IIS express
$iis = new-object Microsoft.Web.Administration.ServerManager 
$iis.Sites

# load IIS proper
$iis = new-object Microsoft.Web.Administration.ServerManager "$env:systemroot\system32\inetsrv\config\applicationhost.config"  
$iis.Sites

【讨论】:

请注意,您使用的构造函数记录为“仅限 Microsoft 内部使用”:msdn.microsoft.com/en-us/library/ms617371(v=vs.90).aspx【参考方案3】:

注意!使用这种方法,我们看到了看似随机的问题,例如“不支持的操作”异常、添加/删除 HTTPS 绑定失败、在 IIS Express 中运行时无法启动/停止应用程序池以及其他问题。不知道这是由于 IIS 通常存在错误还是由于此处描述的非正统方法。总的来说,我的印象是所有用于自动化 IIS 的工具(appcmd、Microsoft.Web.Administration、PowerShell 等)都不稳定且不稳定,尤其是在不同的操作系统版本之间。 (一如既往)建议进行良好的测试!

编辑:另请参阅此答案中的 cmets,了解为什么这种方法可能不稳定。

从 NuGet 安装的常规 Microsoft.Web.Administration 包工作正常。无需复制任何系统 DLL。

官方文档中的明显解决方案也可以正常工作:

ServerManager iisManager = new ServerManager(@"C:\Windows\System32\inetsrv\config\applicationHost.config");

即使您从 IIS Express 的应用程序池中执行上述操作,这仍然有效。您仍然会看到“真实”IIS 的配置。您甚至可以添加新网站,只要您的应用程序以有权这样做的用户身份运行。

但请注意,上面的构造函数被记录为“仅限 Microsoft 内部使用”:

https://msdn.microsoft.com/en-us/library/ms617371(v=vs.90).aspx

【讨论】:

我不认为效果是随机的。系统中存在该dll的两个版本,一个在GAC中,一个在System32\inetsrv\中。由于一些奇怪的未知原因,两者都具有相同的名称。 GAC 中的一个用于 IISExpress,而 inetsrv 中的一个用于 IIS。两者都无法正确读取对方的数据。显然GAC版本不应该存在于实际的网络服务器中,因为没有安装Visual Studio。 @AaA 感谢您的解释。您不知道是否有官方/可靠的方式可以链接到正确的 DLL?接受的答案基于版本号,这似乎不稳定,因为版本号会发生变化(并且对此的评论表明这已经发生了)。 不知道你想知道什么,生产环境中一般不存在IISExpress版本。如果您不想将 dll 复制到您的应用程序文件夹中(显然来自您正在安装应用程序的同一台机器),那么 you can dynamically load the dll on runtime using reflection【参考方案4】:
var iisManager = new ServerManager(Environment.SystemDirectory + "\\inetsrv\\config\\applicationhost.config");

这非常有效。无需更改任何引用

【讨论】:

以上是关于如何使用 ServerManager 从类库中读取 IIS 站点,而不是 IIS express,或者提升的进程如何处理类库?的主要内容,如果未能解决你的问题,请参考以下文章

C# 从类库中获取资源图片,把图片资源保存到类库中

asp.net MVC - 我可以从类库中引用视图吗?

无法从类库访问 appsettings.json

从类库访问用户上下文

从类库项目中的 App.config 中读取

如何在标准类库中读取 .Net Core 配置?