添加https绑定时,Microsoft.Web.Administration中的NullReferenceException

我正在尝试以编程方式将绑定添加到我的默认网站,但我一直在Microsoft.Web.Administration dll中获得空引用exception。 最初我想分配证书和绑定。 我能够用这个查询我想要的证书:

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().FirstOrDefault(); 

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

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

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

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

我仍然得到相同的空ref堆栈:

  System.NullReferenceException未处理
   Message =对象引用未设置为对象的实例。
  来源= Microsoft.Web.Administration
  堆栈跟踪:
       在Microsoft.Web.Administration.Configuration.SetDirty()
       在Microsoft.Web.Administration.ConfigurationElement.SetDirty()
       在Microsoft.Web.Administration.ConfigurationElement.SetAttributeValue(String attributeName,Object value)
       在Microsoft.Web.Administration.Binding.SetBindingProperty(String attributeName,String value)
       在Microsoft.Web.Administration.BindingCollection.Add(String bindingInformation,Byte [] certificateHash,String certificateStoreName)
       在TestApp.Program.Main(String [] args)中的C:\ Projects \ Cube \ trunk \ src \ AutoUpdate \ TestApp \ Program.cs:第33行
       在System.AppDomain._nExecuteAssembly(RuntimeAssembly程序集,String [] args)
       在System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence 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()
  的InnerException: 

这是一个完整的测试应用程序,它演示了这个问题,以及我用来生成示例证书的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().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已安装并手动分配证书工作正常。

所以我通过反编译Microsoft.Web.Administration dll并在堆栈中查找来找到答案。 事实certificate,如果您获得具有帮助程序function的站点,则它不会在站点上设置内部ServerManager属性。

导致该问题的DLL的function是在Microsoft.Web.Administration :: Configuration中

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

这里唯一可以为null的是_configurationManager_configurationManager.Owner 。 我检查了Owner是什么,这是一个ServerManager ,它让我知道我应该从服务器管理器的使用块中查询Site 。 一旦我这样做,空参考就消失了,一切正常。 不幸的是,他们没有检查null,但可能假设没有服务器管理器上下文,没有人会对站点对象采取行动。

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

 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().FirstOrDefault(); site.Bindings.Add("*:443:", certificate.GetCertHash(), store.Name); store.Close(); serverManager.CommitChanges(); } } } 

从我的初始post中可以清楚地看出,将整个代码块包装在服务器管理器中并不意味着什么,它们不是级联的。 您必须从它来自的服务器管理器上对该站点进行操作。