Prinderea excepțiilor nefolosite în ASC.NET UserControls

Încărc dinamic controalele de utilizator adăugându-le în colecția de controale a formularului Web.

Aș dori să ascund comenzile de utilizator dacă acestea produc o excepție nefolosită în timpul redării.

Așadar, am încercat să mă gândesc la evenimentul de eroare al fiecărui UserControl, dar se pare că acest eveniment nu se declanșează niciodată pentru UserControls, așa cum se întâmplă pentru clasa Page.

S-au făcut unele lucruri în jur și nu pare promițătoare. Orice idei aici?

0
fr hi bn

7 răspunsuri

Global.asax și Application_Error?

http://www.15seconds.com/issue/030102.htm

Sau evenimentul Page_Error numai pe o pagină individuală:

http://support.microsoft.com/kb/306355

void Page_Load(object sender, System.EventArgs e)
{
    throw(new ArgumentNullException());
}

public void Page_Error(object sender,EventArgs e)
{
    Exception objErr = Server.GetLastError().GetBaseException();
    string err =    "Error Caught in Page_Error event

" + "
Error in: " + Request.Url.ToString() + "
Error Message: " + objErr.Message.ToString()+ "
Stack Trace:
" + objErr.StackTrace.ToString(); Response.Write(err.ToString()); Server.ClearError(); }

De asemenea, Karl Seguin (Hi Karl!) A postat pe HttpHandler în schimb:

http://codebetter.com/blogs/karlseguin/archive/ 2006/06/12/146356.aspx

(Nu sunteți sigur ce permisiune de a reproduce, dar dacă doriți să scrieți un răspuns, ați primit Upvote?)

0
adăugat

Cum de a adăuga o nouă subclasă de UserControl că eroare-manipulează metodele sale de redare și de încărcare (astfel încât acestea să se ascundă după cum doriți) și apoi moștenirea de la aceasta pentru controalele de utilizator?

0
adăugat

În funcție de locul în care se întâmplă erorile, puteți face ceva de genul ...

public abstract class SilentErrorControl : UserControl
{
    protected override void Render( HtmlTextWriter writer )
    {
        //call the base's render method, but with a try catch
        try { base.Render( writer ); }
        catch ( Exception ex ) { /*do nothing*/ }
    }
}

Apoi moșteniți SilentErrorControl în loc de UserControl.

0
adăugat

Aceasta este o problemă interesantă .. Încă sunt destul de proaspete când vine vorba de controale personalizate etc, dar aici sunt gândurile mele (nu ezitați să comentați/corectați oameni!) .. (Mă gândesc/scriu cu voce tare aici!)

  • Dacă apare o eroare în timpul redării, în unele cazuri, nu ar fi prea târziu? (deoarece unele dintre comenzile HTML pot fi deja trimise la Writer și la ieșire).
  • Prin urmare, nu ar fi mai bine să înfășurați metoda Render de control al utilizatorului, dar mai degrabă decât să-i transmiteți referința la HtmlTextWriter "Live", să treci pe cont propriu, să prindeți orice Excepții ridicate în acest "bule" totul merge bine, apoi treci HTML-ul tău rezultant în HtmlTextWriter?
  • Această logică ar putea fi probabil introdusă într-o clasă generică de împachetare pe care ați folosi-o pentru a încărca/reda dinamic comenzile la timpul de execuție.
  • Dacă apar erori, aveți toate informațiile de care aveți nevoie la dispoziție! (adică referințe de control etc.).

Doar gândurile mele, flacără departe! : D;)

0
adăugat

mmilic, urmând de la răspunsul dvs. la idee prealabilă ..

Nu este necesară logica suplimentară! Acesta este motivul, nu faceți nimic pentru clasele în cauză, pur și simplu înfășurați-le în unele instantiation bubble-wrap! :)

OK, am vrut să fac doar un punct de glont, dar am vrut să văd această lucrare pentru mine, așa că am dat peste un cod foarte brutal, dar conceptul este acolo și pare să funcționeze.

APOLOGIILE PENTRU POSTUL LUNG

The SafeLoader

Acest lucru va fi, în principiu, "balonul" pe care l-am menționat. Acesta va primi controlul HTML, prinsând orice eroare care apar în timpul procesului de redare.

public class SafeLoader
{
    public static string LoadControl(Control ctl)
    {
       //In terms of what we could do here, its down
       //to you, I will just return some basic HTML saying
       //I screwed up.
        try
        {
           //Get the Controls HTML (which may throw)
           //And store it in our own writer away from the
           //actual Live page.
            StringWriter writer = new StringWriter();
            HtmlTextWriter htmlWriter = new HtmlTextWriter(writer);
            ctl.RenderControl(htmlWriter);

            return writer.GetStringBuilder().ToString();
        }
        catch (Exception)
        {
            string ctlType = ctl.GetType().Name;
            return "" + 
                "Rob + Controls = FAIL (" + 
                ctlType + " rendering failed) Sad face :(";
        }
    }
}

