8

我正在尝试以编程方式将绑定添加到我的默认网站,但是我一直在 Microsoft.Web.Administration dll 中收到空引用异常。最初我想与绑定一起分配证书。我可以用这个查询我想要的证书:

var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);

var certificate = store.Certificates.Find(X509FindType.FindByIssuerName,
                                                  "TEST_SELF_SIGNED", true)
                                                  .OfType<X509Certificate>().FirstOrDefault();

这正确地给了我我想要的证书,它是非空的并且有我期望的信息。

Site site = GetSite("Default Web Site");
var binding = site.Bindings.Add("*:443", certificate.GetCertHash(), "https");

鉴于我的变量或示例代码中的任何其他项都不是空的(包括返回 20 字节数组的 GetCertHash),我对为什么在这里得到空感到困惑。我什至尝试了以下重载:

site.Bindings.Add("*:443", "https");

而且我仍然得到相同的空引用堆栈:

System.NullReferenceException 未处理
  Message=对象引用未设置为对象的实例。
  来源=Microsoft.Web.Administration
  堆栈跟踪:
       在 Microsoft.Web.Administration.Configuration.SetDirty()
       在 Microsoft.Web.Administration.ConfigurationElement.SetDirty()
       在 Microsoft.Web.Administration.ConfigurationElement.SetAttributeValue(字符串属性名,对象值)
       在 Microsoft.Web.Administration.Binding.SetBindingProperty(字符串属性名称,字符串值)
       在 Microsoft.Web.Administration.BindingCollection.Add(字符串 bindingInformation,字节 [] certificateHash,字符串 certificateStoreName)
       在 C:\Projects\Cube\trunk\src\AutoUpdate\TestApp\Program.cs:line 33 中的 TestApp.Program.Main(String[] args)
       在 System.AppDomain._nExecuteAssembly(RuntimeAssembly 程序集,字符串 [] 参数)
       在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,证据 assemblySecurity,String [] args)
       在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态)
       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔 ignoreSyncCtx)
       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态)
       在 System.Threading.ThreadHelper.ThreadStart()
  内部异常:

这是一个演示问题的完整测试应用程序,以及我用来生成示例证书的 selfssl 命令行参数:

selfssl.exe /T /N:CN=TEST_SELF_SIGNED /K:512 /V:9999 /Q

class Program
{
    static void Main(string[] args)
    {

        using (ServerManager manager = new ServerManager())
        {
            var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
            store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);

            var certificate = store.Certificates.Find(X509FindType.FindByIssuerName, "TEST_SELF_SIGNED", true).OfType<X509Certificate>().FirstOrDefault();

            Site site = GetSite("Default Web Site");
            site.Bindings.Add("*:443", certificate.GetCertHash(), store.Name);

            store.Close();

            manager.CommitChanges();
        }
    }

    public static Site GetSite(string siteName)
    {
        using (var serverManager = new ServerManager())
        {
            return serverManager.Sites.Where(p => p.Name.ToLower() == siteName.ToLower()).FirstOrDefault();
        }
    }
}

只是为了覆盖我的基础,安装了 Iis 并手动分配证书就可以了。

4

1 回答 1

10

所以我通过反编译 Microsoft.Web.Administration dll 并在堆栈中查找来找到答案。事实证明,如果您获得一个带有辅助函数的站点,它不会在该站点上设置内部 ServerManager 属性。

导致问题的 dll 的功能是 Microsoft.Web.Administration::Configuration

internal void SetDirty()
{
  if (this._hasBeenCommitted || this._configurationManager.Owner.ReadOnly)
    throw new InvalidOperationException(Resources.ObjectHasBeenCommited);
  this._isDirty = true;
}

这里唯一可能为 null 的是_configurationManageror _configurationManager.Owner。我检查了Owner它是什么,它ServerManager告诉我我可能应该Site从服务器管理器的 using 块中查询。一旦我这样做了,null ref 就消失了,一切正常。不幸的是,他们没有检查空值,但也许假设没有服务器管理器上下文,没有人会在站点对象上采取行动。

无论如何,这是更新的代码:

class Program
{
    static void Main(string[] args)
    {

        using (var serverManager = new ServerManager())
        {
            var selfSignedCnName = "TEST_SELF_SIGNED";
            var websiteName = "Default Web Site";

            var site = serverManager.Sites.Where(p => p.Name.ToLower() == websiteName.ToLower()).FirstOrDefault(); 
            var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
            store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);

            var certificate = store.Certificates.Find(X509FindType.FindByIssuerName, selfSignedCnName, true).OfType<X509Certificate>().FirstOrDefault();

            site.Bindings.Add("*:443:", certificate.GetCertHash(), store.Name);

            store.Close();

            serverManager.CommitChanges();
        }
    }

}

从我最初的帖子中也很清楚,将整个代码块包装在服务器管理器中并不意味着什么,它们不是级联的。您必须从它来自的服务器管理器对站点采取行动。

于 2012-04-30T16:20:27.647 回答