1 Востаннє редагувалося boshik1983 (19.12.2017 13:08:27)

Тема: Exception при виклику метода WCF Сервіса

Пишу програму для автоматизації роботи та зберігання даних певної організації
Виникли певні складнощі з розумінням роботи WCF Сервіса
Код писати тут не буду, бо нереально багато і суть питання в логіці, а не коді
Програма багаторівнева:
1) WPF Інтефейс користувача (усілякі форми, дата гріди і т.п. + первинна перевірка даних в оборобниках)
2) Бібліотека бізнес логіки(створюється WCF клієнт та викликаються його методи)
3) WCF Сервіс (звичайний посередник)
4) Бібліотека бізнес логіки (Ретельна перевірка даних)
5) ДАЛ (запис, читання, перевірка по БД)

Коротше, суть проблеми:
Потрібно додати нового менеджера в базу даних. Дії наступні:
1. Заповнюємо необхідні поля WPF форми (!!! усі вони є обов*язковими для БД)
2. Робимо первинну перевірку введених даних і викликаємо метод додавання менеджера на стороні WCF Сервіса
3. WCF Сервіс викликає відповідний метод з Бізнес логіки
4. БЛЛ (бізнес логіка) робить різні перевірки (існування лоігна, мейла в БД ...), конвертації даних і звертається до ДАЛа (якщо все в порядку, звісно), щоб той додав нового менеджера в БД
5. ДАЛ робить свою непильну роботу і тут нам має бути щастя

На кожному етапі, починаючи з третього(включно), усі методи повертають нам екземпляр створеного мною класу Response {Exception ex, bool Result, string Message}.

Нарешті ми підійшли до суті проблеми.
Якщо я заповнюю усі поля правильно (валідними даними), то менеджер успішно додається в БД і мені повертається наступний Response {ex == null, Result == true, Message == "Користувач такий-то успішно доданий в базу даних"}.
Якщо якась із перевірок відловлює помилку, то мені повертається Response з усіма відповідними даними, наприклад {ex == null, Result == false, Message == "Користувач з таким логіном уже існує"}

Але, якщо я додаю менеджера у якого замість імені введено декілька пробілів (решта даних валідна), то ДАЛ, при спробі додати такого користувача, видає Exception, блок catch записує даний Exception в Response і той повертається WCF Сервісу. Але тут стається магія і WCF Сервіс, замість того, щоб показати нам Exception ДАЛа, генерує власний Exception, скрін якого я прикріпив до даної теми.

питання досить очевидне: чому WCF Сервіс викидає власний Exception, а не повертає той, що йому передали?

Post's attachments

Exception.png 54.75 kb, 153 downloads since 2017-12-19 

2

Re: Exception при виклику метода WCF Сервіса

Я розумію, що потрібно ретельніше перевіряти дані і т.п., але така ж фігня відбувається і тоді, коли БД з певних причин недоступна: ДАЛ генерує Exception, який повертається WCF Сервісу, але останній тупо крашиться і розриває з*єднання.

Метод, який звертається до Сервіса

public ResponseToUser AddNewManager(AdvertisingManagerPoco Manager)
        {
            ResponseToUser toReturn = new ResponseToUser();
            try
            {
                ResponsePOCO response = client.AddManager(new AdvertisingManager()
                {
                    AdvertisingManagerName = Manager.AdvertisingManagerName,
                    AdvertisingManagerSurname = Manager.AdvertisingManagerSurname,
                    AdvertisingManagerPhoneNumber = Manager.AdvertisingManagerPhoneNumber,
                    UserEmail = Manager.UserEmail,
                    IsDisabled = false,
                    UserLogin = Manager.UserLogin,
                    UserPassword = Manager.UserPassword
                });
                toReturn.Ex = response.Ex;
                toReturn.Message = response.Message;
                toReturn.Result = response.Result;
            }
            catch (Exception ex)
            {
                toReturn.Ex = ex;
                toReturn.Message = ex.Message;
                toReturn.Result = false;
            }

            return toReturn;
        }

