Почему Azure CloudConfigurationManager.GetSetting возвращает ноль

У меня есть проект веб-роли облачной службы, который запускается локально в эмуляторе, но не запускается при развертывании. Данная ошибка заключается в следующем:

[ArgumentNullException: Value cannot be null.
Parameter name: connectionString]
   Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(String connectionString) in e:\projects\azure-sdk-for-net\microsoft-azure-api\Services\Storage\Lib\Common\CloudStorageAccount.cs:344
   Candor.WindowsAzure.Storage.Table.CloudTableProxy`1.GetTable() in c:\Users\micha_000\Documents\GitHub\candor-common\Candor.WindowsAzure\Storage\Table\CloudTableProxy.cs:66
   Candor.WindowsAzure.Storage.Table.CloudTableProxy`1.Get(String partitionKey, String rowKey) in c:\Users\micha_000\Documents\GitHub\candor-common\Candor.WindowsAzure\Storage\Table\CloudTableProxy.cs:117
   Candor.WindowsAzure.Logging.Common.Table.CloudTableLogger.get_Configuration() +218
   Candor.WindowsAzure.Logging.Common.Table.CloudTableLogger.get_IsInfoEnabled() +9
   Common.Logging.Factory.AbstractLogger.Info(Object message) in c:\_oss\common-logging\src\Common.Logging.Core\Logging\Factory\AbstractLogger.cs:503
   Candor.Configuration.Provider.ProviderCollection`1.SetActiveProvider(T provider) in c:\Users\micha_000\Documents\GitHub\candor-common\Candor\Configuration\Provider\ProviderCollection.cs:169
   Candor.Configuration.Provider.ProviderResolver`1.AppendActive(T provider) in c:\Users\micha_000\Documents\GitHub\candor-common\Candor\Configuration\Provider\ProviderResolver.cs:77
   SHM.PublicMvcWeb.App_Start.ProviderBootstrapper.InitProviders() in c:\Users\micha_000\Documents\Git-Repos\shm-main\SHM.PublicMvcWeb\App_Start\ProviderBootstrapper.cs:23
   SHM.PublicMvcWeb.App_Start.ProviderBootstrapper.PostStartup() in c:\Users\micha_000\Documents\Git-Repos\shm-main\SHM.PublicMvcWeb\App_Start\ProviderBootstrapper.cs:18

Вы можете увидеть код для соответствующих строк, показанных в трассировке стека на github.

https://github.com/michael-lang/candor-common/

Строки, приводящие к ошибке в CloudTableProxy:

            if (String.IsNullOrWhiteSpace(_connectionName))
                throw new InvalidOperationException("The Cloud ConnectionName has not been configured.");
            if (_account == null)
                _account = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting(_connectionName));

Так как он не выдает пользовательскую ошибку "Облачное имя_соединения не настроено", это говорит о том, что _connectionName, переданное в CloudConfigurationManager.GetSetting, не является нулевым. Таким образом, CloudConfigurationManager является вызовом, возвращающим нулевое значение для указанного имени. Учитывая, что это имя возвращает значение при локальном запуске, я не уверен, почему оно не найдено при развертывании в моей облачной веб-роли. Если имя соединения было введено как опечатка, оно также не будет работать локально. Чтобы быть уверенным, вот моя общая конфигурация регистрации, называющая соединение, которое будет использоваться:

  <common>
    <logging>
      <factoryAdapter type="Candor.WindowsAzure.Logging.Common.Table.CloudTableLoggerFactoryAdapter, Candor.WindowsAzure.Logging.Common">
        <arg key="connectionName" value="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" />
      </factoryAdapter>
    </logging>
  </common>

У меня также есть совершенно другое решение с веб-ролью облачного сервиса, использующее те же компоненты Candor.Common, поэтому я не верю, что они являются проблемой.

Я использую один и тот же ноутбук для разработки обоих решений, поэтому оба используют версию инструментов Azure 2.2. Проверка свойств проекта Cloud Service в каждом решении подтверждает это.

