asp.net sharepoint exception-handling moss

Manejo transparente de excepciones genéricas para asp.net/MOSS2007(con código)



sharepoint exception-handling (0)

No es exactamente una pregunta así, pero algo que podría ayudar a algunas personas, espero ...

Hace algún tiempo, escribí un módulo general de manejo de excepciones transparente para usar en una solución MOSS 2007 (Sharepoint). La solución tenía muchas partes web, partes web que a menudo se romperían, causando que la página entera en la que se encontraban se bloqueara. Esto estaba causando que nuestros probadores no se desanimaran, ya que no podían ver fácilmente qué parte de la página era responsable del colapso, ni podían continuar su prueba hasta que se reparara la parte web. A menudo, la parte web que se colgaba ni siquiera era relevante para los probadores, pero aún les impedía hacer su trabajo. Claramente, algo tenía que hacerse.

Se podría argumentar que la mejor solución sería abrocharse el cinturón de seguridad y simplemente arreglar las piezas de la red Dang ... pero había muchas, y los codificadores responsables del desorden se habían movido (¿te suena familiar?), Así que tuvimos la idea de utilice una estrategia general de manejo de excepciones para todas las partes.

Queríamos un bloqueo en un elemento web o control web, etc., para no bloquear toda la página, sino generar el stacktrace en línea en la página web durante el desarrollo y tener un mensaje amigable (definido por los propios webparts, o un estándar). mensaje) enviado al usuario en tiempo de ejecución, en lugar de mostrar toda la página.

En ese momento no conocíamos ninguna de esas soluciones. (Todavía no lo hago). Lo mejor, creo, sería si algo como lo que hice (el archivo está incluido) fue incluido en el marco ASP.Net. (Si alguno de ustedes, muchachos de ASP.Net, están leyendo esto: siéntete libre de robar mi código. Funcionaría mejor cuanto más alto esté en la jerarquía de clases, podría ser, por ejemplo, parte de System.Web.UI.WebControls.WebControl, con algún ajuste de web.config podrías ajustarlo para activarlo ... ayudaría a montones durante el desarrollo ... al menos me ayudaría :))

así que, con respecto a la solución con la que terminamos: hice un BaseWebPart del que heredarían todos los otros elementos web (los que fallaban intermitentemente). Cuando se hereda de, BaseWebPart se aseguraría de que un try / catch rodeara todas las llamadas provenientes del framework ASP.Net (Render, CreateChildControls ... etc.) para que un accidente que ocurriera en una de ellas se manejara muy bien. Cada parte web podría anular un método llamado HandleException para controlar lo que sucedía si se bloqueaba. el comportamiento predeterminado (si no anularon) se configuró para ser

renderizar la pila cuando está en modo de depuración o mostrar un mensaje de error estándar cuando está en modo de liberación

Para ajustar cada llamada de framework con manejo de excepciones, teníamos un enfoque de dos niveles en el cual

  1. el primer nivel (ExceptionHandlingWebPartBase) anula y sella métodos,
  2. luego aplica try / catch a un nuevo conjunto de métodos, parámetros de método de reenvío
  3. estos nuevos métodos se anulan en el segundo nivel (BaseWebPart)
  4. donde están sellados y se realiza una llamada a nuevos métodos virtuales que reciben el mismo nombre que los métodos de marco.
  5. Estos métodos (ahora con un bloque catch alrededor de ellos) se anulan según sea necesario en un elemento web normal que hereda de BaseWebPart. El manejo de excepciones es, por lo tanto, transparente para el heredero.

El único inconveniente de este módulo es que MOSS tiene varias partes web "básicas" de las que heredarías para crear tus propios elementos web, por lo que este BaseWebPart tuvo que duplicarse una vez para cada uno de estos. También queríamos esta funcionalidad en los controles web, así que básicamente teníamos que duplicar el código para hacer también un BaseWebControl. Si este módulo de manejo de errores se incluyó más arriba en la jerarquía, por ejemplo en WebControl o Control, una vez sería suficiente para cubrir todos los casos diferentes. Desafortunadamente c # no permite mixins, o probablemente podríamos salirse con la suya aplicando el manejo de excepciones de una sola vez. Tal como están las cosas, se descubrió que 4-5 clases de código duplicado e idéntico eran preferibles a 40-50 clases con lógica de manejo de excepciones duplicadas.

"¿funcionó?" ¿usted pregunta? así los beneficios derivados de esta configuración incluidos

  1. no hay necesidad de entornos de prueba de revisión de emergencia durante la prueba
  2. registro garantizado de excepciones en producción
  3. una clasificación de error generalmente más sobria por parte de los evaluadores (antes de que dijeran "todo está caído, esta página no funciona, esto es inaceptable, error de nivel 1")
  4. algunas excepciones en los elementos web se colapsaron en la producción, pero en lugar de hacer que se detuviera toda la página, se mostró un mensaje amigable, que nos permitió dedicar una gran cantidad de tiempo a solucionar el problema (la próxima versión en lugar de la revisión)

Definitivamente estoy usando esta configuración nuevamente la próxima vez que estoy en un proyecto con muchos elementos web, controles web o controles personalizados.

y así, en el código:

using System; using System.IO; using System.Text; using System.Web.UI; using System.Web.UI.WebControls.WebParts; ///*'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' /// This is the work of Andreas Knudsen (andreas.knudsen [ at ] gmail.com) /// Anyone may use this work freely as it stands, or change it to suit their needs /// on one condition: All use is on your own risk. It works for me, but I will not be /// liable for any losses incurred by the use of this work. /// /// If you would hold me responsible, you are not to use this work. /// ************************************************************************************ /// /// In order to be truly useful, customizations are needed on lines 120 and 130 /// (search for CUSTOMIZE HERE! /// /// ************************************************************************************ namespace Util { /// <summary> /// Base class for web part development. /// All web parts should inherit from this class. /// Exceptions thrown from web parts inheriting from this base /// will not crash the Page the web part is on, but rather do one of two things: /// /// 1)If compiled in debug mode: Render the stacktrace of the exception inline in the web page /// 2)If compiled in release mode: Render a friendly error message inline in the web page. /// /// This behaviour can be overridden by inheritors by overriding the method HandleException /// /// HOW THIS WORKS: /// ------- /// In order to wrap each framework call with exception handling, /// we have a two-tiered approach in which /// 1) the first tier (ExceptionHandlingWebPartBase) overrides and seals methods, /// 2) then applies try/catch to a new set of methods, forwarding method parameters /// 3) these new methods are overridden in the second tier (BaseWebPart) /// 4) where they are sealed and a call is made to new virtual methods that are named the /// same as the framework methods. /// 5) These methods (now with a catch-block around them) are then overridden as needed in a /// regular web part that inherits from BaseWebPart. The exception handling is thus /// transparent to the inheritor. /// </summary> public abstract class BaseWebPart : ExceptionHandlingWebPartBase { #region temp methods for method piping (overrides and seals methods from ExceptionHandlingWebPartBase) /* * These methods re part of the plumbing necessary to give inheritors * the expected interface. */ public override sealed void RenderWebPart(HtmlTextWriter writer) { Render(writer); } public override sealed void CreateWebPartChildControls() { CreateChildControls(); } public override sealed void InitWebPart(EventArgs e) { OnInit(e); } public sealed override void PreRenderWebPart(EventArgs e) { OnPreRender(e); } public sealed override void LoadWebPart(EventArgs e) { OnLoad(e); } #endregion #region Methods in which exceptions are now handled. protected new virtual void Render(HtmlTextWriter writer) { base.RenderWebPart(writer); } protected new virtual void CreateChildControls() { base.CreateWebPartChildControls(); } protected new virtual void OnInit(EventArgs e) { base.InitWebPart(e); } protected new virtual void OnLoad(EventArgs e) { base.LoadWebPart(e); } protected new virtual void OnPreRender(EventArgs e) { base.PreRenderWebPart(e); } #endregion } public abstract class ExceptionHandlingWebPartBase : WebPart { #region Exception handling section private StringBuilder _errorOutput; private bool _abortProcessing; public virtual bool AbortProcessing { get { return _abortProcessing; } set { _abortProcessing = value; } } public virtual void HandleException(Exception e, HtmlTextWriter writer) { #if !DEBUG // CUSTOMIZE HERE! writer.Write("TODO: Insert helpful error message here"); #else writer.Write(e.Message + "<br/>" + e.StackTrace); #endif } public void ExceptionHappened(Exception ex) { AbortProcessing = true; //CUSTOMIZE HERE! //TODO: use own logging framework here: //Logger.Log(Severity.Error, ex.Message + " " + ex.StackTrace); HandleException(ex, new HtmlTextWriter(new StringWriter(_errorOutput))); } #endregion #region Override framework methods for method piping protected override sealed void CreateChildControls() { if (!AbortProcessing) { try { CreateWebPartChildControls(); } catch (Exception e) { ExceptionHappened(e); } } } protected override sealed void OnInit(EventArgs e) { AbortProcessing = false; _errorOutput = new StringBuilder(); try { InitWebPart(e); } catch (Exception ex) { ExceptionHappened(ex); } } protected override sealed void Render(HtmlTextWriter writer) { StringBuilder tempOutput = new StringBuilder(); if (!AbortProcessing) { HtmlTextWriter tempWriter = new HtmlTextWriter(new StringWriter(tempOutput)); try { RenderWebPart(tempWriter); } catch (Exception ex) { ExceptionHappened(ex); } } if (AbortProcessing) { writer.Write(_errorOutput.ToString()); } else { writer.Write(tempOutput.ToString()); } } protected override sealed void OnLoad(EventArgs e) { if (!AbortProcessing) { try { LoadWebPart(e); } catch (Exception ex) { ExceptionHappened(ex); } } } protected override sealed void OnPreRender(EventArgs e) { if (!AbortProcessing) { try { PreRenderWebPart(e); } catch (Exception ex) { ExceptionHappened(ex); } } } #endregion #region Temp methods for method piping (will be overridden and sealed in subclass) public virtual void RenderWebPart(HtmlTextWriter writer) { EnsureChildControls(); base.Render(writer); } public virtual void CreateWebPartChildControls() { base.CreateChildControls(); } public virtual void InitWebPart(EventArgs e) { base.OnInit(e); } public virtual void LoadWebPart(EventArgs e) { base.OnLoad(e); } public virtual void PreRenderWebPart(EventArgs e) { base.OnPreRender(e); } #endregion } }