Używam netNamedPipeBinding
do wykonywania między-procesowej komunikacji WCF z aplikacji Windows do usługi Windows.Wyjątek WCF odebrany przy zamkniętym połączeniu z oddzwonionymi w użyciu
Teraz moja aplikacja działa dobrze na wszystkich innych kontach (po walce z moim uczciwym udziałem wyjątków WCF, jak każdy, kto pracował z WCF będzie wiedział ..), ale ten błąd jest taki, który okazuje się być dość odporny.
Aby namalować obraz z mojego scenariusza: moja usługa Windows może być ustawiona w kolejce do wykonania jakiejś pracy w dowolnym momencie za pomocą przycisku naciśniętego w aplikacji Windows, a następnie rozmawia przez netNamedPipeBinding
, która jest wiązaniem obsługującym wywołania zwrotne (dwie komunikacji), jeśli nie jesteś zaznajomiony i inicjuje żądanie wykonania tej pracy, (w tym przypadku procedura przesyłania pliku), powoduje ona również wywoływanie zwrotne (zdarzenia) co kilka sekund, począwszy od postępu pliku, szybkości transferu itd. itd. do aplikacji Windows, więc istnieje dość ciasna integracja klient-serwer; w ten sposób otrzymuję moje postępy w działaniu mojej usługi Windows z powrotem do mojej aplikacji Windows.
Teraz wszystko jest wspaniałe, bogowie WCF są teraz ze mną stosunkowo szczęśliwi, oprócz jednego paskudnego wyjątku, który otrzymuję za każdym razem, gdy zamykam aplikację przedwcześnie (co jest doskonale uzasadnionym scenariuszem). Podczas gdy transfer jest w toku, a callbacks strzelają dość ciężko, otrzymuję ten błąd:
System.ServiceModel.ProtocolException:
The channel received an unexpected input message with Action
'http://tempuri.org/ITransferServiceContract/TransferSpeedChangedCallback'
while closing. You should only close your channel when you are not expecting
any more input messages.
Teraz rozumiem, że błąd, ale niestety nie mogę zagwarantować, aby zamknąć mój kanał po nie otrzymaniu żadnych więcej wejściowych Komunikat ten, jako użytkownik może zamknąć aplikację w dowolnym momencie, dlatego też praca będzie kontynuowana w tle usługi Windows (coś w rodzaju działania skanera antywirusowego). Użytkownik powinien mieć możliwość uruchamiania i zamykania aplikacji narzędzi do zarządzania wygraną tak, jak im się podoba bez zakłóceń.
Teraz błąd, otrzymuję natychmiast po wykonaniu mojego połączenia Unsubscribe()
, które jest drugim ostatnim połączeniem przed zakończeniem aplikacji i co uważam za preferowany sposób rozłączenia klienta WCF. Całe wypisanie się przed zamknięciem połączenia powoduje po prostu usunięcie identyfikatora klienta z tablicy, która była przechowywana lokalnie w usłudze winf usługi wcf (ponieważ jest to WSPÓLNE udostępnienie zarówno przez usługę wygrywania, jak i aplikację Windows, ponieważ usługa wygrywająca może wykonywać pracę w zaplanowane zdarzenia samodzielnie) i po usunięciu tablicy identyfikacyjnej klienta, mam nadzieję, że to powinno być czyste odłączenie.
W wyniku tego, oprócz otrzymania wyjątku, moja aplikacja zawiesza się, interfejs użytkownika jest w całkowitym zamknięciu, paski postępu i wszystko w środku, z wszystkimi znakami wskazującymi na stan wyścigu lub impas WCF [westchnienie], ale jestem teraz bardzo doświadczony w tej dziedzinie i uważam, że jest to sytuacja relatywnie odizolowana i przeczytanie wyjątku takim, jakie jest, nie wydaje mi się, że jest to kwestia "wątku" per se, ponieważ mówi bardziej o kwestii wczesnego odłączenia, które następnie spirale wszystkie moje wątki w chaos, być może powodując blokadę.
Moja Unsubscribe()
podejście na klienta wygląda następująco:
public void Unsubscribe()
{
try
{
// Close existing connections
if (channel != null &&
channel.State == CommunicationState.Opened)
{
proxy.Unsubscribe();
}
}
catch (Exception)
{
// This is where we receive the 'System.ServiceModel.ProtocolException'.
}
finally
{
Dispose();
}
}
i mój Dispose()
metodę, która powinna wykonać czystą odłączyć:
public void Dispose()
{
// Dispose object
if (channel != null)
{
try
{
// Close existing connections
Close();
// Attempt dispose object
((IDisposable)channel).Dispose();
}
catch (CommunicationException)
{
channel.Abort();
}
catch (TimeoutException)
{
channel.Abort();
}
catch (Exception)
{
channel.Abort();
throw;
}
}
}
a usługa WCF Subscription()
odpowiednika i klasę atrybuty (dla odniesienia) w usłudze Windows serwer (tutaj nie ma nic trudnego, a mój wyjątek występuje po stronie klienta):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TransferService : LoggableBase, ITransferServiceContract
{
public void Unsubscribe()
{
if (clients.ContainsKey(clientName))
{
lock (syncObj)
{
clients.Remove(clientName);
}
}
#if DEBUG
Console.WriteLine(" + {0} disconnected.", clientName);
#endif
}
...
}
Interfejs:
[ServiceContract(
CallbackContract = typeof(ITransferServiceCallbackContract),
SessionMode = SessionMode.Required)]
public interface ITransferServiceContract
{
[OperationContract(IsInitiating = true)]
bool Subscribe();
[OperationContract(IsOneWay = true)]
void Unsubscribe();
...
}
interfejs umowy zwrotnej, to nie ma nic bardzo ekscytujące zrobić, po prostu wywołuje zdarzenia za pośrednictwem delegatów itd. Powodem tego jest włączone, aby pokazać ty moje atrybuty. Zrobiłem łagodzić jeden zestaw zakleszczenia już o tym UseSynchronizationContext = false
:
[CallbackBehavior(UseSynchronizationContext = false,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TransferServiceCallback : ITransferServiceCallbackContract
{ ... }
naprawdę nadzieję, że ktoś może mi pomóc! Wielkie dzięki = :)
nie wiem na temat konkretnego problemu, ale dla informacji snafu gwintowania brzmi * ewentualnie * ze względu na to, jak WCF używa Sync kontekstu (który jest za pośrednictwem formularza w WinForm etc). –
Dziękuję Marc, tak, że mnie dopadłeś i złagodziłem jeden zestaw zakleszczeń czytając o tym problemie, sztuczka polegała na ustawieniu 'UseSynchronizationContext = false' na umowie oddzwaniania;) Dodam to do moich przykładów. – GONeale
ah, z prawej; dobrze widzieć, że już to zakryłeś; p –