Я проверил каждый компонент и ссылку на пакет NuGet, чтобы убедиться, что в решении нет несоответствий версий. Для рабочего решения и этого нерабочего решения для этих же компонентов установлено значение copy-local = true. Они также имеют одинаковые перенаправления привязки. Хотя это была моя самая большая проблема, теперь решенная, прежде чем столкнуться с этой проблемой подключения.

Конфигурация развертывания нерабочего сервиса:

<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="SHM.AzureService.PublicMvcWeb" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="4" osVersion="*" schemaVersion="2013-10.2.2">
  <Role name="SHM.PublicMvcWeb">
    <Instances count="1" />
    <ConfigurationSettings>
      <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)" />
      <Setting name="DefaultTableConnection" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)" />
      <Setting name="UserTableConnection" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)" />
      <Setting name="UserSaltTableConnection" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)" />
      <Setting name="UserAuditTableConnection" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)" />
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

Я также недавно пытался вставить эти же имена подключений в настройки приложения веб-приложения. Это было в ответ на комментарий 3 года назад, что их код выполнялся до RoleEnvironment.OnStart. Но эта попытка все еще приводит к той же самой ошибке.

Вот как выглядела попытка:

  <appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <add key="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)"/>
    <add key="DefaultTableConnection" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)"/>
    <add key="UserTableConnection" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)"/>
    <add key="UserSaltTableConnection" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)"/>
    <add key="UserAuditTableConnection" value="DefaultEndpointsProtocol=https;AccountName=(redacted);AccountKey=(redacted)"/>
  </appSettings>

Этот код по ошибке запускается при запуске приложения с использованием WebActivator 2.0.6, тогда как мое рабочее решение использует WebActivator 2.0.4. Но заметки о выпуске WebActivator показывают только изменение компиляции с Debug на "Retail" и изменение лицензии между двумя версиями, и эти изменения были год назад.

На случай, если проблема была с синхронизацией, я также попытался добавить Thread.Sleep(1000) непосредственно перед ошибочным вызовом, и он тоже не сработал, поэтому я собираюсь удалить его.

using System.Threading;
using Candor.Configuration.Provider;
using Candor.Security;
using Candor.Security.Cryptography;
using Candor.Security.Web;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(StopHarassingMe.PublicMvcWeb.App_Start.ProviderBootstrapper), "PreStartup")]
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(StopHarassingMe.PublicMvcWeb.App_Start.ProviderBootstrapper), "PostStartup")]

namespace SHM.PublicMvcWeb.App_Start
{
    public class ProviderBootstrapper
    {
        public static void PreStartup()
        {
        }
        public static void PostStartup()
        {
            Thread.Sleep(1000); //let RoleEnvironment finish startup first or connectionstrings are not available.
            InitProviders();
        }

        private static void InitProviders()
        {
            ProviderResolver<HashProvider>.Configure()
                .AppendActive(new SHA2HashProvider("sha2") { IsObsolete = false, SaltModifier = "" });
        }
    }
}

Это первый провайдер, настроенный как на работающие, так и на нерабочие решения.