Și unele controale ..

Ok, tocmai am batjocorit două controale aici, una va arunca cealaltă va face junk. Arătați aici, eu nu dau nimic. Acestea vor fi înlocuite cu comenzile dvs. personalizate ..

BadControl

public class BadControl : WebControl
{
    protected override void Render(HtmlTextWriter writer)
    {
        throw new ApplicationException("Rob can't program controls");
    }
}

GoodControl

public class GoodControl : WebControl
{
    protected override void Render(HtmlTextWriter writer)
    {
        writer.Write("Holy crap this control works");
    }
}

Pagina

OK, asa ca lasa sa te uiti la pagina "test". Aici instalez doar controalele, apuca html-ul si iesi-l, voi urma cu gandurile in sprijinul designerului etc.

Codul paginii-din spate

    protected void Page_Load(object sender, EventArgs e)
    {
       //Create some controls (BadControl will throw)
        string goodHtml = SafeLoader.LoadControl(new BadControl());
        Response.Write(goodHtml);

        string badHtml = SafeLoader.LoadControl(new GoodControl());
        Response.Write(badHtml);
    }

Gânduri

OK, stiu la ce te gandesti ", aceste controale sunt instantiate programatic, ce inseamna sprijinul designerului? Mi-am petrecut orele de frecare pentru a obtine aceste controale placute designerului, acum imi pui mojo-ul".

OK, so I havent really tested this yet (probably will do in a min!) but the idea here is to override the CreateChildControls method for Pagina, and take the instance of each control added on the form and run it through The SafeLoader. If the code passes, you can add it to the Controls collection as normal, if not, then you can create erroneous literals or something, up to you my friend.

In cele din urma..

Din nou, îmi pare rău pentru postul lung, dar am vrut să obțin codul aici pentru a putea discuta acest lucru :) Sper ca acest lucru sa-mi demonstreze ideea :)

Actualizați

Testați prin îndesarea unui control asupra designerului și înlăturând metoda CreateChildControls cu acest lucru, funcționează bine, poate avea nevoie de ceva curat pentru a face lucrurile mai bine, dar vă voi lăsa asta;)

protected override void CreateChildControls()
{
   //Pass each control through the Loader to check
   //its not lame
    foreach (Control ctl in Controls)
    {
        string s = SafeLoader.LoadControl(ctl);
       //If its bad, smack it downnnn!
        if (s == string.Empty)
        {
            ctl.Visible = false;//Prevent Rendering
            string ctlType = ctl.GetType().Name;
            Response.Write("Problem Occurred Rendering " + 
                ctlType + " '" + ctl.ID + "'.");
        }
    }
}

Bucurați-vă!

0
adăugat

Nu sunt sigur că înțeleg răspunsul dvs. .. Cum vă încărcați controalele dvs. și adăugarea acestora la colecția dvs. de controale?

Acesta a fost întregul punct al bitului adăugat în secțiunea "Actualizare". Aveți flexibilitatea de a utiliza SafeLoader oriunde doriți.

Nu sunt sigur de ce credeți că nu aveți acces/control asupra Html-ului? Scopul programului SafeLoader este că nu îngrijește ce este html, încercați pur și simplu să "scoateți" controlul (în "bubble") și să determinați dacă acesta se încarcă OK în starea sa actuală.

Dacă se întâmplă (adică html-ul este returnat), atunci puteți face ceea ce vă place cu el, extrageți html-ul, adăugați controlul la colecția de controale, indiferent!

Dacă nu, din nou, puteți face ceea ce vă place, redați un mesaj de eroare, aruncați o excepție personalizată .. Alegerea este a ta!

Sper că acest lucru vă ajută să vă clarificați lucrurile, dacă nu, atunci vă rog să strigați :)

0
adăugat

Am folosit abordarea lui @ Keith, dar problema este că controlul este redat până când Excepția este aruncată, potențial rezultând în etichete HTML deschise. De asemenea, fac randarea informațiilor de excepție în modul Control în cazul în Debug.

  protected override void Render(System.Web.UI.HtmlTextWriter writer)
  {
     try
     {
       //Render the module to a local a temporary writer so that if an Exception occurs
       //the control is not halfway rendered - "it is all or nothing" proposition
        System.IO.StringWriter sw = new System.IO.StringWriter();
        System.Web.UI.HtmlTextWriter htw = new System.Web.UI.HtmlTextWriter(sw);
        base.Render(htw);

       //We made it!  Copy the Control Render over
        writer.Write(sw.GetStringBuilder().ToString());
     }
     catch (System.Exception ex)
     {
        string message = string.Format("Error Rendering Control {0}\n", ID);
        Log.Error(message, ex);
        if (Page.IsDebug)
           writer.Write(string.Format("{0}
Exception:
{1}\n{2}
", message, ex.Message, ex.StackTrace)); } }
0
adăugat