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

C# 添加https绑定时Microsoft.Web.Administration中的NullReferenceException,c#,ssl,iis-7,C#,Ssl,Iis 7,我试图以编程方式将绑定添加到默认网站,但在Microsoft.Web.Administration dll中始终出现空引用异常。最初,我想在绑定的同时分配一个证书。我可以通过以下方式查询我想要的证书: var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite); var certificate

我试图以编程方式将绑定添加到默认网站,但在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();
考虑到我的变量或示例代码中的任何其他项都不为null(包括返回20字节数组的GetCertHash),我对为什么在这里得到null感到困惑。我甚至尝试了以下过载:

site.Bindings.Add("*:443", "https");
我仍然得到相同的null ref堆栈:

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: System.NullReferenceException未处理 Message=对象引用未设置为对象的实例。 Source=Microsoft.Web.Administration 堆栈跟踪: 在Microsoft.Web.Administration.Configuration.SetDirty()上 在Microsoft.Web.Administration.ConfigurationElement.SetDirty()上 位于Microsoft.Web.Administration.ConfigurationElement.SetAttributeValue(字符串attributeName,对象值) 位于Microsoft.Web.Administration.Binding.SetBindingProperty(字符串attributeName,字符串值) 在Microsoft.Web.Administration.BindingCollection.Add(字符串bindingInformation,字节[]certificateHash,字符串certificateStoreName) 在C:\Projects\Cube\trunk\src\AutoUpdate\TestApp\Program.cs中的TestApp.Program.Main(字符串[]args)处:第33行 位于System.AppDomain.\u nExecuteAssembly(RuntimeAssembly程序集,字符串[]args) 位于System.AppDomain.ExecuteAssembly(字符串汇编文件、证据汇编安全性、字符串[]args) 在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()上 位于System.Threading.ThreadHelper.ThreadStart\u上下文(对象状态) 在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

类程序
{
静态void Main(字符串[]参数)
{
使用(ServerManager=newservermanager())
{
var store=new X509Store(StoreName.Root,StoreLocation.LocalMachine);
store.Open(OpenFlags.openingonly | OpenFlags.ReadWrite);
var certificate=store.Certificates.Find(X509FindType.FindByIssuerName,“TEST_SELF_SIGNED”,true);
Site Site=GetSite(“默认网站”);
添加(“*:443”,certificate.GetCertHash(),store.Name);
store.Close();
manager.CommitChanges();
}
}
公共静态站点GetSite(字符串siteName)
{
使用(var serverManager=newservermanager())
{
返回serverManager.Sites.Where(p=>p.Name.ToLower()==siteName.ToLower()).FirstOrDefault();
}
}
}

为了弥补我的不足,安装了Iis,手动分配证书工作正常。

因此,我通过反编译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;
}
此处唯一可能为空的是
\u configurationManager
\u configurationManager.Owner
。我检查了
所有者
是什么,是
服务器管理器
提示我可能应该从服务器管理器的using块中查询
站点
。一旦我这么做了,空参考就消失了,一切都正常了。不幸的是,他们没有检查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();
        }
    }

}
类程序
{
静态void Main(字符串[]参数)
{
使用(var serverManager=newservermanager())
{
var selfSignedCnName=“自签名测试”;
var websiteName=“默认网站”;
var site=serverManager.Sites.Where(p=>p.Name.ToLower()==websiteName.ToLower()).FirstOrDefault();
var store=new X509Store(StoreName.Root,StoreLocation.LocalMachine);
store.Open(OpenFlags.openingonly | OpenFlags.ReadWrite);
var certificate=store.Certificates.Find(X509FindType.FindByIssuerName,selfSignedCnName,true);
添加(“*:443:”,certificate.GetCertHash(),store.Name);
store.Close();
serverManager.CommitChanges();
}
}
}
从我的第一篇文章中也可以清楚地看到,在服务器管理器中包装整个代码块并不意味着什么,它们不是级联的。您必须从该站点的服务器管理器对其进行操作

internal void SetDirty()
{
  if (this._hasBeenCommitted || this._configurationManager.Owner.ReadOnly)
    throw new InvalidOperationException(Resources.ObjectHasBeenCommited);
  this._isDirty = true;
}
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();
        }
    }

}