Конфигурация.NET (app.config/web.config/settings.settings)

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

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

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

161
задан N30 24 May 2011 в 17:17
поделиться

11 ответов

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

Это виды элементов конфигурации, которые я обычно храню на уровне машины:

, Когда каждая среда (разработчик, интеграция, тест, этап, живой), имеет свои собственные уникальные настройки в каталог c:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG, тогда, можно продвинуть Ваш код приложения между средами без любых модификаций постсборки.

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

я делал это в течение 7 лет на более чем 200 ASP.NET приложениях в 25 + различные компании. (Не пытающийся похвастать, просто хотите сообщить, что я никогда не видел ситуации, где этот подход не делает работа.)

61
ответ дан Jaymin 23 November 2019 в 21:27
поделиться

Как Вы у меня есть также установка 'много' app.config - например, app.configDEV, app.configTEST, app.config. ЛОКАЛЬНЫЙ. Я вижу часть превосходной предложенной альтернативы, но если бы Вам нравится способ, которым она работает на Вас, я добавил бы следующее:

я имею
<appSettings>
<add key = "Env" value = "[Local] "/> для каждого приложения, я добавляю это к UI в строке заголовка: от ConfigurationManager. AppSettings. Доберитесь ("ENV");

я просто переименовываю конфигурацию к той, для которой я нацелен (у меня есть проект с 8 приложениями с большим количеством конфигурации database/wcf против 4 evenioments). Для развертывания с clickonce в каждого, я изменяю 4 кипения в проекте и иду. (это, которое я хотел бы автоматизировать)

Мой единственный глюк к rememeber для 'очистки всех' после изменения, поскольку старая конфигурация застревает после руководства переименовывают. (Который я думаю, зафиксирует Вас проблема setting.setting).

я нахожу, что это работает действительно хорошо (однажды, я заставлю время смотреть на MSBuild/NAnt)

2
ответ дан Jaymin 23 November 2019 в 21:27
поделиться

Одно из решений, которые работавший меня прекрасный использовал WebDeploymentProject. У меня были 2/3 различные web.config файлы в моем сайте, и на публикуют, в зависимости от выбранного режима конфигурации (выпускать/подготавливать/и т.д....), я скопировал бы по сети. Release.config и переименовывают его к web.config в событии AfterBuild и удаляют тех, мне не нужно (сеть. Staging.config, например).

<Target Name="AfterBuild">
    <!--Web.config -->
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Release.config" DestinationFiles="$(OutputPath)\Web.config" />
    <Copy Condition=" '$(Configuration)|$(Platform)' == 'Staging|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\Web.Staging.config" DestinationFiles="$(OutputPath)\Web.config" />
    <!--Delete extra files -->
    <Delete Files="$(OutputPath)\Web.Release.config" />
    <Delete Files="$(OutputPath)\Web.Staging.config" />
    <Delete Files="@(ProjFiles)" />
  </Target>
5
ответ дан Adam Vigh 23 November 2019 в 21:27
поделиться

Вы найдете другое решение здесь: Лучший способ к конфигурации коммутатора между средами Development/UAT/Prod в ASP.NET? , который использует XSLT для передавания web.config.

существуют также некоторые хорошие примеры при использовании NAnt.

3
ответ дан Community 23 November 2019 в 21:27
поделиться

Мы раньше использовали веб-проекты Развертывания, но с тех пор мигрировали на NAnt. Вместо ветвления и копирования различных файлов установки мы в настоящее время встраиваем значения конфигурации непосредственно в сценарий сборки и вводим их в наши файлы конфигурации через xmlpoke задачи:

  <xmlpoke
    file="${stagingTarget}/web.config"
    xpath="/configuration/system.web/compilation/@debug"
    value="true"
  />

В любом случае, Ваши файлы конфигурации могут иметь любые значения разработчика, которые Вы хотите, и они будут хорошо работать из Вашей dev среды, не повреждая Ваши производственные системы. Мы нашли, что разработчики, менее вероятно, произвольно заменят переменные сценария сборки при проверении вещей, таким образом, случайные неверные конфигурации были более редкими, чем с другими методами, мы попробовали, хотя все еще необходимо добавить каждый var рано в процессе так, чтобы значение dev не становилось продвинутым подталкивать по умолчанию.

8
ответ дан jasondoucette 23 November 2019 в 21:27
поделиться

Мне кажется, что можно извлечь выгоду из веб-Проект s.

Развертывания Visual Studio 2005 года, С которым, можно сказать ему обновлять/изменять разделы web.config файла в зависимости от конфигурации сборки.

Смотрят на эта запись в блоге от Scott Gu для быстрого обзора/образца.

11
ответ дан Magnus Johansson 23 November 2019 в 21:27
поделиться

Из того, что я читаю, это кажется на использование Visual Studio для процесса сборки. Вы думали об использовании MSBuild и Nant вместо этого?

синтаксис XML Nant является немного странным, но как только Вы понимаете его, делая то, что Вы упомянули, становится довольно тривиальным.

