RONUA
ROmanian .NET User Association --- Asociaţia Romană a Utilizatorilor .NET
Comunitatea dezvoltatorilor software pe .NET Framework

Interceptare erori - discutie

rated by 0 users
This post has 32 Replies | 4 Followers

Top 75 Contributor
Points 1,720
ignatandrei:

Ce erori ati intercepta ?De unde stiti ca sunt toate ? Care ar fi eroare de scoatere a dischetei dupa ce user-ul a selectat din OpenFileDialog discheta ( sau network connection, daca vreti) ? 

Uite rasp mele.

  1. Ce erori as intercepta? -> In cazul in care intrebi: Ce exceptii as intercepta? raspunsul ar fi: Toate exceptiile definite in documentatie.
  2. De unde stiti ca sunt toate? -> La fel ca la intrebarea anterioara, o sa raspund tot pentru exceptii: Nu stiu ca sunt toate. Dar in mod sigur acopera aproape toate cazurile posibile. Mai mult ca sigur ca daca apare alta exceptie care nu e documentata si apare la teste simple (scoaterea dischetei, cablu retea, etc), o sa tin minte sa o prind si pe ea, daca tipul ei are sens pentru operatia care o faci, cu toate ca e putin probabil, in cazul in care functia e documentata bine.
  3. In functie de "mediul" care vrei sa il accesezi, e posibil sa primesti (nu le-am incercat, dar spun cum mi se pare normal sa se intample):
    • IOException - in cazul in care device-ul a fost in timp ce se scria pe el
    • FileNotFoundException, DirectoryNotFoundException - in cazul in care device-ul a fost scos intre click pe open si operatia de scriere (de exemplu, in cazul in care mai ai niste operatii mai lungi intre)
    • UnauthorizedAccessException - in alte cazuri (de exemplu dispozitivul e protejat hard sa fie read-only - SD card, disketa
    • Restul exceptiilor le las pentru ca sunt mai mult pentru validare, iar SecurityException e clar pentru ce e.
    • Mai poti sa tii cont si de faptul ca fereastra Open are si validare (e putin pb sa iti dea un nume de fisier invalid, sau un director)
  4. System.Exception - In cazul in care vreau sa informez utilizatorul, cu conditia sa ies din aplicatie.

Mai vin cu o remarca la ce am scris mai sus: Este posibil ca unele framework-uri sa fie scrise aiurea si sa arunce Exception in loc de exceptii custom. De asemenea, mai este posibil ca frameworkul care il folosesti sa nu acopere anumite cazuri (De exemplu, daca scoti discheta, nu iti da FloppyRemovedException ci iti da IOException sau FileNotFoundException sau DirectoryNotFoundException).

Un exemplu care deriveaza putin (si nu e neaparat valid): In cazul in care ai conexiune la retea ar fi posibil sa iti dea o exceptie de time-out in loc sa dea IOException, sau FileNotFound. Oricum, nu cred ca asta e scopul. Si daca te plangi ca nu iti da alte exceptii e ca si cum te-ai plange ca ti-a luat foc placa de baza si nu primesti o exceptie "FireOnNetworkCardException".

 

--
Numai bine,
Bogdan Maxim

  • | Post Points: 20
Top 75 Contributor
Points 1,720

tudor.t:
Termini aplicatia brusc, iar user-ul isi pierde toate datele nesalvate?

In nici un caz nu am spus asta.

De preferat ar fi sa ai niste "snapshot-uri" sau "copii de siguranta" intermediare, de exemplu cum face Microsoft Word sau Excel.

Ai putea sa ii spui chiar log, cum are SQL Server pt bazele de date.

Daca aplicatia a crapat, nu mai poti fi sigur ca datele care o sa le salvezi sunt valide sau ca operatia de salvare se efectueaza cu succes.

--
Numai bine,
Bogdan Maxim

  • | Post Points: 5
Top 10 Contributor
Points 72,350
bogdan.maxim:
ignatandrei:

Ce erori ati intercepta ?De unde stiti ca sunt toate ? Care ar fi eroare de scoatere a dischetei dupa ce user-ul a selectat din OpenFileDialog discheta ( sau network connection, daca vreti) ? 

Uite rasp mele.

  1. Ce erori as intercepta? -> In cazul in care intrebi: Ce exceptii as intercepta? raspunsul ar fi: Toate exceptiile definite in documentatie.
  2. De unde stiti ca sunt toate? -> La fel ca la intrebarea anterioara, o sa raspund tot pentru exceptii: Nu stiu ca sunt toate. Dar in mod sigur acopera aproape toate cazurile posibile. Mai mult ca sigur ca daca apare alta exceptie care nu e documentata si apare la teste simple (scoaterea dischetei, cablu retea, etc), o sa tin minte sa o prind si pe ea, daca tipul ei are sens pentru operatia care o faci, cu toate ca e putin probabil, in cazul in care functia e documentata bine.
  3. In functie de "mediul" care vrei sa il accesezi, e posibil sa primesti (nu le-am incercat, dar spun cum mi se pare normal sa se intample):
    • IOException - in cazul in care device-ul a fost in timp ce se scria pe el
    • FileNotFoundException, DirectoryNotFoundException - in cazul in care device-ul a fost scos intre click pe open si operatia de scriere (de exemplu, in cazul in care mai ai niste operatii mai lungi intre)
    • UnauthorizedAccessException - in alte cazuri (de exemplu dispozitivul e protejat hard sa fie read-only - SD card, disketa
    • Restul exceptiilor le las pentru ca sunt mai mult pentru validare, iar SecurityException e clar pentru ce e.
    • Mai poti sa tii cont si de faptul ca fereastra Open are si validare (e putin pb sa iti dea un nume de fisier invalid, sau un director)
  4. System.Exception - In cazul in care vreau sa informez utilizatorul, cu conditia sa ies din aplicatie.

Mai vin cu o remarca la ce am scris mai sus: Este posibil ca unele framework-uri sa fie scrise aiurea si sa arunce Exception in loc de exceptii custom. De asemenea, mai este posibil ca frameworkul care il folosesti sa nu acopere anumite cazuri (De exemplu, daca scoti discheta, nu iti da FloppyRemovedException ci iti da IOException sau FileNotFoundException sau DirectoryNotFoundException).

Un exemplu care deriveaza putin (si nu e neaparat valid): In cazul in care ai conexiune la retea ar fi posibil sa iti dea o exceptie de time-out in loc sa dea IOException, sau FileNotFound. Oricum, nu cred ca asta e scopul. Si daca te plangi ca nu iti da alte exceptii e ca si cum te-ai plange ca ti-a luat foc placa de baza si nu primesti o exceptie "FireOnNetworkCardException".

 

Sa rezum:

Cu cunostintele de acum, interceptezi  

dar in nici un caz System.EXCEPTION - lasi .NET sa ii afiseze user-ului fereastra aia magnifica de eroare din care nu o sa inteleaga nimic ... Corect ?

 

  • | Post Points: 20
Top 75 Contributor
Points 1,720

Citeste punctul 4:

System.Exception - In cazul in care vreau sa informez utilizatorul, cu conditia sa ies din aplicatie.

 

--
Numai bine,
Bogdan Maxim

  • | Post Points: 35
Top 10 Contributor
Points 72,350
bogdan.maxim:

Citeste punctul 4:

System.Exception - In cazul in care vreau sa informez utilizatorul, cu conditia sa ies din aplicatie.

 

Scuze,,,, 

  • | Post Points: 5
Top 10 Contributor
Points 22,965
bogdan.maxim:

Citeste punctul 4:

System.Exception - In cazul in care vreau sa informez utilizatorul, cu conditia sa ies din aplicatie.



Ei bine, si eu am fost de aceiasi parere la inceput, daca apare o exceptie neprevazuta sa se inchida aplicatia pentru a evita coruperea de date.

Insa in practica s-a dovedit ca nu e bine sa se intample asta, userii au cerut explicit sa nu se intample asa ceva pentru ca chiar daca e o eroare nu vroiau sa-si piarda munca si de multe ori incercau chiar ei sa vada de ce apare eroarea (cazul exceptional) si ne-o raportau dupa. (La aplicatii mari, si foarte des modificate/customizate nu poti evita 100% din erori indiferent de ce ai face sau cat de mult se testeaza (testarea automata reduce semnificativ numarul de erori, insa repet pt. aplicatii mari customizate si modificate frecvent un numar de erori x e posibil sa apara intru-un interval de timp T)).

Ca urmare toata structura a fost gandita in asa fel incat o exceptie neaspteptata sa nu poata corupe starea globala a aplicatie, adica :

- nu se modifica intr-un block try ..catch variabile globale/shared state/ etc, ci se lucreaza cu copii locale si se face "comit" la terminarea operatiei.

- se poate reveni oricand la starea initiala a unui "work unit" adica se reincarca datele

- o exceptie nu poate bloca aplicatia intr-un loop infinit (nu sunt blocuri try..catch generice in loop-uri, ci doar inafara lor)

- intotdeauna te poti intoarce la pasul anterior ( << Back) fara ca exceptia sa fi corupt datele din pasul precedent.

- blocurile try..catch(exception ex) sunt puse doar pe metodele top level (cum ar fi un event handler sau imediat sub el), nu se prind exceptii in mijlocul codului

- orice exceptie neaspteptata nu mai permite sa se faca comit pe 'unit of work' current.

- orice 'unit  of work' incepe cu validarea datelor de intrare si la final trimite datele de iesire spre urmatorul unit of work (datele de iesire nu sunt datele de intrare modificate, ci un nou set de date)

- se foloseste doar managed code (fara pointeri :) )  deci se poate garanta faptul ca o eroare nu poate corupe o locatie de memorie aleatoare.


Asa ca lucrand in modul asta  se poate evita intruducerea de date corupte in sistem si fara inchiderea aplicatiei in cazul unei exceptii neasteptate.

Eu zic ca in .Net spre deosebire de limbajele native se poate face o arhitectura a unei aplicatii (end user)  in asa fel incat o exceptie neaspteptata sa nu necesite terminarea imediata atat timp cat se asta nu duce la coruperea systemului de operare sau a datelor. Adica daca se lucreaza tranzactional folosind tranzactii explicite unde e posibil (DB, Registry in Vista, NTFS in Vista, etc) sau simularea lor in cod.

  • | Post Points: 35
Top 150 Contributor
Points 615
maro158 replied on Fri, Mar 7 2008 3:28 PM

Adica ceva de genul asta?

public partial class MainForm : Form
{
    SaveFileDialog _saveFileDialog = null;
    string _previousState = null;
    bool checkpointPassed = false;

    public MainForm()
    {
        InitializeComponent();
        _previousState = "INITIAL_STATE";
    }

    [ReliabilityContractAttribute(Consistency.WillNotCorruptState, Cer.MayFail)]
    private void buttonDropTheBomb_Click(object sender, EventArgs e)
    {
        // Sa ne asiguram ca state-ul actual este salvat intr-o forma sau alta.
        string currentState = "andrei";

        // Exceptiile ce vor fi generate nu vor avea efect asupra
        // gradului de reliability al codului din blocul "finally"
        RuntimeHelpers.PrepareConstrainedRegions();
        try
        {
            checkpointPassed = false;

            // Utilizatorul vrea sa salveze date, asa ca e mai
            // indicat SaveFileDialog. OpenFileDialog ar afisa butonul
            // 'Open'. 

            // Urmatorul rand nu apare in codul initial, presupun ca
            // initializarea se face in InitializeComponent()
            // asa ca _saveFileDialog se afla intr-un state necunoscut.
            _saveFileDialog = new SaveFileDialog();

            // Un handler pentru tot ce vrem sa evitam inainte ca user-ul
            // sa inchida dialogul
            _saveFileDialog.FileOk += new CancelEventHandler(_saveFileDialog_FileOk);

            // Procedura GetFolderPath se poate impotmoli
            // din cauza inexistentei profilui de cont, d.ex. daca
            // rulam programul in contul unui alt utililzator, care
            // a fost creat, dar al carui profile path nu a fost inca
            // creat si poate returna String.Empty fiindca nu se verifica
            // rezultatul de la Win32Native.SHGetFolderPath.
            string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

            appDataPath = null;

            if (appDataPath != String.Empty)
                _saveFileDialog.InitialDirectory = appDataPath;

            // Sa nu pui un filtru concret cand salvezi un fisier
            // resp. o extensie default nu e tocmai o idee buna
            _saveFileDialog.DefaultExt = "mft";
            _saveFileDialog.Filter = "My File-Type (*.mft)|*.mft";

            // Ma rog, asta-i dupa necesitatile aplicatiei
            _saveFileDialog.DereferenceLinks = false;

            // Oricat de inocent ar parea urmatorul rand, el poate genera
            // side-effects datorita unor erori in third party shell
            // extensions sau a calificarii functiei Main cu atributul
            // MTAThread. La fel ca in cazul OutOfMemoryException, nu avem ce
            // face, asa ca lasam UnhandledExceptionEventHandler-ul
            // sa-si faca treaba.
            if (_saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                // Cerem permisiuni de accesare a fisierului. In caz de esec, ne
                // trezim cu o SecurityException
                new FileIOPermission(FileIOPermissionAccess.Write, _saveFileDialog.FileName).Demand();

                FileInfo fi = new FileInfo(_saveFileDialog.FileName);

                // Chiar daca avem drepturi de acces, noi vrem sa scriem in fisier
                // asa ca mai bine vedem daca nu e read-only. Astfel evitam proactiv
                // generarea unei exceptii si ii dam posibilitatea utilizatorului sa
                // incerce altceva.
                if ((fi.Attributes & FileAttributes.ReadOnly) != FileAttributes.ReadOnly)
                {
                    // Fisierul ar putea fi deschis exclusiv de alta aplicatie
                    // asa ca mai bine preintampinam situatia asta.
                    if (!IsFileLocked(_saveFileDialog.FileName))
                    {
                        // IOException posibila. Pierdere de date la orizont.
                        File.WriteAllText(_saveFileDialog.FileName, currentState);

                        // Checkpoint
                        checkpointPassed = true;
                    }
                    else
                    {
                        MessageBox.Show("The file you are trying to open is currently in use by another application. No action was taken.");
                        //strategie pentru continuarea executiei
                    }
                }
                else
                {
                    MessageBox.Show("The file you are trying to open is read-only. No action was taken.");
                    ///strategie pentru continuarea executiei
                }
            }
        }
        // Prelucrarea exceptiilor de mai jos nu afecteaza stabilitatea
        // aplicatiei, ci pe de-o parte furnizeaza utilizatorului un mesaj
        // simplu, care sa-l ajute sa gaseasca un remediu si pe de alta
        // parte logeaza informatii detaliate destinate bug fixing-ului sau
        // security audit-ului cf. politicii in vigoare. O buna parte din
        // posibilele exceptii legate de handling-ul fisierelor sunt preintampinate
        // de setting-urile SaveFileDialog-ului.
        // Restul exceptiilor vor fi prinse fie in UnhandledExceptionEventHandler,
        // fie in ThreadExceptionEventHandler.
        catch (System.UnauthorizedAccessException ex)
        {
            //Detaliile legate de Exception, InnerException etc. pot fi scrise acum in log
            MessageBox.Show("The file can not be written because of insufficient access rights. Message: " + ex.Message + " Your data will be saved to C:\\yourdata.txt.");
        }
        catch (System.Security.SecurityException ex)
        {
            //Detaliile legate de Exception, InnerException etc. pot fi scrise acum in log
            MessageBox.Show("The file could not be written due to a security exception. Message: " + ex.Message + " Your data will be saved to C:\\yourdata.txt");
        }
        finally
        {
            if (!checkpointPassed)
                // state-ul precedent nu e modificat, iar state-ul current,
                // care nu a putut fi scri in fisier, e persistat intr-o forma sau alta
                TrySaveYourData(currentState);
            else
                // reliable state transition
                _previousState = currentState;

            //Clean-up
            if (_saveFileDialog != null)
                _saveFileDialog.Dispose();

            checkpointPassed = false;

            MessageBox.Show(String.Format("Previous state: {0}\nCurrent state: {1}",_previousState, currentState));
        }
    }

    void TrySaveYourData(string State)
    {
        // Incercam sa salvam ce poate fi salvat
    }

    void _saveFileDialog_FileOk(object sender, CancelEventArgs e)
    {
        // Aici putem face teste suplimentare inainte ca
        // utilizatorul sa inchida dialogul
        string selectedFilePath = _saveFileDialog.FileName;
        string fileExtension = Path.GetExtension(selectedFilePath);

        if (fileExtension != ".mft")
        {
            MessageBox.Show("This file type is not supported");
            e.Cancel = true;
        }
    }

    public bool IsFileLocked(string fileName)
    {
        try {
            using (FileStream stream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)){}
        }
        catch (System.IO.IOException ex) {
            return true;
        }

        return false;
    }

}

  • | Post Points: 5
