Aplikačný blok výnimok pre .Net aplikácie

Publikoval Michal Kočí dňa 25.1.2005 o 23:23 v kategórii .Net

Microsoft na svojich stránkach MSDN ponúka niekoľko aplikačných blokov (AB) - tie by sa dali v skratke opísať ako nejaké stavebné jednotky aplikácie. T.j. pomáhajú Vám pokryť istú často sa opakujúcu oblasť riešenia v programovaných aplikáciách. V tomto príspevku mienim jemne predstaviť (teda nie detailne popísať všetky možnosti, to by som len kopíroval článok na MSDN) aplikačný blok výnimok (ABV), ktorý sa mi osvedčil a navyše sa celkom jednoducho implementoval aj do mnou posledne vyvíjanej aplikácie.

Tento AB zjednodušuje publikáciu výnimok. Keď Vám v aplikácii nastane výnimka, a neviete ju rovno ošetriť, je dobré aspoň ju publikovať, teda niekam uchovať informáciu o tom, ak výnimka nastala, kedy, kde, kto bol práve prihlásený, atď... No k zjednošeniu tohto procesu by Vám práve spomínaný AB mohol dopomôcť. Navyše dávam do pozornosti článok Exception Management Architecture Guide ktorý si za cieľ kladie byť Vašim sprievodcom pri dizajne a implementácii výnimok a ich spracovania.

Začnem asi dvomi dôležitými linkami, ktoré vedú na MSDN:

Veľmi jemne teraz nastienim, ako sa tento AB funguje, detailnejší popis nájdete vo vyššie spomenutom článku.

Úplne na začiatku si musíte rozmyslieť, kam chcete výnimku publikovať - publikáciu má na starosti Publisher. Microsoft priamo dodáva Publisher, ktorý vie výnimku zapísať do Event Log-u. Vďaka tomu, že publisherom sa môže stať ktorákoľvek trieda, ktorá implementuje rozhranie IExceptionPublisher obsahujúce iba jednu metódu (aké prekvapenie asi pre Vás bude, že táto sa volá Publish), je veľmi jednoduché naprogramovať si vlastný publisher.

Keď máte vybraný, alebo naprogramovaný publisher, musíte si nakonfigurovať aplikáciu v jej konfiguračnom súbore (web.config alebo app.config). Táto konfigurácia pozostáva z dvoch krokov:

  • nadefinujete, že ktorákoľvek sekcia exceptionManagement má byť spracovávaná ABV
  • nadefinujete toľko sekcií exceptionManagement, koľko publisherov chcete použiť, každý publisher pravdepodobne bude od vás očakávať iné nastavenia

Takže keď z kódu požiadate o publikovanie výnimky, môže byť jednak jedna výnimka spracovaná viacerými publishermi, druhak môžu rôzny publisheri spracovávať rôzne výnimky. Niektoré výnimky môžno chcete publikovať do Event Log-u, iné zase napríklad chcete posielať mailom. Fantázii (účelnosti) sa hranice nekladú. Navyše, ak by došlo k výnimke práve v publisherovi (napríklad z dôvodu jeho chybnej konfigurácie), táto výnimka bude automaticky zaznamenaná do Event Logu.

Tým, že každý publisher pracuje s výnimkou iným spôsobom, je pravdepodobné, že aj samotný publisher si bude musieť čítať nejaké nastavenia z konfiguračného súboru. Napríklad je pravdepodobné, že budete chcieť udržiavať nastavenie SMTP serveru, v prípade publishera publikujúceho mailom, v konfiguračnom súbore a nie natvrdo v zdrojovom kóde triedy (publishera).

Keď už máte ABV a jeho publishery nakonfigurované, nezostáva už nič iné, iba z kódu žiadať manažéra výnimok o publikovanie výnimok v momente ich nastatia. Takže dajme tomu, že máte nejaký kritický kód, ktorý uzatvoríte do try/catch bloku a v catch bloku chcete len a iba publikovať výnimku. Kód bude jednoduchý a stále rovnaký, nezávislý na tom, akých publisherov používate, pretože ako som spomínal, použitie publisherov konfigurujete na úrovni konfiguračného súboru:

try
{
  // kriticky kod
}
catch (Exception ex)
{
  ExceptionManager.Publish(ex);
}

A to je všetko. Manažér výnimok sa postará o zavolanie metód Publish všetkých publisherov, ktorých ste pre publikovanie výnimky nadefinovali v konfiguračnom súbore.

Ešte uvediem ukážku, ako vyzerá konfigurácia v konfiguračnom súbore v prípade publishera, ktorého som si pripravil ja. Tohto som si nazval ExceptionPublisherMail a jeho úlohou je posielať emailovú správu (jeho zdrojový kód je uvedený nižšie). SMTP server, adresy odosielateľa a príjemcov, apod. sú zisťované z konfiguračného súboru. Takže najskôr prvý spomínaný krok konfigurácie:

<configSections>
  <section
    name="exceptionManagement"
    type="Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionManagerSectionHandler,
Microsoft.ApplicationBlocks.ExceptionManagement" /> </configSections>

(Riadok type a hneď za ním nasledujúci tvoria v skutočnosti jeden riadok, zalomil som to úmyselne, aby nebol text moc dlhý.) A druhý spomínaný krok, konfigurácia samotného publishera:

<exceptionManagement>
  <publisher
    mode="on"
    assembly="Microsoft.ApplicationBlocks.ExceptionManagement"
    type="Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionPublisherMail"
    emailSmtpServer="firemnysmtpserver"
    emailFrom="odosielatel@firma.sk"
    emailTo="prijemca@firma.sk"
    emailSubject="[Exception] NazovApp" />
</exceptionManagement>

A to je všetko. Jednoduché, účinné a navyše ľahko rozšíriteľné o ďaľších publisherov podľa potrieb samotnej aplikácie.

Prikladám kód mnou naprogramovanej triedy - publishera, ktorý výnimku publikuje v podobe odoslania emailu. Keďže sa jedná o primitívnu metódu, nebudem ju do hĺbky rozoberať, ale namiesto toho ju uvádzam v celku a doplnil som ju komentármi:

// publisher, ktory bude info o vynimke mailovat
public class ExceptionPublisherMail : IExceptionPublisher
{
  // premenne potrebne pre odoslanie mailu, konfigurovat sa budu
  // v konfiguracnom subore aplikacie
  private string emailSmtpServer = string.Empty;
  private string emailFrom = string.Empty;
  private string emailTo = string.Empty;
  private string emailCc = string.Empty;
  private string emailBcc = string.Empty;
  private string emailSubject = string.Empty;
  // konstruktor, nepouziva sa
  public ExceptionPublisherMail() {}
  // metoda, ktora sa ako jedina musi implementovat a ktora
  // publikuje vynimku - posle mail
  // metoda ma vdaka parametrom pristup nie len k vynimke ale
  // aj k dodatocnym informaciam (meno pc kde k vynimke prislo,
  // login prihlaseneho uzivatela, ...) a samozrejme ku konfigu-
  // uracnym parametrom v konfiguracnom subore aplikacie
  //
  // ak v metode nastane vynimka, manazer vynimiek sa sam postara
  // o jej publikovanie v event logu a preto nie je potrebne a
  // zrejme ani vhodne uzatvarat posielanie mailu do try/catch
  // bloku
  public void Publish(Exception exception, 
    NameValueCollection AdditionalInfo, 
    NameValueCollection ConfigSettings)
  {
    // nacitanie konfiguracnych udajov
    if (ConfigSettings != null)
    {
      if (ConfigSettings["emailSmtpServer"] != null &&  
        ConfigSettings["emailSmtpServer"].Length > 0)
      {  
        emailSmtpServer = ConfigSettings["emailSmtpServer"];
      }
      if (ConfigSettings["emailFrom"] != null &&  
        ConfigSettings["emailFrom"].Length > 0)
      {  
        emailFrom = ConfigSettings["emailFrom"];
      }
      if (ConfigSettings["emailTo"] != null &&  
        ConfigSettings["emailTo"].Length > 0)
      {  
        emailTo = ConfigSettings["emailTo"];
      }
      if (ConfigSettings["emailCc"] != null &&  
        ConfigSettings["emailCc"].Length > 0)
      {  
        emailCc = ConfigSettings["emailCc"];
      }
      if (ConfigSettings["emailBcc"] != null &&  
        ConfigSettings["emailBcc"].Length > 0)
      {  
        emailBcc = ConfigSettings["emailBcc"];
      }
      if (ConfigSettings["emailSubject"] != null &&  
        ConfigSettings["emailSubject"].Length > 0)
      {  
        emailSubject = ConfigSettings["emailSubject"];
      }
    }
    // pripravime obsah mailovej spravy obsahujuci jednak
    // dodatocne informacie a jednak obsah samotnej vynimky
    StringBuilder strInfo = new StringBuilder();
    if (AdditionalInfo != null)
    {
      strInfo.AppendFormat("<H3>General Information</H3><PRE>{0}", 
        Environment.NewLine);
      foreach (string i in AdditionalInfo)
      {
        strInfo.AppendFormat("{0}: {1}{2}", i, 
        AdditionalInfo.Get(i), Environment.NewLine);
      }
      strInfo.Append("</PRE>");
    }
    strInfo.AppendFormat("<H3>Exception Information</H3><PRE>{0}", 
      Environment.NewLine);
    strInfo.AppendFormat(exception.ToString());
    strInfo.Append("</PRE>");
    // pripravime mail a posleme ho
    MailMessage mmInfo = new MailMessage();
    mmInfo.From = emailFrom;
    mmInfo.To = emailTo;
    mmInfo.Cc = emailCc;
    mmInfo.Bcc = emailBcc;
    mmInfo.Subject = emailSubject;
    mmInfo.Body = strInfo.ToString();
    mmInfo.BodyFormat = MailFormat.Html;
    SmtpMail.SmtpServer = emailSmtpServer;
    SmtpMail.Send(mmInfo);
  }
}

A to už je naozaj všetko, čo som mal na srdci. Mne architektúra tohto AB plne vyhovuje, ak sa zdá, že by mohla aj Vám, neváhajte a vyskúšajte. Súčasťou downloadu je samozrejme zdrojový kód a príklad použitia ABV. Nezabudnite si však prečítať popis v MSDN, pretože tento príspevok nerozoberá ABV do úplných detailov...

Mohlo by ťa tiež zaujímať

Páčil sa ti príspevok?

Zdieľaj príspevok alebo si ho odlož na neskôr

Sleduj ma

Ak nechceš premeškať príspevky ako je tento, sleduj ma na Twitteri, alebo ak máš RSS čítačku, môžeš sledovať môj RSS kanál.