niedziela, 15 września 2013

Obsługa wyjątków w WCF

WCF pozwala na przekazywanie wyjątków do klienta. Oczywiście wyjątki, które znamy z .NET nie możemy wprost przesyłać do klienta - należy pamiętać, że nasz serwis może być obsługiwany przez klientów innych platform.
Wyjątki którymi się posługujemy w WCF są typu FaultException oraz generyczna odmiana FaultException<T>. Aby zaznaczyć, że metoda może zwrócić wyjątek należy oznaczyć ją atrybutem FaultContract(typeof(ExceptionType)):


Code:
        [OperationContract]
        [FaultContract(typeof(string))]
        string GetData(int value);

Metodę następnie możemy zaimplementować w następujący sposób:


Code:
        public string GetData(int value)
        {
            if (value <= 0)
            {
                throw new FaultException<string>("Value must be greater than 0", "Incoret value");
            }
            return string.Format("You entered: {0}", value);
        }

Ogólnie przyjęte jest, że nie należy wysyłać do klienta oryginalnego wyjątku. Zobaczmy na poniższy diagram:



Z diagramu wynika, że oryginalny wyjątek przed wysłaniem do klienta musi zostać przetworzony. Nie przekazujemy oryginalnego wyjątku klientowi, aby nie ujawniać mu wewnętrznej struktury naszego serwisu. Ogólnie przyjmuje się, że po stronie serwisu:
  • przechwytujemy zawartość wyjątku, kto i kiedy go spowodował oraz oryginalne żądanie
  • logujemy zawartość Exception do bazy lub pliku
  • tworzymy identyfikator zgłoszenia - ułatwi to rozmowę pomocy technicznej z danym klientem
Klientowi przekazujemy następujące informacje:
  • wiadomość typu: "W serwisie wystąpił błąd..."
  • kod błędu (np HTTP 5xx)
  • dodajemy także informacje kontaktowe z pomocą techniczną oraz identyfikator problemu
Powyższe działania określane są często mianem Sanitizing Response - tłumacząc na polski usuwamy z odpowiedzi to co nie jest potrzebne klientowi i potencjalnie szkodliwe dla nas.


Aplikacja kliencka następnie może przechwycić wyjątek, tak jak każdy inny. Przykładowy kod klienta:


Code:
            var channelFactory = new ChannelFactory<IService1>(new BasicHttpBinding(),
                new EndpointAddress("http://localhost.:30000/MyService/"));
            var channel = channelFactory.CreateChannel();
            try
            {
                var data = channel.GetData(-5);
                Console.WriteLine(data);
            }
            catch (FaultException<string> ex)
            {
                Console.WriteLine(ex.Reason);
                Console.WriteLine(ex.Detail);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            ((IClientChannel)channel).Close();

Brak komentarzy:

Prześlij komentarz