这不是一个问题,但是我希望可以帮助一些人的事情......
前段时间,我编写了一个通用的透明异常处理模块,用于MOSS 2007(Sharepoint)解决方案。该解决方案有许多Web部件,Web部件经常会断开,导致它们所在的整个页面崩溃。这导致我们的测试人员无法忍受痛苦,因为他们无法轻易看到页面的哪个部分导致崩溃,也无法在Web部件修复之前继续测试。通常情况下,崩溃的Web部件甚至与测试人员无关,但仍然使他们无法完成工作。显然需要做点什么。
你可能会争辩说,最好的解决方案就是扣上并修复dang web部件..但是它们中有很多,并且负责混乱的编码器已经移动(听起来很熟悉?)所以我们有为部件使用通用的通用异常处理策略的想法。
我们希望在Web部件或Web控件等中崩溃,不要使整个页面崩溃,而是在开发过程中在网页中内联输出堆栈跟踪,并获得友好的消息(由webparts本身定义,或者标准消息)在运行时输出给用户,而不是整个页面。
当时我们不知道任何此类解决方案。 (我还是没有)。 我认为,最好的方法是将我所做的(包含文件)包含在ASP.Net框架中。 (如果你们ASP.Net的任何人都在读这个:随意窃取我的代码。它会更好地工作在类层次结构中越高 例如,它可以是System.Web.UI.WebControls.WebControl的一部分,有一些web.config设置你可以调整来激活它...它会在开发过程中帮助堆积..至少它会帮助我:))
所以,对于我们结束的解决方案: 我创建了一个BaseWebPart,其中所有其他Web部件(间歇性崩溃的部分)将继承。从继承之后,BaseWebPart将确保try / catch包含来自ASP.Net框架(Render,CreateChildControls等等)的所有调用,以便在其中一个中发生崩溃得到很好的处理。 然后,每个Web部件都可以覆盖一个名为HandleException的方法,以控制崩溃时发生的情况。默认行为(如果他们没有覆盖)设置为
在调试模式下渲染堆栈跟踪 要么 在处于发布模式时呈现标准错误消息
为了用异常处理包装每个框架调用, 我们有一个双层方法,其中
这个模块唯一的缺点是MOSS有几个“基础”Web部件,你可以继承自己的Web部件,所以这个BaseWebPart必须为每个部分重复一次。 我们还希望在Web控件上使用此功能, 所以我们必须基本上复制代码来制作BaseWebControl。 如果此错误处理模块包含在层次结构中较高的位置(例如WebControl或Control中),则一次就足以涵盖所有不同的情况。不幸的是,c#不允许使用mixins,或者我们可能一下子就可以完全应用异常处理。目前,发现4-5类重复的相同代码更适合40-50个具有重复异常处理逻辑的类。
“它有效吗?”你问?以及从这种设置中获得的好处包括
下次我在一个包含大量网页部件,网页控件或自定义控件的项目中时,我肯定会再次使用此设置。
等等,代码:
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
}
}