Вопрос по iis-7, c#, ssl – NullReferenceException в Microsoft.Web.Administration при добавлении привязки https

7

Я пытаюсь программно добавить привязку к моему веб-сайту по умолчанию, однако я постоянно получаю исключение нулевой ссылки в dll Microsoft.Web.Administration. Изначально я хотел назначить сертификат вместе с привязкой. Я смог запросить сертификат, который я хотел с этим:

<code>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();
</code>

Это правильно дало мне сертификат, который я хотел, он был ненулевым и имел информацию, которую я ожидал.

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

Учитывая, что ни одна из моих переменных или каких-либо других элементов в примере кода не является нулевой (включая GetCertHash, который возвращает 20-байтовый массив), я не понимаю, почему я получаю нулевое значение здесь. Я даже попробовал следующую перегрузку:

<code>site.Bindings.Add("*:443", "https");
</code>

И я все еще получаю тот же стек нулевых ссылок:

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

<code>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();
        }
    }
}
</code>

Просто чтобы покрыть мои основы, Iis установлен, и ручное назначение сертификата работает просто отлично.

Ваш Ответ

1   ответ
8

я нашел ответ, декомпилировав dll Microsoft.Web.Administration и перелистывая стек. Оказывается, что если вы получаете сайт с вспомогательной функцией, он не устанавливает внутреннее свойство ServerManager на сайте.

Функция dll, которая вызвала проблему, была в Microsoft.Web.Administration :: Configuration

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

Единственное, что могло быть здесь нулевым, было либо_configurationManager или же_configurationManager.Owner, Я проверил чтоOwner был и это былоServerManager который дал мне понять, что я, вероятно, должен запросить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();
        }
    }

}

Из моего первоначального поста также ясно, что перенос всего блока кода в диспетчере сервера ничего не означает, они не каскадируются. Вы должны действовать на сайте от менеджера сервера, с которого он пришел.

Похожие вопросы