Pergunta

Eu estou carregar dinamicamente controlos de utilizador adicioná-los para a coleção de Controles de formulário da web.

Eu gostaria de ocultar os controles de usuário, se eles podem causar uma excepção não processada durante a renderização.

Então, eu tentei ligar para o evento de Erro de cada um UserControl, mas parece que este evento é acionado nunca pelo UserControls como faz para a classe de Página.

Fez algum googling ao redor e não me parece promissor.Todas as ideias aqui?

Foi útil?

Solução

mmilic, na sequência de sua resposta para minha idéia anterior..

Nenhuma lógica adicional necessário!Esse é o ponto, o não fazer nada para as classes em questão, basta envolvê-los em algumas instâncias bubble-wrap!:)

OK, eu estava indo apenas para ponto de bala, mas eu queria ver esse trabalho para mim mesmo, para que eu improvisada juntos alguns muito áspero código, mas o conceito existe e parece funcionar.

DESCULPAS PELO LONGO POST

O SafeLoader

Este vai ser basicamente a "bolha" que eu mencionei..Ele vai ter os controles HTML, pegando todos os erros que ocorrem durante o Processamento.

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 "<span style=\"color: red; font-weight:bold; font-size: smaller;\">" + 
                "Rob + Controls = FAIL (" + 
                ctlType + " rendering failed) Sad face :(</span>";
        }
    }
}

E Alguns Controles..

Ok eu só escarnecido, juntos, dois controles, um vai jogar o outro vai processar o lixo.O ponto aqui, eu não dou uma porcaria.Estes serão substituídos com seus controles personalizados..

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("<b>Holy crap this control works</b>");
    }
}

Página

OK, então vamos dar uma olhada na página "teste"..Aqui eu simplesmente instanciar os controles, pegue o seu html e saída, vou seguir com pensamentos sobre suporte de designer, etc..

Página Code-Behind

    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);
    }

Pensamentos

OK, eu sei que você está pensando, "esses controles são instanciados através de programação, o que sobre suporte de designer?Passei parvos horas, ficando estes controles bom para o designer, agora você está bagunçando com a minha mojo".

OK, então eu ainda não testado de verdade, ainda (provavelmente vai fazer em min!) mas a idéia aqui é substituir o método CreateChildControls para a página, e levar a instância de cada controle adicionado no formulário e executá-lo através da SafeLoader.Se o código passa, você pode adicioná-lo para a coleção de Controles como normal, se não, então você pode criar errada literais ou algo assim, até você, meu amigo.

Finalmente..

Novamente, desculpe pelo longo post, mas eu queria ter o código aqui para que possamos discutir isso :) Espero que isso ajuda a demonstrar a minha ideia :)

Atualização

Testado por chucking um controle sobre o designer e substituindo o método CreateChildControls com isso, funciona bem, pode precisar de algumas limpar a fazer as coisas melhor, mas vou deixar isso para você ;)

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("<b>Problem Occurred Rendering " + 
                ctlType + " '" + ctl.ID + "'.</b>");
        }
    }
}

Divirta-se!

Outras dicas

Esse é um problema interessante..Eu ainda sou muito novo quando se trata de controles personalizados etc, mas aqui estão os meus pensamentos (sinta-se livre para comentar/corrigir as pessoas!)..(Eu estou um bocado a pensar/escrever alto aqui!)

  • Se ocorrer um erro durante o processamento, em alguns casos, não seria tarde demais?(uma vez que alguns dos controles HTML já pode ter sido enviado para o Escritor e saída).
  • Portanto, não seria melhor para quebrar o controle de usuário do método de Renderização, mas, ao invés de passar a referência para o "ao Vivo" HtmlTextWriter, você passar a sua própria, interceptar Exceções levantadas neste pouca segurança "bolha", se tudo correr bem, você, em seguida, passar o HTML resultante para o real HtmlTextWriter?
  • Essa lógica pode provavelmente ser lançado para um genérico classe de wrapper que você gostaria de usar para carregar dinamicamente/render os controles em tempo de execução..
  • Se qualquer erro ocorrer, você tem todas as informações que você precisa ao seu dispor!(eu.e de controlo de referências, etc.).

Apenas meus pensamentos, chama de distância!:D ;)

Dependendo de onde os erros estão ocorrendo e que você pode fazer algo como...

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*/ }
    }
}

Então herdar SilentErrorControl em vez de UserControl.

Globais.asax e Application_Error?

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

Ou o Evento Page_Error em uma Página individual só:

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 =    "<b>Error Caught in Page_Error event</b><hr><br>" + 
                    "<br><b>Error in: </b>" + Request.Url.ToString() +
                    "<br><b>Error Message: </b>" + objErr.Message.ToString()+
                    "<br><b>Stack Trace:</b><br>" + 
                      objErr.StackTrace.ToString();
    Response.Write(err.ToString());
    Server.ClearError();
}

Além Disso, Karl Seguin (Oi Karl!) teve um Post sobre a utilização de HttpHandler em vez disso:

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

(Não tenho certeza de que a permissão para reproduzi-lo, mas se você quiser escrever uma resposta, você tem a minha vote positivamente ☺)

Como sobre a adição de uma nova sub-classe de UserControl que erro-lida com a render e métodos de carga (de modo que eles se escondem como quiser) e, em seguida, herança do que para controles de usuário?

Eu não tenho certeza se entender sua resposta..Como você está colocando seus controles e adicioná-las à sua coleção de controles?

Esse foi o ponto de todo o bit adicionado na "secção" Actualização..Você tem a flexibilidade para usar o SafeLoader onde quer que você queira.

Eu não tenho certeza de por que você sente que não tem acesso/controle sobre o Html?O objetivo do SafeLoader é que você não cuidados o que o html é, você simplesmente tenta e "saída" de controle (dentro da "bolha") e determinar se ele carrega OK em seu estado atual.

Se ele faz (i.e.o html é devolvido), então você pode fazer o que quiser com ele, a saída de html, adicionar o controle para a coleção de controles, o que quer!

Se não, então, novamente, você pode fazer o que você gosta, compor uma mensagem de erro, lançar uma exceção personalizada..A escolha é sua!

Espero que isso ajude a esclarecer as coisas para você, se não, então por favor gritar :)

Eu usei @Keith abordagem, mas o problema é que o controle é processado até a Exceção é lançada, potencialmente resultando em aberto tags HTML.Eu também estou de renderização as informações de exceção em que o Controle se no modo de Depuração.

  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}<br>Exception:<br><pre>{1}\n{2}</pre>", message, ex.Message, ex.StackTrace));
     }
  }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top