Top 25 Contributor
Points 4,585
Ovidiu replied on Fri, Mar 7 2008 7:40 PM

Cryogenic:

[......] 

Ca urmare toata structura a fost gandita in asa fel incat o exceptie neaspteptata sa nu poata corupe starea globala a aplicatie, adica :

- nu se modifica intr-un block try ..catch variabile globale/shared state/ etc, ci se lucreaza cu copii locale si se face "comit" la terminarea operatiei.

- se poate reveni oricand la starea initiala a unui "work unit" adica se reincarca datele

- o exceptie nu poate bloca aplicatia intr-un loop infinit (nu sunt blocuri try..catch generice in loop-uri, ci doar inafara lor)

- intotdeauna te poti intoarce la pasul anterior ( << Back) fara ca exceptia sa fi corupt datele din pasul precedent.

- blocurile try..catch(exception ex) sunt puse doar pe metodele top level (cum ar fi un event handler sau imediat sub el), nu se prind exceptii in mijlocul codului

- orice exceptie neaspteptata nu mai permite sa se faca comit pe 'unit of work' current.

- orice 'unit  of work' incepe cu validarea datelor de intrare si la final trimite datele de iesire spre urmatorul unit of work (datele de iesire nu sunt datele de intrare modificate, ci un nou set de date)