Вот список пакетов, используемых веб-приложением по ошибке:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Antlr" version="3.5.0.2" targetFramework="net45" />
  <package id="Candor.Core" version="1.4.1.0" targetFramework="net45" />
  <package id="Candor.jQuery.AutoAsync" version="4.0.0.50129" targetFramework="net45" />
  <package id="Candor.Security" version="2.4.0.0" targetFramework="net451" />
  <package id="Candor.Security.AzureStorageProvider" version="2.3.2.0" targetFramework="net451" />
  <package id="Candor.Web.Mvc" version="1.0.3.0" targetFramework="net451" />
  <package id="Candor.Web.Mvc.ErrorHandler" version="1.0.0.0" targetFramework="net45" />
  <package id="Candor.Web.Mvc.Security" version="2.1.0.0" targetFramework="net45" />
  <package id="Candor.WindowsAzure" version="1.3.0.0" targetFramework="net451" />
  <package id="Candor.WindowsAzure.Logging.Common" version="1.1.1.0" targetFramework="net451" />
  <package id="Common.Logging" version="2.2.0" targetFramework="net45" />
  <package id="Common.Logging.Core" version="2.2.0" targetFramework="net45" />
  <package id="form2js" version="1.0.0.30224" targetFramework="net45" />
  <package id="jQuery" version="2.1.4" targetFramework="net451" />
  <package id="jQuery.UI.Combined" version="1.8.20.1" targetFramework="net45" />
  <package id="jQuery.Validation" version="1.13.1" targetFramework="net45" />
  <package id="MarkdownSharp" version="1.13.0.0" targetFramework="net451" />
  <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.HelpPage" version="5.2.3" targetFramework="net451" />
  <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net45" />
  <package id="Microsoft.Data.Edm" version="5.6.0" targetFramework="net451" />
  <package id="Microsoft.Data.OData" version="5.6.0" targetFramework="net451" />
  <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net45" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
  <package id="Microsoft.WindowsAzure.ConfigurationManager" version="2.0.1.0" targetFramework="net45" />
  <package id="Modernizr" version="2.8.3" targetFramework="net45" />
  <package id="Newtonsoft.Json" version="6.0.8" targetFramework="net45" />
  <package id="Respond" version="1.4.2" targetFramework="net45" />
  <package id="RestSharp" version="105.0.1" targetFramework="net451" />
  <package id="System.Spatial" version="5.6.0" targetFramework="net451" />
  <package id="T4MVC" version="3.7.4" targetFramework="net45" />
  <package id="T4MVCExtensions" version="3.7.4" targetFramework="net45" />
  <package id="Twilio" version="4.0.3" targetFramework="net451" />
  <package id="Twilio.Mvc" version="3.1.15" targetFramework="net451" />
  <package id="Twilio.TwiML" version="3.3.6" targetFramework="net451" />
  <package id="WebActivatorEx" version="2.0.6" targetFramework="net451" />
  <package id="WebGrease" version="1.6.0" targetFramework="net45" />
  <package id="WindowsAzure.Storage" version="2.1.0.3" targetFramework="net45" />
</packages>

Между моим рабочим и нерабочим решением есть несколько различий в пакетах, но я не думаю, что они применимы к ошибке. Я перешел с MVC 5.0 на 5.2.3, обновил пакеты, связанные с javascript, и Candor.WindowsAzure с 1.2.10 до 1.3. Это может показаться актуальным, но единственное изменение кода состояло в том, чтобы заменить реализацию метода пакетного обновления.

ПАКЕТЫ ПРОЕКТА РАБОЧЕГО РЕШЕНИЯ:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Antlr" version="3.5.0.2" targetFramework="net45" />
  <package id="Candor.Core" version="1.4.1.0" targetFramework="net451" />
  <package id="Candor.jQuery.AutoAsync" version="3.5.0.40210" targetFramework="net451" />
  <package id="Candor.Security" version="2.4.0.0" targetFramework="net451" />
  <package id="Candor.Security.AzureStorageProvider" version="2.3.2.0" targetFramework="net451" />
  <package id="Candor.Web.Mvc" version="1.0.3.0" targetFramework="net451" />
  <package id="Candor.Web.Mvc.ErrorHandler" version="1.0.0.0" targetFramework="net45" />
  <package id="Candor.Web.Mvc.Security" version="2.1.0.0" targetFramework="net45" />
  <package id="Candor.WindowsAzure" version="1.2.10.0" targetFramework="net451" />
  <package id="Candor.WindowsAzure.Logging.Common" version="1.1.1.0" targetFramework="net451" />
  <package id="Common.Logging" version="2.2.0" targetFramework="net451" />
  <package id="Common.Logging.Core" version="2.2.0" targetFramework="net451" />
  <package id="form2js" version="1.0.0.30224" targetFramework="net45" />
  <package id="jQuery" version="2.0.3" targetFramework="net45" />
  <package id="jQuery.UI.Combined" version="1.10.3" targetFramework="net45" />
  <package id="jQuery.Validation" version="1.11.1" targetFramework="net45" />
  <package id="MarkdownSharp" version="1.13.0.0" targetFramework="net451" />
  <package id="Microsoft.AspNet.Mvc" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.Razor" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.Web.Optimization" version="1.1.2" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.HelpPage" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.OData" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.WebHost" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages.Data" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages.WebData" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.Data.Edm" version="5.6.0" targetFramework="net45" />
  <package id="Microsoft.Data.OData" version="5.6.0" targetFramework="net45" />
  <package id="Microsoft.jQuery.Unobtrusive.Ajax" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
  <package id="Microsoft.WindowsAzure.ConfigurationManager" version="2.0.1.0" targetFramework="net45" />
  <package id="Modernizr" version="2.7.1" targetFramework="net45" />
  <package id="Newtonsoft.Json" version="5.0.8" targetFramework="net45" />
  <package id="SlidesJS" version="3.0.4" targetFramework="net451" />
  <package id="System.Spatial" version="5.6.0" targetFramework="net45" />
  <package id="T4MVC" version="3.7.4" targetFramework="net45" />
  <package id="T4MVCExtensions" version="3.7.4" targetFramework="net45" />
  <package id="WebActivatorEx" version="2.0.4" targetFramework="net45" />
  <package id="WebGrease" version="1.6.0" targetFramework="net451" />
  <package id="WindowsAzure.Storage" version="2.1.0.3" targetFramework="net45" />