Метод на стороні Сервіса

        public ResponsePOCO AddManager(AdvertisingManager newManager)
        {
            return adder.AddNewManager(newManager);
        }

3

Re: Exception при виклику метода WCF Сервіса

Можливо тому, що вам треба опрацювати виключення у вашому ДАЛ та сгенерувати наступне користуючись throw?

Подякували: 0xDADA11C71

4

Re: Exception при виклику метода WCF Сервіса

varkon написав:

Можливо тому, що вам треба опрацювати виключення у вашому ДАЛ та сгенерувати наступне користуючись throw?


Навряд. Я писав, що "ДАЛ, при спробі додати такого користувача, видає Exception, блок catch записує даний Exception в Response і той повертається WCF Сервісу" (це я прослідкував). Тобто метод adder.AddNewManager(newManager); повертає згенероване ДАЛом виключення
Ось метод на стороні ДАЛа:

public Response AddManager(AdvertisingManager newManager)
        {
            Response result = new Response();
            try
            {
                fivePlus.Users.Add(newManager);
                fivePlus.SaveChanges();
                result.Result = true;
                result.Message = $"Менеджер {newManager.AdvertisingManagerName} успішно доданий в базу даних";
            }
            catch (Exception ex)
            {
                result.Ex = ex;
                result.Message = $"При додаванні менеджера {newManager.AdvertisingManagerName} в базу даних сталася помилка!";
            }
            return result;
        }

5

Re: Exception при виклику метода WCF Сервіса

Можливе виключення в блоці обробника виключень catch, тому так.

6 Востаннє редагувалося varkon (19.12.2017 21:17:22)

Re: Exception при виклику метода WCF Сервіса

Прихований текст
boshik1983 написав:
varkon написав:

Можливо тому, що вам треба опрацювати виключення у вашому ДАЛ та сгенерувати наступне користуючись throw?


Навряд. Я писав, що "ДАЛ, при спробі додати такого користувача, видає Exception, блок catch записує даний Exception в Response і той повертається WCF Сервісу" (це я прослідкував). Тобто метод adder.AddNewManager(newManager); повертає згенероване ДАЛом виключення
Ось метод на стороні ДАЛа:

public Response AddManager(AdvertisingManager newManager)
        {
            Response result = new Response();
            try
            {
                fivePlus.Users.Add(newManager);
                fivePlus.SaveChanges();
                result.Result = true;
                result.Message = $"Менеджер {newManager.AdvertisingManagerName} успішно доданий в базу даних";
            }
            catch (Exception ex)
            {
                result.Ex = ex;
                result.Message = $"При додаванні менеджера {newManager.AdvertisingManagerName} в базу даних сталася помилка!";
            }
            return result;
        }

Поясніть будь ласка що ви маєте на увазі коли кажете:

Тобто метод adder.AddNewManager(newManager); повертає згенероване ДАЛом виключення

Я не знаю такого терміна "поверає виключення". Ви можете опрацювати  та сгенерувати його (або нове) далі щоб його обробив хтось інший. У вашому коді я бачу що ви "обробляєте" виключення але ви не генеруєте нічого. Якщо ви хочете щоб ваше виключення опрацьювувалося на рівні контроллера, чи шо там у вас - йому треба не передавати обьєкт з виключенням а генерувати та обробляти виключення на рівні контроллера.

7 Востаннє редагувалося varkon (19.12.2017 21:14:56)

Re: Exception при виклику метода WCF Сервіса

Що б ви не вважали що це я "аби сказати" - цитата з документації:

Things to Avoid When Throwing Exceptions

The following list identifies practices to avoid when throwing exceptions:

    Exceptions should not be used to change the flow of a program as part of ordinary execution. Exceptions should only be used to report and handle error conditions.

    Exceptions should not be returned as a return value or parameter instead of being thrown.

    Do not throw System.Exception, System.SystemException, System.NullReferenceException, or System.IndexOutOfRangeException intentionally from your own source code.

    Do not create exceptions that can be thrown in debug mode but not release mode. To identify run-time errors during the development phase, use Debug Assert instead.

Переклад потрібен?