- se foloseste doar managed code (fara pointeri :) )  deci se poate garanta faptul ca o eroare nu poate corupe o locatie de memorie aleatoare.


[......]

Există termeni și tehnici consacrate pentru problemele astea. Se cheamă tranzacții - volatile și persistente. Dacă tot codul pe care îl scrii are garanții tranzacționale, e ok și să tragi calculatorul din priză la momente aleatoare (iar excepția asta chiar nu poate fi prinsă), nu vei corupe date sub nici o formă. Există un nume și pentru tehnica asta de programare - "crash-only code". Chiar și dacă scrii cod crash-only, cu garanții tranzacționale foarte puternice, realitatea e că buguri tot rămân în cod. Recomandarea mea rămâne ca aplicațiile să-și oprească execuția cât mai repede atunci când se prind că au ajuns într-o stare inconsistentă (de obicei asta înseamnă un cod de eroare sau o excepție pe care nu știu să o trateze). Tehnica asta se numește fail-fast, e veche de când lumea (e menționată prin "The Art of UNIX Programming" de ex) și ideea e că vrei ca aplicația să crape cât mai aproape de momentul când s-a manifestat bugul. Cu cât crapă mai târziu, cu atât e mai greu de depanat.

La Microsoft codul pentru cele mai multe produse e testat foarte serios pentru a găsi probleme de robustețe. Asta se face prin teste de stres, prin fault injection și prin alte câteva tehnici. Conceptele astea n-au fost inventate la Microsoft, sunt știute de când lumea. Mi se pare totuși fascinant că lucruri elementare și vechi de când lumea gen fail-fast încă mai sunt dezbătute aprins. Asta implică ceva ce știam de fapt - în general, marea majoritate a programatorilor nu atacă în mod proactiv problema robusteții codului ci doar reacționează la probleme pe măsură ce apar. Dacă aș avea timp de așa ceva, e material pentru câteva zeci de blog posturi aici...