</packages>

3 ответа

В моем случае я использовал SlowCheetah (пакет NuGet) для преобразования файлов App.config. В Debug он не использовал Transformation. Использование параметров отладки в файле "root"-config решило мою проблему.

Суть вопроса заключается в том, что CloudConfigurationManager.GetSetting будет считывать заданный ключ конфигурации из настроек облачного проекта, если он определен, или же обратится к реальной конфигурации приложения или веб-конфигурации. Так что если вы убедитесь, что он существует в одном из мест, он должен работать нормально. Поскольку вы подтвердили, что он работает локально, он должен работать точно так же, даже после развертывания.

Другой случай, который может произойти, - это когда у вас есть несколько файлов конфигурации для локальных и облачных сред развертывания, и эта конфигурация может отсутствовать в файле конфигурации облака, который вы использовали для развертывания в облаке.

Я попытался развернуть сайт, чтобы увидеть разницу. Строки подключения к таблице были в appSettings из предыдущих попыток обойти проблему синхронизации, поэтому имело смысл попробовать вариант развертывания веб-сайтов (не облачной веб-роли).

Ошибка от этой попытки была

[FileNotFoundException: Could not load file or assembly 'Microsoft.WindowsAzure.ServiceRuntime, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.]

[FileNotFoundException: Could not load file or assembly 'Microsoft.WindowsAzure.ServiceRuntime, Version=2.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.]
   Candor.WindowsAzure.Logging.Common.Table.CloudTableLogger.WriteInternal(LogLevel level, Object message, Exception exception) +0
   Common.Logging.Factory.AbstractLogger.Info(Object message) in c:\_oss\common-logging\src\Common.Logging.Core\Logging\Factory\AbstractLogger.cs:504
   Candor.Configuration.Provider.ProviderCollection`1.SetActiveProvider(T provider) in c:\Users\micha_000\Documents\GitHub\candor-common\Candor\Configuration\Provider\ProviderCollection.cs:166
   Candor.Configuration.Provider.ProviderResolver`1.AppendActive(T provider) in c:\Users\micha_000\Documents\GitHub\candor-common\Candor\Configuration\Provider\ProviderResolver.cs:75

Это было странно, поскольку другая веб-роль рабочего решения, развернутая сейчас в облаке, имеет эту ссылку, установленную как CopyLocal = false. Но когда я установил значение true в этом нерабочем решении, оно начало работать при развертывании веб-сайта.

Затем я повторно развернул облачную веб-роль с этим компонентом, установленным как CopyLocal=True, и теперь он работает. Я не знаю, почему это требуется в одном развертывании проекта, а не в другом, в то время как для обоих проектов требовалось, чтобы другие компоненты Azure были CopyLocal = true.

Есть еще одна проблема со скоростью запуска, но я оставлю это для другого вопроса, если не пойму. По какой-то причине этот небольшой проект после запуска запускается в цикле занятости / перезапуска, но страница загружается время от времени. Это довольно странно, поскольку у него меньше зависимостей, инициализируемых при запуске, то есть экземпляры провайдеров, которые пишут по одной записи в журнале.

Другие вопросы по тегам