Подякували: leofun011

8 Востаннє редагувалося boshik1983 (20.12.2017 12:37:55)

Re: Exception при виклику метода WCF Сервіса

Поясніть будь ласка що ви маєте на увазі коли кажете:

    Тобто метод adder.AddNewManager(newManager); повертає згенероване ДАЛом виключення

Послідовність викликів методів при додаванні нового менеджера починаючи з Сервіса:
WCF Service :             

public ResponsePOCO AddManager(AdvertisingManager newManager)
            {
                return adder.AddNewManager(newManager);
            }

BLL (логіка)  :

public ResponsePOCO AddNewManager(POCOlib.AdvertisingManager managerPoco)
        {
            ResponsePOCO rP = new ResponsePOCO();

            if (verifier.UserLoginExist(managerPoco.UserLogin).Result == false)
            {
                if (verifier.UserEmailExist(managerPoco.UserEmail).Result == false)
                {
                    BoardsDB.DBTables.AdvertisingManager managerD = Convertor.ManagerPocoToDB(managerPoco); //статичний метод конвертації
                    managerD.Salt = GenerateSalt();
                    managerD.UserPassword = HashPassword(managerD.Salt, managerD.UserPassword);
                    Response r = adder.AddManager(managerD);
                    rP.Result = r.Result;
                    rP.Ex = r.Ex;
                    rP.Message = r.Message;
                }
                else
                {
                    rP.Result = false;
                    rP.Message = $"Користувач з електронною поштою {managerPoco.UserEmail} уже існує";
                }
            }
            else
            {
                rP.Result = false;
                rP.Message = $"Користувач з логіном {managerPoco.UserLogin} уже існує";
            }
            return rP;
        }

ДАЛ :

public Response AddManager(AdvertisingManager newManager)
        {
            Response result = new Response();
            try
            {
                fivePlus.Users.Add(newManager);
                fivePlus.SaveChanges();
                result.Result = true;
                result.Message = $"Менеджер {newManager.AdvertisingManagerName} успішно доданий в базу даних";
            }
            catch (Exception ex)
            {
                result.Ex = ex;
                result.Message = $"При додаванні менеджера {newManager.AdvertisingManagerName} в базу даних сталася помилка!";
            }
            return result;
        }

Як бачите, кожен метод повертає клас Response (або ResponsePOCO, що є те саме, тільки позначений Дата контрактом для Сервіса).
Логіка у мене була така, що користувач, при виникненні помилок в роботі, мав би бачити де і яка помилка виникла.
Якщо він хоче використати, наприклад, існуючий логін, то я в ході перевірок в Логіці записую відповідне повідомлення в Response.Message, полю Response.Result присвоюю false(по замовчуванню) і повертаю клас  Response в користувацький додаток.
Якщо ж у мене на якомусь рівні виникає Exception, то я записую це Виключення в поле Response.Exception, додаю відповідне повідомлення в Response.Message і залишаю Response.Result false. Потім повертаю клас Response в користувацький додаток.
Але при виникненні Виключень моя логіка зламалась.

9

Re: Exception при виклику метода WCF Сервіса

Якщо ви хочете щоб ваше виключення опрацьювувалося на рівні контроллера, чи шо там у вас - йому треба не передавати обьєкт з виключенням а генерувати та обробляти виключення на рівні контроллера.

А можна на прикладі кода показати, бо я тут вичитав, що для Сервіса взагалі потрібно генерувати FaultException, щоб з*єднання не крашилось?
Можете змінити метод ДАЛа, щоб я второпав врешті?

    public Response AddManager(AdvertisingManager newManager)
            {
                Response result = new Response();
                try
                {
                    fivePlus.Users.Add(newManager);
                    fivePlus.SaveChanges();
                    result.Result = true;
                    result.Message = $"Менеджер {newManager.AdvertisingManagerName} успішно доданий в базу даних";
                }
                catch (Exception ex)
                {
                    result.Ex = ex;
                    result.Message = $"При додаванні менеджера {newManager.AdvertisingManagerName} в базу даних сталася помилка!";
                }
                return result;
            }