Ovidiu
This posting is provided "AS IS" with no warranties, and confers no rights.
  • | Post Points: 35
Top 10 Contributor
Points 72,350
Ovidiu:

La Microsoft codul pentru cele mai multe produse e testat foarte serios pentru a găsi probleme de robustețe. Asta se face prin teste de stres, prin fault injection și prin alte câteva tehnici. Conceptele astea n-au fost inventate la Microsoft, sunt știute de când lumea. Mi se pare totuși fascinant că lucruri elementare și vechi de când lumea gen fail-fast încă mai sunt dezbătute aprins. Asta implică ceva ce știam de fapt - în general, marea majoritate a programatorilor nu atacă în mod proactiv problema robusteții codului ci doar reacționează la probleme pe măsură ce apar. Dacă aș avea timp de așa ceva, e material pentru câteva zeci de blog posturi aici...

Ovidiu,

Ce sa inteleg de aici, in cazul simplu al codului de care a fost vorba, vezi http://ronua.ro/CS/forums/permalink/203916/203864/ShowThread.aspx#203864

    1. Ca interceptezi ce exceptii stii(File.IO.Exception) dar nu System.Exception, si lasi  dialogul ala de .NEt ca a fost o eroare sa se afiseze utilizatorului( apropo : si ala are "continue"  or "quit" - nu prea e fail fast... - de ce or fi facut-o asa ?)

    2. Esti de parerea lui Bogdan, http://ronua.ro/CS/forums/permalink/203864/203903/ShowThread.aspx#203903, si interceptezi si System.Exception , dar cu conditia sa iesi din aplicatie