<target name="build">
    <property name="config.type" value="Release" />

    <msbuild project="${filename}" target="Build" verbose="true" failonerror="true">
        <property name="Configuration" value="${config.type}" />
    </msbuild>

    <if test="${config.type == 'Debug'}">
        <copy file=${debug.app.config}" tofile="${app.config}" />
    </if>

    <if test="${config.type == 'Release'}">
        <copy file=${release.app.config}" tofile="${app.config}" />
    </if>

</target>
14
ответ дан Steven Williams 23 November 2019 в 21:27
поделиться

Здесь существует связанный вопрос:

Улучшение Вашего Процесса сборки

Файлы конфигурации идут со способом переопределить настройки:

<appSettings file="Local.config">

Вместо того, чтобы регистрироваться в двух файлах (или больше), Вы только регистрируетесь в файле конфигурации по умолчанию, и затем на каждой целевой машине, Вы помещаете Local.config только с разделом appSettings, который имеет переопределения для той конкретной машины.

при использовании разделов конфигурации эквивалент:

configSource="Local.config"

, Конечно, это - хорошая идея сделать резервные копии всех файлов Local.config от других машин и регистрировать их где-нибудь, но не как часть фактических решений. Каждый разработчик помещает "игнорировать" на файл Local.config, таким образом, это не становится зарегистрированным, который перезаписал бы всех файл else.

(Вы не должны на самом деле называть его "Local.config", это, что я использую)

34
ответ дан Community 23 November 2019 в 21:27
поделиться

Мой текущий работодатель решил этот выпуск первым помещением dev уровня (отладка, этап, живой, и т.д.) в machine.config файле. Тогда они записали код, чтобы взять это и использовать правильный файл конфигурации. Это решило проблему с неправильной строкой подключения после того, как приложение развертывается.

Они просто недавно записали центральный веб-сервис, который передает корректную строку подключения обратно от значения в значении machine.config.

действительно ли это - лучшее решение? Вероятно, не, но это работает на них.

7
ответ дан Hector Sosa Jr 23 November 2019 в 21:27
поделиться

У нашего проекта такая же проблема, когда нам приходилось поддерживать конфигурации для dev, qa, uat и prod. Вот что мы следовали (применимо только в том случае, если вы знакомы с MSBuild):

Используйте MSBuild с расширением задач сообщества MSBuild. Он включает задачу «XmlMassUpdate», которая может «массово обновлять» записи в любом XML-файле после того, как вы дадите ему правильный узел для начала.

Для реализации:

1) У вас должен быть один файл конфигурации, который будет иметь свои записи dev env; это файл конфигурации в вашем решении.

2) У вас должен быть файл 'Substitutions.xml', который содержит только РАЗНЫЕ записи (в основном appSettings и ConnectionStrings) для каждой среды. Записи, которые не изменяются в среде, не нужно помещать в этот файл. Они могут жить в сети. config решения и задача не будет затронута

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

См. Пример ниже:

    <!-- Actual Config File -->
    <appSettings>
        <add key="ApplicationName" value="NameInDev"/>
        <add key="ThisDoesNotChange" value="Do not put in substitution file" />
    </appSettings>

    <!-- Substitutions.xml -->
    <configuration xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
      <substitutions>
        <QA>
           <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInQA"/>
           </appSettings>            
        </QA>
        <Prod>
          <appSettings>
            <add xmu:key="key" key="ApplicationName" value="NameInProd"/>
          </appSettings>            
        </Prod>
     </substitutions>
    </configuration>


<!-- Build.xml file-->

    <Target Name="UpdateConfigSections">
            <XmlMassUpdate ContentFile="Path\of\copy\of\latest web.config" SubstitutionsFile="path\of\substitutionFile" ContentRoot="/configuration" SubstitutionsRoot="/configuration/substitutions/$(Environment)" />
        </Target>

замените «$ Environment» на «QA» или «Prod» в зависимости от того, какой env. вы строите для. Обратите внимание, что вы должны работать с копией файла конфигурации, а не с самим файлом конфигурации, чтобы избежать любых возможных неисправимых ошибок.

Просто запустите файл сборки, а затем переместите обновленный файл конфигурации в среду развертывания, и вы готово!

Для лучшего обзора прочтите это:

http://blogs.microsoft.co.il/blogs/dorony/archive/2008/01/18/easy-configuration-deployment-with-msbuild- and-the-xmlmassupdate-task.aspx

3
ответ дан 23 November 2019 в 21:27
поделиться

Это может помочь некоторым людям, имеющим дело с Settings.settings и App.config: следите за атрибутом GenerateDefaultValueInCode на панели свойств при редактировании любых значений в сетке Settings.settings в Visual Studio (Visual Studio 2008 в моем случае) .

Если вы установите для GenerateDefaultValueInCode значение True (True здесь по умолчанию!), Значение по умолчанию компилируется в EXE (или DLL), вы можете найти его встроенным в файл, когда откроете его в текстовом редакторе.

Я работал над консольным приложением, и если я использовал EXE по умолчанию, приложение всегда игнорировало файл конфигурации, помещенный в тот же каталог! Настоящий кошмар и никакой информации об этом во всем Интернете.

51
ответ дан 23 November 2019 в 21:27
поделиться