10

Re: Exception при виклику метода WCF Сервіса

boshik1983 написав:

Якщо ви хочете щоб ваше виключення опрацьювувалося на рівні контроллера, чи шо там у вас - йому треба не передавати обьєкт з виключенням а генерувати та обробляти виключення на рівні контроллера.

А можна на прикладі кода показати, бо я тут вичитав, що для Сервіса взагалі потрібно генерувати FaultException, щоб з*єднання не крашилось?
Можете змінити метод ДАЛа, щоб я второпав врешті?

    public Response AddManager(AdvertisingManager newManager)
            {
                Response result = new Response();
                try
                {
                    fivePlus.Users.Add(newManager);
                    fivePlus.SaveChanges();
                    result.Result = true;
                    result.Message = $"Менеджер {newManager.AdvertisingManagerName} успішно доданий в базу даних";
                }
                catch (Exception ex)
                {
                    result.Ex = ex;
                    result.Message = $"При додаванні менеджера {newManager.AdvertisingManagerName} в базу даних сталася помилка!";
                }
                return result;
            }

Шось типа цього:

    catch (Exception ex)
                {
                   //If need to log this
                    throw ex;
                }

У BLL

    public int AddNewManager(POCOlib.AdvertisingManager managerPoco)
            {
                   // Не дуже зрозуміло навіщо вам цілий обьєкт респонзу коли ви можете формувати код помилки 
                   // та вертати його сервісу. Те як ви це робите - створить вам чимало проблем. Повертайте код помилки
                  // а помилки вже опрацьовуйте у сервісі чи що там у вас. 
                //ResponsePOCO rP = new ResponsePOCO();
                        BoardsDB.DBTables.AdvertisingManager managerD = Convertor.ManagerPocoToDB(managerPoco); //статичний метод конвертації 
                     
                     //   managerD.Salt = GenerateSalt();
                     //   managerD.UserPassword = HashPassword(managerD.Salt, managerD.UserPassword);
                  if(! CheckPasswordAndGenerateHash( managerD)){
                    return SERVICE_USER_PASSWORD_NOT_CORRECT;
                  }
                  try{
                        adder.AddManager(managerD);  
                 }catch(/*Тут ексептион першого типу - наприклад дублювання праймарі ид*/ ){
                      /*Щось робимо*/
                       . ..
                     return SERVICE_DUBLE_PM_ID; // abo номер помилки з виключення
                }catch(/*Тут ексептион другого типу - нема звьязку з БД*/ ){
                    /*Щось робимо*/
                    ...
                   return SERVICE_DB_OFFLINE
                }catch(/*Тут ексептион третього типу - порушення унікальності логіна або пошти*/ ){
                  /*Щось робимо*/
                      ...
                 return SERVICE_DUBLICATE_USER;
                }       
                    
                return SERVICE_NONE_ERROR;
            }

У вашому сервісі створюєте хелпер який формує повідомлення необхідною мовою, пишите його до логу або показуєте користувачу.
Це звичайно приклад - але зверніть увагу наскільки це зручніше. Звичайно енуми типів помилок треба теж десь сформувати.

Подякували: 0xDADA11C71

11

Re: Exception при виклику метода WCF Сервіса

Прихований текст

впевнений на 99%, що проблема в російській локалізації чогось там

12

Re: Exception при виклику метода WCF Сервіса

Локалізація Українська і немає жодного відношення до проблеми

13

Re: Exception при виклику метода WCF Сервіса

Кортоше, як завжди допомогли....
Проблема в тому, що при роботі з WCF сервісом потрібно уникати Вийнятків типу .NET (тобто звичний усім Exception), оскільки 1) тільки .NET додатки можуть працювати з такими вийнятками, а до WCF сервіса можуть звертатися усі кому завгодно 2) Unhandled Exceptions привоядть до краша та розриву з*єднання з Сервісом.
Тому усі Вийнятки потрібно обробляти і перетворювати їх на FaultExceptions. Це якщо коротко.

Подякували: 0xDADA11C7, leofun012