3. Alta opinie ? 


Multumesc,

Andrei 

 PS: scuze tuturor pentru scrierea in graba a FileOpen in loc de  FileSave, cum bine a scris maro158 aici

http://ronua.ro/CS/forums/permalink/203916/203915/ShowThread.aspx#203915
 

  • | Post Points: 20
Top 150 Contributor
Points 615
maro158 replied on Fri, Mar 7 2008 10:54 PM

Uite ca acum am ajuns de la tratarea exceptiilor in C# la .NET FCL si la System.Transactions, si nu mai lipseste mult si ajungem la obiectele imutabile din limbajele functionale. Toate au indreptatirea lor. Dar intorcandu-ne la exemplul lui Andrei, tu ce ai face, Ovidiu?

try
{
   openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

   if( openFileDialog.ShowDialog(this) == DialogResult.OK)
   {
      File.WriteAllText(openFileDialog.Filename,"andrei");
   } 
}
catch(Exception ex)
{
   // In cazul unei exceptii asincrone, n-o sa ajungem niciodata aici.
   Environment.FailFast(ex.Message);
}
finally
{
   // N-o sa ajungem niciodata aici, daca FailFast executa.
}

Hmmm...

  • | Post Points: 5
Top 25 Contributor
Points 4,585
Ovidiu replied on Sat, Mar 8 2008 7:28 PM
ignatandrei:

Ovidiu,

Ce sa inteleg de aici, in cazul simplu al codului de care a fost vorba, vezi http://ronua.ro/CS/forums/permalink/203916/203864/ShowThread.aspx#203864

    1. Ca interceptezi ce exceptii stii(File.IO.Exception) dar nu System.Exception, si lasi  dialogul ala de .NEt ca a fost o eroare sa se afiseze utilizatorului( apropo : si ala are "continue"  or "quit" - nu prea e fail fast... - de ce or fi facut-o asa ?)

    2. Esti de parerea lui Bogdan, http://ronua.ro/CS/forums/permalink/203864/203903/ShowThread.aspx#203903, si interceptezi si System.Exception , dar cu conditia sa iesi din aplicatie

3. Alta opinie ? 


Multumesc,

Andrei 

 PS: scuze tuturor pentru scrierea in graba a FileOpen in loc de  FileSave, cum bine a scris maro158 aici

http://ronua.ro/CS/forums/permalink/203916/203915/ShowThread.aspx#203915
 

Important e să nu înghiți excepții despre care nu știi nimic și, despre care, în consecință nu știi cum să le tratezi. E acceptabil și să nu prinzi excepții necunoscute deloc, sau să le prinzi, dar să termini blocul cu un "throw;" sau cu Environment.FailFast.

Nu știu exact la ce dialog te referi, dar presupun că e cel de excepție netratată din WinForms. Nu zice nimeni că la Microsoft oamenii nu fac greșeli Smile. În v1.0, din păcate, autorii frameworkului au pus și în CLR, și în unele componente de nivel mai înalt cod care face exact greșelile de care spuneam că ar trebui evitate.

