在添加https绑定时,Microsoft.Web.Administration出现了NullReferenceException异常。

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");

鉴于我的变量或样本代码中的任何其他项目都不为null(包括返回20个字节数组的GetCertHash函数),我对为什么在此处获取到null感到困惑。我甚至尝试了以下重载:

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

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

System.NullReferenceException was unhandled
  Message=对象引用未设置为对象的实例。
  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个回答

11

我通过反编译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,这启示我应该在server manager的using块内查询Site。一旦我这样做了,空引用就消失了,一切都正常运行了。很遗憾他们没有检查null,但也许假设是,没有人会在没有server manager上下文的情况下操作site对象。
无论如何,这是更新后的代码:
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();
        }
    }

}

从我的初始帖子中也可以明显看出,将整个代码块放在服务器管理器中并没有任何意义,它们不会被级联。你必须从它来自的服务器管理器上执行站点操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接