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

时间:2012-04-30 14:01:52

标签: c# ssl iis-7

我正在尝试以编程方式将绑定添加到我的默认网站,但是我一直在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");

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

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

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

System.NullReferenceException was unhandled
  Message=Object reference not set to an instance of an object.
  Source=Microsoft.Web.Administration
  StackTrace:
       at Microsoft.Web.Administration.Configuration.SetDirty()
       at Microsoft.Web.Administration.ConfigurationElement.SetDirty()
       at Microsoft.Web.Administration.ConfigurationElement.SetAttributeValue(String attributeName, Object value)
       at Microsoft.Web.Administration.Binding.SetBindingProperty(String attributeName, String value)
       at Microsoft.Web.Administration.BindingCollection.Add(String bindingInformation, Byte[] certificateHash, String certificateStoreName)
       at TestApp.Program.Main(String[] args) in C:\Projects\Cube\trunk\src\AutoUpdate\TestApp\Program.cs:line 33
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at 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<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并手动分配证书就可以了。

1 个答案:

答案 0 :(得分:8)

所以我通过反编译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的是_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<X509Certificate>().FirstOrDefault();

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

            store.Close();

            serverManager.CommitChanges();
        }
    }

}

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