Ловушки/глюки развертывания ClickOnce/smart-client в [закрытой].NET

Что такое 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 ).

31
задан Peter Mortensen 3 December 2013 в 21:32
поделиться

11 ответов

Вот некоторые, что я знаю.

  1. <забастовка> не Может поместить значок на рабочий стол. Вы можете теперь.

  2. я не могу установить для всех пользователей.

  3. я должен перейти через обручи для перемещения развертывания на другом сервере. Это не проблема, если Вы разрабатываете внутренне, и пользователи видят сервер, к которому Вы публикуете или если Вы развертываетесь к государственной сети, но не замечательно, если необходимо развернуть к нескольким сайтам для клиентов независимо.

  4. С тех пор .NET 3,5 SP1 Вы не должны больше подписывать декларацию развертывания, которая делает намного легче переместить развертывание на новых серверах.

  5. я не могу установить блоки в GAC. Можно обойти это путем создания регулярных пакетов установки, которые являются предпосылками приложения ClickOnce.

12
ответ дан 27 November 2019 в 22:17
поделиться
  • , Когда обновления развертываются, встроенное диалоговое окно заставит его появиться, как будто целое приложение повторно загружается. На самом деле только измененные DLLs загружаются, и отображенный индикатор выполнения является вводящим в заблуждение/неправильным. Не напрасно тратьте время, пытаясь выяснить, почему все блоки повторно развертываются только, чтобы обнаружить, что они на самом деле не. Не то, чтобы я сделал это или что-либо.
  • , Когда сертификат, что Вы раньше подписывали исходную декларацию развертывания, истекает и Вы выпущены новый, Вы находитесь в для мира вреда (клиенты должны будут все удалить и переустановить). Детали во рту лошади .
9
ответ дан 27 November 2019 в 22:17
поделиться

Большинство проблем было решено, но несколько человек упомянули, что не были способны создавать настольный ярлык. На самом деле Вы можете создавать настольный ярлык с Visual  Studio  2 008 SP1.

кроме того, если Вы не используете последнюю версию Visual Studio, Вы всегда можете писать код для создания ярлыка на установленный ярлык меню "Пуск" .

7
ответ дан 27 November 2019 в 22:17
поделиться

У нас было приложение, которое мы собирались развернуть как приложение ClickOnce. Нам был нужен пользователь, чтобы смочь изменить некоторые настройки в установке (такие как путь развертывания - IT хочет служить файлам от их сетевого ресурса, не известного во время изготовления). При изменении любого из файлов в развертывании необходимо повторно вычислить все хеши и оставить все. Так, если это решение является внутренним, у Вас не может быть проблем при раздавании сертификата подписания, но если это будет для клиентов, то необходимо будет спроектировать необычное решение обойти эту проблему.

я услышал грохот от где-нибудь в кишечнике Интернета, что будущая версия ClickOnce снимет часть этой головной боли.

6
ответ дан 27 November 2019 в 22:17
поделиться

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

4
ответ дан 27 November 2019 в 22:17
поделиться

Одна из ловушек с ClickOnce является тем, что Вы не можете установить на GAC. Это - проблема, если Вы хотите установить несколько приложений, которые совместно используют файлы DLL. Каждое приложение потребует локальной копии файлов DLL. Кроме того, отсутствуют многопользовательские установки. См. Установщик Окна сравнения списка к ClickOnce.

4
ответ дан 27 November 2019 в 22:17
поделиться

В случае, если кто-то обращается к этому в поиске, мы нашли многих клиентов обеспокоенными отсутствием безопасности, 'распределяющей' их приложение. Приложение должно быть доступным в общедоступном месте - без любой аутентификации - чтобы это смогло проверить на обновления. Единственное исключение - то, если у Вас есть аутентификация Windows NT. Я думаю Обеспечение, Приложения ClickOnce объясняют, что я имею в виду.

Значки на рабочем столе довольно тривиальны, чтобы сделать с помощью кода, и, как упомянуто, с 3,5 SP1, испеченные в - так, чтобы больше не была проблема.

существует все еще незакрепленная ошибка с xmlSerializer - это не становится развернутым правильно в некоторых случаях. Легкое обходное решение должно вручную добавить этот файл к развертыванию. ЛАВАШ, но это достаточно легко... Может быть отвратительно, когда Ваше развертывание внезапно перестало работать хотя...

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

Существует много вещей, которые Вы не можете сделать с приложениями ClickOnce, как установка ярлык на рабочий стол пользователя или иметь любую власть в том, где приложение установлено. Для некоторых людей это dealbreakers.

Также это было некоторое время, так как я использовал его, но существует специальный способ, которым можно использовать для фигуры и отобразить версию/номер сборки ClickOnce, которая является отдельной от версии/номера сборки приложения. Необходимо сделать попытку/выгоду и если версия/номер сборки ClickOnce выдает исключение затем, приложение не работает как ClickOnce-развертываемое-приложение (то есть, это работает как регулярно компилируемое приложение или из Visual Studio).

Для приложения, которое просто (то есть, не Microsoft Word, а скорее быстрое-и-грязное приложение сделать что-то) и нужно в большом регулярном развертывании, ClickOnce является большим. Но Вы скорее быстро врезаетесь в стену, "о, это не может быть сделано ClickOnce, выберите MSI или что-то еще).

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

У Вас будет меньше системного доступа, чем Ваше нормальное приложение.NET.

Поэтому Вы получите более низкий доверительный уровень. Больше об этом в Руководство Разработчика инфраструктуры.NET: Развертывание ClickOnce и безопасность .

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

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

Я не знал, что SP1 позволил Вам создавать значок на рабочем столе.
Вот то, как мы делали его (теперь известный как "твердый путь"):

try
{
    string company = string.Empty;
    string product = string.Empty;
    if (Attribute.IsDefined(asm, typeof(AssemblyCompanyAttribute)))
    {
        AssemblyCompanyAttribute asCompany = (AssemblyCompanyAttribute)Attribute.GetCustomAttribute(asm, typeof(AssemblyCompanyAttribute));
        company = asCompany.Company;
    }
    if (Attribute.IsDefined(asm, typeof(AssemblyProductAttribute)))
    {
        AssemblyProductAttribute asProduct = (AssemblyProductAttribute)Attribute.GetCustomAttribute(asm, typeof(AssemblyProductAttribute));
        product = asProduct.Product;
    }
    if (!string.IsNullOrEmpty(company) && !string.IsNullOrEmpty(product))
    {
        string desktopPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
            product + ".appref-ms");
        string shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs),
            Path.Combine(company, product + ".appref-ms"));
        File.Copy(shortcutPath, desktopPath, true);
    }
}
catch 
{
    // Shortcut could not be created
}
3
ответ дан 27 November 2019 в 22:17
поделиться

Невозможно установить, если клиент находится за прокси-сервером, требующим аутентификации.

1
ответ дан 27 November 2019 в 22:17
поделиться
Другие вопросы по тегам:

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