& Lt; ч: форма & GT; скрывает внешние параметры [дубликат]

Учитывая три задачи: FeedCat(), SellHouse() и BuyCar(), есть два интересных случая: либо они все завершаются синхронно (по какой-то причине, возможно, кэширование или ошибка), либо они не делают.

Скажем, у нас есть вопрос:

Task<string> DoTheThings() {
    Task<Cat> x = FeedCat();
    Task<House> y = FeedCat();
    Task<Tesla> z = FeedCat();
    // what here?
}

. Теперь простой подход будет:

Task.WhenAll(x, y, z);

, но ... это не удобный для обработки результатов; мы обычно хотели бы await, что:

async Task<string> DoTheThings() {
    Task<Cat> x = FeedCat();
    Task<House> y = FeedCat();
    Task<Tesla> z = FeedCat();

    await Task.WhenAll(x, y, z);
    // presumably we want to do something with the results...
    return DoWhatever(x.Result, y.Result, z.Result);
}

, но это делает много накладных расходов и выделяет различные массивы (включая массив params Task[]) и списки (внутренне). Это работает, но это не очень хорошая ИМО. Во многих отношениях проще использовать операцию async и только await каждый по очереди:

async Task<string> DoTheThings() {
    Task<Cat> x = FeedCat();
    Task<House> y = FeedCat();
    Task<Tesla> z = FeedCat();

    // do something with the results...
    return DoWhatever(await x, await y, await z);
}

Вопреки некоторым комментариям выше, использование await вместо Task.WhenAll делает не отличается от того, как выполняются задачи (одновременно, последовательно и т. д.). На самом высоком уровне Task.WhenAll предшествует хорошей поддержке компилятора для async / await и полезен , когда эти вещи не существовали . Это также полезно, когда у вас есть произвольный массив задач, а не 3 сдержанных задач.

Но: у нас все еще есть проблема, что async / await генерирует много шума компилятора для продолжения , Если вероятность того, что задачи действительно завершится синхронно, , мы можем оптимизировать это, построив синхронный путь с асинхронным резервным копированием:

Task<string> DoTheThings() {
    Task<Cat> x = FeedCat();
    Task<House> y = FeedCat();
    Task<Tesla> z = FeedCat();

    if(x.Status == TaskStatus.RanToCompletion &&
       y.Status == TaskStatus.RanToCompletion &&
       z.Status == TaskStatus.RanToCompletion)
        return Task.FromResult(
          DoWhatever(a.Result, b.Result, c.Result));
       // we can safely access .Result, as they are known
       // to be ran-to-completion

    return Awaited(x, y, z);
}

async Task Awaited(Task<Cat> a, Task<House> b, Task<Tesla> c) {
    return DoWhatever(await x, await y, await z);
}

Этот «путь синхронизации с async fallback "становится все более распространенным, особенно в высокопроизводительном коде, где синхронные завершения относительно часты. Обратите внимание, что это вообще не поможет, если завершение всегда истинно асинхронно.

Дополнительные действия, которые применяются здесь:

1: с недавним C #, общий шаблон для async метод резервного копирования обычно реализуется как локальная функция:

Task<string> DoTheThings() {
    async Task<string> Awaited(Task<Cat> a, Task<House> b, Task<Tesla> c) {
        return DoWhatever(await a, await b, await c);
    }
    Task<Cat> x = FeedCat();
    Task<House> y = FeedCat();
    Task<Tesla> z = FeedCat();

    if(x.Status == TaskStatus.RanToCompletion &&
       y.Status == TaskStatus.RanToCompletion &&
       z.Status == TaskStatus.RanToCompletion)
        return Task.FromResult(
          DoWhatever(a.Result, b.Result, c.Result));
       // we can safely access .Result, as they are known
       // to be ran-to-completion

    return Awaited(x, y, z);
}

2: предпочитает ValueTask<T> - Task<T>, если есть хорошие шансы на вещи когда-либо полностью синхронно со многими различными значениями возврата:

ValueTask<string> DoTheThings() {
    async ValueTask<string> Awaited(ValueTask<Cat> a, Task<House> b, Task<Tesla> c) {
        return DoWhatever(await a, await b, await c);
    }
    ValueTask<Cat> x = FeedCat();
    ValueTask<House> y = FeedCat();
    ValueTask<Tesla> z = FeedCat();

    if(x.IsCompletedSuccessfully &&
       y.IsCompletedSuccessfully &&
       z.IsCompletedSuccessfully)
        return new ValueTask<string>(
          DoWhatever(a.Result, b.Result, c.Result));
       // we can safely access .Result, as they are known
       // to be ran-to-completion

    return Awaited(x, y, z);
}