Una din ele e cea din Windows Forms - procedura universală de fereastră prinde excepțiile netratate care provin din handlere și are opțiunea de a continua execuția. E o idee proastă din motivele discutate deja, și care nu știu dacă poate fi eliminată din setări. Dacă-mi amintesc bine, din cod e destul de ușor să influențezi comportamentul ăsta (și să-l îndrepți) - vezi Application.ThreadException. Din Framework nu poate fi eliminat cu totul, pentru că acum există deja o groază de aplicații care se bazează pe versiunea greșită. În consecință, pentru aplicații WinForms, ce-am spus mai sus trebuie transformat în "E acceptabil și să nu prinzi excepții necunoscute deloc (câtă vreme știi că top-level exception handler-ul funcționează corect și distruge procesul când prinde o excepție necunoscută) [...]".

Cel mai cunoscut exemplu e faptul că în 1.0, threadurile din CLR thread pool înghițeau toate excepțiile netratate care ajungeau la baza stivei. După ce s-au convins oamenii că în practică, pe clienți nu-i distrează ca aplicația să înceapă să aibă probleme la momentul X și ca problemele să devină vizibile la momentul X + 7 zile, în 2.0 comportamentul a fost schimbat (în mod implicit, excepțiile netratate în thread pool trag jos tot AppDomain-ul, dacă-mi amintesc bine) și cred că există un app-compat switch pentru a reveni la comportamentul vechi în caz că cineva chiar îl mai dorește.

Cel mai sinistru exemplu e AccessViolationException. Simplul fapt că CLR-ul încearcă să mai execute un pic de cod după ce un AV a avut loc pe undeva e sinucidere. Din păcate, nu cred că excepția asta va fi eliminată complet din BCL prea curând, tot din motive de compatibilitate.

Dacă vreți o lectură faină, căutați subcapitolul "Basics of the Unix Philosophy" (care e de fapt un "basics of software engineering") - de ex. pe Google Books. 

Ovidiu
This posting is provided "AS IS" with no warranties, and confers no rights.
  • | Post Points: 35
Top 150 Contributor
Points 615
maro158 replied on Sun, Mar 9 2008 1:09 AM

Mersi pentru "Basics of the Unix Philosophy", tocmai am terminat de citit capitolul. La obiect. Succint. Si foarte interesant. Cu cateva ore inainte citisem un articol oarecum la antipol ("Treating Bugs As Allergies: A Safe Method for Surviving Software Failures"), asa ca acum ma aflu intr-un state tranzient, deloc atomic, si plin de perplexitate. Nu-mi ramane decat sa "fail noisily and as soon as possible."

  • | Post Points: 5
Top 10 Contributor
Points 22,965

Ovidiu,

.Net-ul nu e nici unix si nici cod nativ. O aplicatie de .Net poate fi segmentata in asa fel incat o exceptie sa nu necesite terminarea intregului proces. Sub unix unde o exceptie iti lasa intradevar sistemul intr-o stare nedefinita din cauza modelului de memorie adica din cauza poiterilor. In .Net sunt safehandles, critical finalization,  constrained execution regions, application domains, si altele. Toate sunt mecanisme de protectie inpotriva failure-urilor. In unix nu exista nici pe departe asa ceva, daca aparea o exceptie era imposibil de stiut daca s-a corupt memoria, daca s-a creat un resource leak sau orice alta problema ar fi aparut. In .Net ai niste garantii f. puternice date de CLR in aceasta privinta si anume ca nu se poate corupe memoria, ca nu vor exista "resource leaks" si asa mai departe. Exemplu perfect in aceasta privinta e Sql Server 2005, orice exceptie s-ar arunca intr-o procedura stocata managed, nu e nevoie de terminarea intregului process ci doar a appdomain-ului respectiv. Ba chiar mai mult terminarea uni app domain chiar si intr-un mod brutal (cu TreadAbbortException) nu duce la coruperea enviroment-ului si a datelor. Acelasi lucru se poate obtine si intr-o aplicatie .net desktop in procent destul de mare (pt. ca nici .Net-ul nu e perfect si mai are scapari, si noi la fel).

