2011-03-28 3 views
15

У нас есть служба WCF, которую мы потребляем из веб-приложения. Клиент, который мы используем, был создан с использованием опции «Добавить ссылку на службу» Visual Studio. Поскольку это веб-приложение, и поскольку характер приложения, скорее всего, приведет к относительно коротким сеансам, мы решили создать экземпляр клиента, когда пользователь входит в систему и сохраняет его в течение всего сеанса, а затем обрабатывать его, когда сеанс проходит.Обращение с постоянным клиентом WCF, входящим в состояние с ошибкой

Это подводит меня к моему вопросу - мы пытаемся решить, как лучше обращаться с каналом клиента, входящим в состояние Faulted. После поиска вокруг некоторых, мы придумали с этим:

if(client.State = CommuncationState.Faulted) 
{ 
    client = new Client(); 
} 

try 
{ 
    client.SomeMethod(); 
} 
catch //specific exceptions left out for brevity 
{ 
    //logging or whatever we decide to do 
    throw; 
} 

Это, однако, не работает из-за того, что, по крайней мере, в нашем случае, даже если услуга вниз клиент покажет Open, пока вы на самом деле не попытаетесь сделать вызов, используя его, после чего он войдет в состояние Faulted.

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

try 
{ 
    client.SomeMethod(); 
} 
catch 
{ 
    if(client.State == CommunicationState.Faulted) 
    { 
     //we know we're faulted, try it again 
     client = new Client(); 
     try 
     { 
      client.SomeMethod(); 
     } 
     catch 
     { 
      throw; 
     } 
    } 
    //handle other exceptions 
} 

Но это пахнет. Очевидно, мы могли бы избежать этого, используя нового клиента и избавляясь от него для каждого вызова. Это кажется ненужным, но если это правильный путь, я думаю, это то, что мы выберем. Итак, каков наилучший способ изящно описать, находится ли клиент в неисправном состоянии, а затем что-то делать? Должны ли мы действительно просто получать нового клиента для каждого звонка?

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

+0

Что заставляет клиента вводить неисправное состояние? Я всегда имел возможность, чтобы служба WCF возвращала ошибку нормально, и клиент может продолжать рассказывать о своем бизнесе. Сервер не отвечает или что-то еще? – Tridus

+0

В этом случае мы используем членство в ASP.NET, и мы столкнулись с ним, превысив атрибут userIsOnlineTimeWindow. Очевидно, что в этом случае имеет смысл просто перенаправить пользователя на страницу входа в систему, но мы стараемся, чтобы мы были готовы к любой другой ситуации, в которой мы могли бы попасть в неисправное состояние. – Zannjaminderson

ответ

18

Чтобы ответить на ваш вопрос, вы можете справиться с Faulted event в ChannelFactory собственности, как это:

client.ChannelFactory.Faulted += new EventHandler(ChannelFactory_Faulted); 

Это позволит вам выполнить любую регистрацию/очистки, что вам нужно сделать.

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

Также, если это возможно, рассмотрите НЕ использование Visual Studio Add Service Reference или, по крайней мере, очистку генерируемого кода/конфигурации.Я рекомендую, чтобы, если вы хотите использовать прокси-реализацию, создайте свой собственный, выведя из ClientBase или воспользуемся реализацией ChannelFactory. Поскольку вы упоминаете класс-оболочку, я бы рекомендовал вам использовать ChannelFactory и обрабатывать Faulted event для ваших нужд очистки.

+0

Спасибо за ответ. Я видел, как много людей говорили об открытии и закрытии клиентского канала для каждого звонка, и мне интересно, зачем это нужно делать? – Zannjaminderson

+2

Причина в том, что у вас может быть так много одновременных вызовов и одновременных сеансов для вашей службы. Поэтому, если каждый сеанс в вашем веб-приложении имеет открытый сеанс, вы быстро достигнете предела по умолчанию и должны его изменить, и производительность будет страдать. Для получения дополнительной информации об оптимизации этих (и других) настроек: http://msdn.microsoft.com/en-us/library/ee377061(v=bts.10).aspx – BrandonZeider

+0

Спасибо. Я читал еще кое-что в ChannelFactory, и похоже, мы будем двигаться в этом направлении. – Zannjaminderson

11

Попробуйте обработку события .Faulted на прокси клиента, например:

((ICommunicationObject)client).Faulted += new EventHandler(client_Faulted); 

private void client_Faulted(object sender, EventArgs e) 
{ 
    client = new Client(); 
    ((ICommunicationObject)client).Faulted += new EventHandler(client_Faulted); 
} 

Он должен вызывать тот момент, недостатки канала, что дает вам возможность вновь открыть его.

Вы также должны поместить каждый вызов методу client в блок try-catch и, возможно, даже обернуть его в цикл while(), который повторяет вызов n раз, затем регистрирует сбой. EG:

bool succeeded = false; 
int triesLeft = 3; 
while (!succeeded && triesLeft > 0) 
{ 
    triesLeft--; 
    try 
    { 
     client.SomeMethod(); 
     succeeded = true; 
    } 
    catch (exception ex) 
    { 
     logger.Warn("Client call failed, retries left: " + triesLeft; 
    } 
} 
if (!succeeded) 
    logger.Error("Could not call web service"); 

В моем коде я пошел так далеко, чтобы использовать ManualResetEvent блокировать, а() цикл, пока обработчик события client_Faulted не было возможности повторного создания client прокси.

+1

Как насчет отмены подписки на событие 'Faulted'? где это делать? – itsho

 Смежные вопросы

  • Нет связанных вопросов^_^