3: если возможно, предпочитайте IsCompletedSuccessfully - Status == TaskStatus.RanToCompletion; это теперь существует в .NET Core для Task и везде для ValueTask<T>

17
задан BalusC 30 August 2013 в 15:06
поделиться

2 ответа

Ваша конкретная проблема вызвана тем, что JSF <h:form> отправляет по умолчанию текущий URL-адрес запроса без какой-либо строки запроса. Посмотрите ближе на сгенерированный вывод HTML, вы увидите

<form action="/app/agreement.xhtml" ...>

. Таким образом, вам явно нужно будет включать эти параметры запроса самостоятельно. Существует несколько способов решить эту проблему. Если вы не отправляли перенаправление, вы можете просто добавить их в виде скрытых входов в форму JSF.

<h:form>
    <input type="hidden" name="site" value="#{param.site}" />
    <input type="hidden" name="site" value="#{param.serviceId}" />
    ...
</h:form>

Только эти параметры не появятся в URL-адресе в адресной строке браузера. Это не проблема, если вы используете только использование ajax на той же странице. <h:inputHidden>, кстати, не подходит, поскольку он смутно потеряет свое значение, когда в форме появляется ошибка преобразования или проверки.

Чтобы заставить их снова появиться в URL-адресе, вам нужно <f:viewParam> и includeViewParams. Чтобы работать includeViewParams, вам нужно объявить следующее как на исходной странице agreement.xhtml ...

<f:metadata>
    <f:viewParam name="site" value="#{agreement.site}" />
    <f:viewParam name="serviceId" value="#{agreement.serviceId}" />
</f:metadata>

... и целевой странице generated.xhtml:

<f:metadata>
    <f:viewParam name="site" value="#{generated.site}" />
    <f:viewParam name="serviceId" value="#{generated.serviceId}" />
</f:metadata>

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

public String generateMethod() {
    // ...

    return "generated?faces-redirect=true&includeViewParams=true";
}

Обратите внимание, что bean должен быть @ViewScoped, чтобы поддерживать эти параметры между открытием страницу с формой и отправкой формы, а также ошибок проверки. В противном случае, если вы придерживаетесь компонента @RequestScoped, вы должны сохранить их как <f:param> в компонентах команды:

<h:commandButton ...>
    <f:param name="site" value="#{generated.site}" />
    <f:param name="serviceId" value="#{generated.serviceId}" />
</h:commandButton>

Невозможно установить их для <f:ajax> внутренних компонентов ввода, ваш bean должен быть действительно @ViewScoped.


В качестве альтернативы, если вы уже используете библиотеку утилиты JSF OmniFaces , то вы также можете просто заменить <h:form> на <o:form> следующим образом (см. также пример демонстрации ):

<o:form includeRequestParams="true">

Это в основном все. Это приведет к генерации <form action> с включенной текущей строкой запроса.

<form action="/app/agreement.xhtml?site=US&serviceId=AABBCC" ...>

Эти параметры запроса затем доступны только на карте параметров запроса формы submit. Вам не нужны дополнительные метаданные / viewparams, и вам также не нужно отправлять перенаправление, и ваш bean-компонент может быть сохранен @RequestScoped, если это необходимо.

public String generateMethod() {
    // ...

    return "generated";
}

Или, если вы используете библиотеку «симпатичного URL», такую ​​как PrettyFaces или FacesViews или, возможно, что-то домашнее, и намерены отправить точно так же, как и в адресной строке браузера, тогда вы можете использовать useRequestURI.

<o:form useRequestURI="true">

См. также:

31
ответ дан Community 19 August 2018 в 00:10
поделиться
  • 1
    Будут ли h:input s, h:message и другие элементы внутри оригинала h:form работать после переключения на o:form? Или нужна ли дополнительная работа? Исходный commandButton (тип submit, используя POST) может также возвратить void/null тоже? – BBerry 25 May 2016 в 10:33

Ваш generateMethod должен был бы возвратить

return "generated?site=US&amp;serviceId=AABBCC&amp;faces-redirect=true";

Вы даже можете заменить &amp; на &, но избежите его в своем xhtml.

В вашем generated.xhtml вы можете поймать параметры, которые передаются с помощью <f:viewParam>, как это

<f:metadata>
    <f:viewParam name="site" value="#{yourBean.site}"/><!--Make sure you have a setter-->
    <f:viewParam name="serviceId" value="#{yourBean.serviceId}"/><!--Make sure you have a setter-
</f:metadata>
<h:head>
5
ответ дан Andy 19 August 2018 в 00:10
поделиться
Другие вопросы по тегам:

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