Iar referitor la faptul ca, catch (Exception ex) duce la probleme de debug, daca faci asta doar top level si-ti loghezi exceptia si timpul (cu tot cu stack trace, avand grija ca sa nu-l distrugi niciodata) atunci nu mai sunt probleme in a gasi un bug.

A nu folosi catch (Exception ex) e un lux pe care nu ti-l poti permite atat timp cat ti se cere explicit ca aplicatia ta sa nu crape si nu ai nici resurse comparabile cu cele de la Microsoft pentru testarea ei sau pentru dezvolatare. Asa ca in conditiilea astea iti ramane doar sa faci ce stii mai bine pentru a nu-ti da cu stangul in dreptul adica sa faci in asa fel incat sa fie cat mai robusta aplicatia iar o exceptie (care o fi ea) sa nu-ti corupa datele si in plus pe langa asta nici sa nu ascunzi bug-urile sa fie de negasit.

E foarte adevarat ce spui tu (si altii) ca daca termini aplicatia cat mai aproape de momentul exceptiei e mai usor de gasit problema pentru noi programatorii. Dar noi nu facem aplicatii ca sa fie usor pentru noi, in detrimetul utilizatorului care poate sa-si piarda munca (poate cateva ore bune) doar pentru a ne usura debug-ul ulterior.

Nu e greu sa nu prinzi exceptii neasteptate cand stii ca oricum aplicatia se testeaza automat pe sute de configuratii OS + Hardare intr-o ferma de testare cu zeci de mii te unit test-uri. Insa nu toti au ferme  de servere de test cu zeci de intalari de OS sau sau resurse umane pentru a testa la nivelul Microsoft. Insa cu toate aceastea si de la noi si de la Microsoft se asteapta aplicatii fiabile.

Asta e realitatea in care traiesc eu, si pana nu-mi arata cineva un exeplu cu ce rau se poate intampla din cauza lui catch (Exception ex) (inafara de creere a unui bug care nu tine de asta ci de ce faci mai departe), pana atunci nu sunt totalmente convins ca e raul de pe lume sa prinzi base exception in anumite situatii controlate.



  • | Post Points: 35
Top 10 Contributor
Points 24,890
MrSmersh replied on Sun, Mar 9 2008 12:26 PM
O sa revin la subiect tocmai fac ceva in jurul unei probleme din asta chiar consumare procesare procesare aruncare... De fapt in DAL prin tot de la DB cele care ne intereseaza sint categorizate (am aceeasi exceptie la aceasi situatie indiferent de baza de date si de metoda de access si providerul folosit) si toate (98%) lasate mai departe. Si acuma MS in SQL a umblat putin la clase de eroare asa ca unele se scurg afara in pielea originala, si acuma am intrat la retestare cu astea sa gasim toate surprizele.
Si off topi dar ma maninca: dar la testare se pare ca MS a trecut la virtualizare si de aici mai multe gherle ca inainte, mai ieftin dar nu asa de eficient...
  • | Post Points: 20
Top 10 Contributor
Points 72,350

MrSmersh:
O sa revin la subiect tocmai fac ceva in jurul unei probleme din asta chiar consumare procesare procesare aruncare... De fapt in DAL prin tot de la DB cele care ne intereseaza sint categorizate (am aceeasi exceptie la aceasi situatie indiferent de baza de date si de metoda de access si providerul folosit) si toate (98%) lasate mai departe. Si acuma MS in SQL a umblat putin la clase de eroare asa ca unele se scurg afara in pielea originala, si acuma am intrat la retestare cu astea sa gasim toate surprizele.

Exemple exemplare ? 

MrSmersh:

Si off topi dar ma maninca: dar la testare se pare ca MS a trecut la virtualizare si de aici mai multe gherle ca inainte, mai ieftin dar nu asa de eficient...

Exemple exemplare ? 

  • | Post Points: 20
Page 2 of 3 (33 items) < Previous 1 2 3 Next > | RSS


Urmatorul Facebook pe zona de mobile vine in Romania!
Vrei sa lucrezi intr-un startup american listat la bursa din US?
(Numai) daca esti un A-player,
CLICK AICI

(c) RONUA 2004-2009
Powered by Community Server (Commercial Edition), by Telligent Systems