Как лучше всего обойти проблему с клиентом WCF, использующим блокировку?

Вот версия Swift версии Билла Чесвика (в настоящее время главный ответ):

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

var pageIsAnimating = false

Установите анимационное состояние:

func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
    self.pageIsAnimating = true
}

func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    if finished || completed {
        self.pageIsAnimating = false
    }
}

Заблокировать переходы, если он в настоящее время оживляет:

func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    if self.pageIsAnimating {
        return nil
    }

    // Your code here
}

func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
    if self.pageIsAnimating {
        return nil
    }

    // Your code here
}

Спасибо, Билл Чесвик!

394
задан live2 17 June 2017 в 15:35
поделиться

5 ответов

На самом деле, хотя я вел блог (см. ответ Luke ), я думаю , это лучше, чем моя обертка IDisposable. Типичный код:

Service<IOrderService>.Use(orderService=>
{
  orderService.PlaceOrder(request);
}); 
<час>

(редактирование на комментарии)

С тех пор Use возвраты пусто, самый легкий способ обработать возвращаемые значения через полученную переменную:

int newOrderId = 0; // need a value for definite assignment
Service<IOrderService>.Use(orderService=>
  {
    newOrderId = orderService.PlaceOrder(request);
  });
Console.WriteLine(newOrderId); // should be updated
131
ответ дан Community 18 June 2017 в 01:35
поделиться
  • 1
    читайте об инжекциях заголовка с электронной почтой для понимания что I' m говорящий о. – Jan. 3 September 2010 в 03:01

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

TReturn UseService<TChannel, TReturn>(Func<TChannel, TReturn> code)
{
    var chanFactory = GetCachedFactory<TChannel>();
    TChannel channel = chanFactory.CreateChannel();
    bool error = true;
    try {
        TReturn result = code(channel);
        ((IClientChannel)channel).Close();
        error = false;
        return result;
    }
    finally {
        if (error) {
            ((IClientChannel)channel).Abort();
        }
    }
}

можно выполнить вызовы как это:

int a = 1;
int b = 2;
int sum = UseService((ICalculator calc) => calc.Add(a, b));
Console.WriteLine(sum);

Это в значительной степени точно так же, как Вы имеете в своем примере. В некоторых проектах мы пишем вспомогательные методы со строгим контролем типов, таким образом, мы заканчиваем тем, что писали вещи как "Wcf. UseFooService (f => f...)".

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

Это позволяет другим изящным функциям быть включенными. Например, на одном сайте, сайт проходит проверку подлинности к сервису от имени зарегистрированного пользователя. (Сайт не имеет никаких учетных данных отдельно.) Путем записи нашему собственному помощнику метода "UseService", мы можем настроить фабрику канала путем, мы хотим и т.д. Мы также не связываемся с использованием сгенерированных прокси - любой интерфейс сделает.

32
ответ дан Nick Westgate 18 June 2017 в 01:35
поделиться
  • 1
    Наконец! Это отсутствовало начиная с направляющих 2 – paul.ago 8 July 2013 в 00:45

Наша архитектура системы часто использует Единица МОК платформа для создания экземпляров ClientBase, таким образом, нет никакого верного способа осуществить это, другие разработчики даже используют using{} блоки. Для создания его максимально надежным, я сделал этот пользовательский класс, который расширяет ClientBase, и дескрипторы, закрывающие канал на, располагают, или на завершают в случае, если кто-то явно не избавляется от созданного экземпляра Единицы.

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

public abstract class PFServer2ServerClientBase<TChannel> : ClientBase<TChannel>, IDisposable where TChannel : class
{
    private bool disposed = false;

    public PFServer2ServerClientBase()
    {
        // Copy information from custom identity into credentials, and other channel setup...
    }

    ~PFServer2ServerClientBase()
    {
        this.Dispose(false);
    }

    void IDisposable.Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    public void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            try
            {
                    if (this.State == CommunicationState.Opened)
                        this.Close();
            }
            finally
            {
                if (this.State == CommunicationState.Faulted)
                    this.Abort();
            }
            this.disposed = true;
        }
    }
}

Тогда клиент может просто:

internal class TestClient : PFServer2ServerClientBase<ITest>, ITest
{
    public string TestMethod(int value)
    {
        return base.Channel.TestMethod(value);
    }
}

И вызывающая сторона может сделать любой из них:

public SomeClass
{
    [Dependency]
    public ITest test { get; set; }

    // Not the best, but should still work due to finalizer.
    public string Method1(int value)
    {
        return this.test.TestMethod(value);
    }

    // The good way to do it
    public string Method2(int value)
    {
        using(ITest t = unityContainer.Resolve<ITest>())
        {
            return t.TestMethod(value);
        }
    }
}
1
ответ дан Peter Mortensen 18 June 2017 в 01:35
поделиться
  • 1
    много большое спасибо! +1 для нескольких опций!! – normalUser 17 April 2014 в 07:08

Given a choice between the solution advocated by IServiceOriented.com and the solution advocated by David Barret's blog, I prefer the simplicity offered by overriding the client's Dispose() method. This allows me to continue to use the using() statement as one would expect with a disposable object. However, as @Brian pointed out, this solution contains a race condition in that the State might not be faulted when it is checked but could be by the time Close() is called, in which case the CommunicationException still occurs.

So, to get around this, I've employed a solution that mixes the best of both worlds.

void IDisposable.Dispose()
{
    bool success = false;
    try 
    {
        if (State != CommunicationState.Faulted) 
        {
            Close();
            success = true;
        }
    } 
    finally 
    {
        if (!success) 
            Abort();
    }
}
87
ответ дан 22 November 2019 в 23:40
поделиться

Я наконец нашел несколько солидных шагов к чистому решению этой проблемы.

Этот пользовательский инструмент расширяет WCFProxyGenerator, чтобы обеспечить прокси-сервер обработки исключений. Он генерирует дополнительный прокси под названием ExceptionHandlingProxy , который наследуется , исключая , исключение , исключения - последнее, из которых реализует мясо функциональности прокси. Результатом заключается в том, что вы можете использовать прокси-сервер по умолчанию, который наследует ClientBase или ExceptionHandLingProxy , который инкапсулирует управление сроком службы канала завода и канала. ExceptionHandlingProxy уважает ваши выборы в диалоговом окне «Добавить справочник службы» в отношении асинхронных методов и типов сбора.

CodePlex имеет проект под названием Exception, обрабатывая прокси-генератор WCF . Он в основном устанавливает новый пользовательский инструмент в Visual Studio 2008, затем используйте этот инструмент для генерации нового прокси-сервера (Добавить ссылку на обслуживание) . Он имеет хорошую функциональность для решения недостаточных каналов, тайм-аутов и безопасного утилизации. Здесь называется отличное видео ExceptionHandlingProxyWrapper , объясняющий именно, как это работает.

Вы можете безопасно использовать оператор , используя оператор , и если канал не поврежден по любому запросу (TimeOutexception или CommunicationException), обертка будет повторно инициализирует неисправный канал и повторяет запрос. Если это не удается, то он позвонит в команду Abort () и утилизируйте прокси-сервер и ретро, ​​исключение. Если сервис бросает ShipException код , он прекратит выполнение, а прокси будет прервана безопасно бросать правильное исключение, как и ожидалось.

14
ответ дан 22 November 2019 в 23:40
поделиться
Другие вопросы по тегам:

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