• Asp.net Web Applicatoin实现自定义HttpModule拦截异常处理


            Asp.net的NamePipe机制给我们提供了很多扩展性. 使用HttpModule我们可能实现的有:

    • 强制站点范围的Cookie策略
    • 集中化监控与日志
    • 编写设置与删除HTTP头
    • 控制response输出,如删除多余空白字符
    • Session管理
    • 认证与受权

    下面我们来看如何实现自定义异常处理:

       1:    public class ErrorModule:IHttpModule
       2:      {
       3:          #region IHttpModule Members
       4:   
       5:          /// <summary>
       6:          /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
       7:          /// </summary>
       8:          public void Dispose()
       9:          {
      10:              //do nothing 
      11:          }
      12:   
      13:          /// <summary>
      14:          /// Initializes a module and prepares it to handle requests.
      15:          /// </summary>
      16:          /// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param>
      17:          public void Init(HttpApplication context)
      18:          {
      19:              context.Error += new EventHandler(customcontext_Error);
      20:          }
      21:   
      22:          private void customcontext_Error(object sender, EventArgs e)
      23:          {
      24:              HttpContext ctx = HttpContext.Current;
      25:              HttpResponse response = ctx.Response;
      26:              HttpRequest request = ctx.Request;
      27:   
      28:              Exception exception = ctx.Server.GetLastError();
      29:   
      30:              var sboutput = new StringBuilder();
      31:              sboutput.Append("Querystring:<p/>");
      32:              //Get out the query string 
      33:              int count = request.QueryString.Count;
      34:              for (int i = 0; i < count; i++)
      35:              {
      36:                  sboutput.AppendFormat("<br/> {0}:-- {1} ", request.QueryString.Keys[i], request.QueryString[i]);
      37:              }
      38:              //Get out the form collection info
      39:              sboutput.Append("<p>-------------------------<p/>Form:<p/>");
      40:              count = request.Form.Count;
      41:              for (int i = 0; i < count; i++)
      42:              {
      43:                  sboutput.AppendFormat("<br/> {0}:-- {1}  -- <br/>", request.Form.Keys[i], request.Form[i]);
      44:              }
      45:              sboutput.Append("<p>-------------------------<p/>ErrorInfo:<p/>");
      46:              sboutput.AppendFormat(@"Your request could not processed. Please press the back button on your browser and try again.<br/>
      47:                                 If the problem persists, please contact technical support<p/>
      48:                                 Information below is for technical support:<p/>
      49:                                  <p/>URL:{0}<p/>Stacktrace:---<br/>{1}<p/>InnerException:<br/>{2}"
      50:           , ctx.Request.Url, exception.InnerException.StackTrace, exception.InnerException);
      51:   
      52:             response.Write(sboutput.ToString());
      53:   
      54:              // To let the page finish running we clear the error
      55:              ctx.Server.ClearError();
      56:          }
      57:   
      58:          #endregion
      59:   
      60:      }

    上面的代码实现了IHttpModule接口, 实现基于HttpApplication.Error事件, 接着我们自定义输出了一些信息,包括Form,QueryString. 最后把原来的Error信息清除了,这样你看到以前那个黄页了. 这个自定义的Module可以用于调试Web应用程序使用.

    Web.config中配置:

    <httpModules>
          <add name="ErrorLoggingModule" type="MyWeb.ErrorModule"/>
    </httpModules>

    实际开发中,我们可以做的事儿很多,对这些信息记日志,发邮件. 如下, 我们演示使用Enterprise Library 做异常处理并日志记录,部分代码如下:

       1:          /// <summary>
       2:          /// Handles the Error event of the EntLibLogging control.
       3:          /// </summary>
       4:          /// <param name="sender">The source of the event.</param>
       5:          /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
       6:          /// <remarks>author Petter Liu http://wintersun.cnblogs.com</remarks>
       7:          private void EntLibLogging_Error(object sender, EventArgs e)
       8:          {
       9:              var builder = new ConfigurationSourceBuilder();
      10:   
      11:              builder.ConfigureInstrumentation()
      12:                .ForApplicationInstance("MyApp")
      13:                .EnableLogging()
      14:               .EnablePerformanceCounters();
      15:   
      16:              //a single exception handling policy named MyPolicy for exceptions of type ArgumentNullException. 
      17:              //The handler for this exception policy will log the exception to the General category (defined in the Logging Application Block configuration) 
      18:              //as a warning with event ID 9000, wrap the ArgumentNullException with an InvalidOperationException, set the new exception message to MyMessage, and then re-throw the exception.
      19:              builder.ConfigureExceptionHandling()
      20:                  .GivenPolicyWithName("MyPolicy")
      21:                  .ForExceptionType<ArgumentNullException>()
      22:                  .LogToCategory("Exception")
      23:                    .WithSeverity(System.Diagnostics.TraceEventType.Warning)
      24:                    .UsingEventId(9000)
      25:                  .WrapWith<InvalidOperationException>()
      26:                    .UsingMessage("MyMessage")
      27:                   .ThenNotifyRethrow();
      28:   
      29:              //logging application 
      30:              builder.ConfigureLogging()
      31:                 .WithOptions
      32:                 .DoNotRevertImpersonation()
      33:                 .LogToCategoryNamed("Exception")
      34:                 .SendTo.FlatFile("Exception Logging File")
      35:                  .FormatWith(new FormatterBuilder()
      36:                  .TextFormatterNamed("Text Formatter")
      37:                 . UsingTemplate("Timestamp: {timestamp}{newline}Message: {message}{newline}Category: {category}{newline}"))
      38:                  .ToFile("d:\\logs\\ExceptionsLog.log")
      39:                 .SendTo.RollingFile("Rolling Log files")
      40:                 .RollAfterSize(1024)
      41:                 .ToFile("d:\\logs\\Rollinglog.log")
      42:                 .LogToCategoryNamed("General")
      43:                 .WithOptions.SetAsDefaultCategory()
      44:                 .SendTo.SharedListenerNamed("Exception Logging File");
      45:   
      46:              var configSource = new DictionaryConfigurationSource();
      47:              builder.UpdateConfigurationWithReplace(configSource);
      48:              EnterpriseLibraryContainer.Current  = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
      49:            
      50:              var ex = HttpContext.Current.Server.GetLastError();
      51:              var em = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();
      52:              em.HandleException(ex.InnerException, "MyPolicy");   
      53:          }

    注意上面的代码, 为了运行代码您需要引用以下程序集

    Enterprise Library Share Common Library
    Microsoft.Practices.ServiceLocation
    Logging Application Block
    Exception Handling Application Block
    Exception Handling Logging Provider

    这里我们使用Fluent API配置, 因此没有配置XML文件. 所以不需要Web.Config中配置任何信息. 代码中有注释. 为了测试我们使用一个PAGE故意Throw 一个ArgumentNullException. 通过Server.GetLastError()获取Exception, 这时由名为MyPolicy策略处理异常. 对于ArgumentNullException把它们记录日志到名为Exception分类中,这个日志文件位于d:\\logs\\
    ExceptionLog.log.实际开发你完全按照你的需要来自定义策略.

    然后这个日志文件中写出的内容是这样的:

    ----------------------------------------
    Timestamp: 2011-11-12 5:57:08
    Message: HandlingInstanceID: a99d005d-5f8d-4613-9522-2d60efb089aa
    An exception of type 'System.ArgumentNullException' occurred and was caught.
    ----------------------------------------------------------------------------
    11/12/2011 13:57:08
    Type : System.ArgumentNullException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    Message : Value cannot be null.
    Parameter name: Demo error
    Source : MyWeb
    Help link : 
    ParamName : Demo error
    Data : System.Collections.ListDictionaryInternal
    TargetSite : Void Page_Load(System.Object, System.EventArgs)
    Stack Trace :    at MyWeb.About.Page_Load(Object sender, EventArgs e) in H:\My Project\DotNet40\TDD2010\WebHost\MyWeb\About.aspx.cs:line 14
       at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
       at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
       at System.Web.UI.Control.OnLoad(EventArgs e)
       at System.Web.UI.Control.LoadRecursive()
       at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
    
    Additional Info:
    
    MachineName : USER
    TimeStamp : 2011-11-12 5:57:08
    FullName : Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
    AppDomainName : 3e5cb21e-3-129655510216406250
    ThreadIdentity : 
    WindowsIdentity : USER\Petter
    
    Category: Exception

    由于我们日志模块我们配置还需要写Rollinglog.log文件,内容如下:

    ----------------------------------------
    Exception Warning: 9000 : Timestamp: 2011-11-12 5:57:08
    Message: HandlingInstanceID: a99d005d-5f8d-4613-9522-2d60efb089aa
    An exception of type 'System.ArgumentNullException' occurred and was caught.
    ----------------------------------------------------------------------------
    11/12/2011 13:57:08
    Type : System.ArgumentNullException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    Message : Value cannot be null.
    Parameter name: Demo error
    Source : MyWeb
    Help link : 
    ParamName : Demo error
    Data : System.Collections.ListDictionaryInternal
    TargetSite : Void Page_Load(System.Object, System.EventArgs)
    Stack Trace :    at MyWeb.About.Page_Load(Object sender, EventArgs e) in H:\My Project\DotNet40\TDD2010\WebHost\MyWeb\About.aspx.cs:line 14
       at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
       at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
       at System.Web.UI.Control.OnLoad(EventArgs e)
       at System.Web.UI.Control.LoadRecursive()
       at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
    
    Additional Info:
    
    MachineName : USER
    TimeStamp : 2011-11-12 5:57:08
    FullName : Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
    AppDomainName : 3e5cb21e-3-129655510216406250
    ThreadIdentity : 
    WindowsIdentity : USER\Petter
    
    Category: Exception
    Priority: 0
    EventId: 9000
    Severity: Warning
    Title:Enterprise Library Exception Handling
    Machine: USER
    App Domain: 3e5cb21e-3-129655510216406250
    ProcessId: 2444
    Process Name: C:\Program Files\Common Files\Microsoft Shared\DevServer\10.0\WebDev.WebServer40.exe
    Thread Name: 
    Win32 ThreadId:2748
    Extended Properties: 
    ----------------------------------------
    你可以看到上面的EventId=9000与我们之前在CODE中配置是相同的. 
    在开源社区有一个组件ELMAH(Error Logging Modules and Handlers for ASP.NET),已实现Error处理发邮件,写DB,发送到SNS等功能. 我们随意来看下它的代码:
    它就是基于IHttpModule的扩展,下面代码来ELMAH:
       1:      /// <summary>
       2:      /// Provides an abstract base class for <see cref="IHttpModule"/> that
       3:      /// supports discovery from within partial trust environments.
       4:      /// </summary>
       5:      public abstract class HttpModuleBase : IHttpModule
       6:      {
       7:          void IHttpModule.Init(HttpApplication context)
       8:          {
       9:              if (context == null)
      10:                  throw new ArgumentNullException("context");
      11:   
      12:              if (SupportDiscoverability)
      13:                  HttpModuleRegistry.RegisterInPartialTrust(context, this);
      14:   
      15:              OnInit(context);
      16:          }
      17:   
      18:          void IHttpModule.Dispose()
      19:          {
      20:              OnDispose();
      21:          }
      22:   
      23:          /// <summary>
      24:          /// Determines whether the module will be registered for discovery
      25:          /// in partial trust environments or not.
      26:          /// </summary>
      27:          protected virtual bool SupportDiscoverability
      28:          {
      29:              get { return false; }
      30:          }
      31:   
      32:          /// <summary>
      33:          /// Initializes the module and prepares it to handle requests.
      34:          /// </summary>
      35:          protected virtual void OnInit(HttpApplication application) {}
      36:   
      37:          /// <summary>
      38:          /// Disposes of the resources (other than memory) used by the module.
      39:          /// </summary>
      40:          protected virtual void OnDispose() {}
      41:      }
    这是ErrorLogModule实现之前HttpModuleBase:
       1:  public class ErrorLogModule : HttpModuleBase, IExceptionFiltering
       2:      {
       3:          public event ExceptionFilterEventHandler Filtering;
       4:          public event ErrorLoggedEventHandler Logged;
       5:   
       6:          /// <summary>
       7:          /// Initializes the module and prepares it to handle requests.
       8:          /// </summary>
       9:          
      10:          protected override void OnInit(HttpApplication application)
      11:          {
      12:              if (application == null)
      13:                  throw new ArgumentNullException("application");
      14:              
      15:              application.Error += new EventHandler(OnError);
      16:              ErrorSignal.Get(application).Raised += new ErrorSignalEventHandler(OnErrorSignaled);
      17:          }
      18:   
      19:          /// <summary>
      20:          /// Gets the <see cref="ErrorLog"/> instance to which the module
      21:          /// will log exceptions.
      22:          /// </summary>
      23:          protected virtual ErrorLog GetErrorLog(HttpContext context)
      24:          {
      25:              return ErrorLog.GetDefault(context);
      26:          }
      27:   
      28:          /// <summary>
      29:          /// The handler called when an unhandled exception bubbles up to 
      30:          /// the module.
      31:          /// </summary>
      32:          protected virtual void OnError(object sender, EventArgs args)
      33:          {
      34:              HttpApplication application = (HttpApplication) sender;
      35:              LogException(application.Server.GetLastError(), application.Context);
      36:          }
      37:   
      38:          /// <summary>
      39:          /// The handler called when an exception is explicitly signaled.
      40:          /// </summary>
      41:          protected virtual void OnErrorSignaled(object sender, ErrorSignalEventArgs args)
      42:          {
      43:              LogException(args.Exception, args.Context);
      44:          }
      45:   
      46:          /// <summary>
      47:          /// Logs an exception and its context to the error log.
      48:          /// </summary>
      49:          protected virtual void LogException(Exception e, HttpContext context)
      50:          {
      51:              if (e == null)
      52:                  throw new ArgumentNullException("e");
      53:   
      54:              //
      55:              // Fire an event to check if listeners want to filter out
      56:              // logging of the uncaught exception.
      57:              //
      58:   
      59:              ExceptionFilterEventArgs args = new ExceptionFilterEventArgs(e, context);
      60:              OnFiltering(args);
      61:              
      62:              if (args.Dismissed)
      63:                  return;
      64:              
      65:              //
      66:              // Log away...
      67:              //
      68:   
      69:              ErrorLogEntry entry = null;
      70:   
      71:              try
      72:              {
      73:                  Error error = new Error(e, context);
      74:                  ErrorLog log = GetErrorLog(context);
      75:                  string id = log.Log(error);
      76:                  entry = new ErrorLogEntry(log, id, error);
      77:              }
      78:              catch (Exception localException)
      79:              {
      80:                  //
      81:                  // IMPORTANT! We swallow any exception raised during the 
      82:                  // logging and send them out to the trace . The idea 
      83:                  // here is that logging of exceptions by itself should not 
      84:                  // be  critical to the overall operation of the application.
      85:                  // The bad thing is that we catch ANY kind of exception, 
      86:                  // even system ones and potentially let them slip by.
      87:                  //
      88:   
      89:                  Trace.WriteLine(localException);
      90:              }
      91:   
      92:              if (entry != null)
      93:                  OnLogged(new ErrorLoggedEventArgs(entry));
      94:          }
      95:   
      96:          /// <summary>
      97:          /// Raises the <see cref="Logged"/> event.
      98:          /// </summary>
      99:          protected virtual void OnLogged(ErrorLoggedEventArgs args)
     100:          {
     101:              ErrorLoggedEventHandler handler = Logged;
     102:   
     103:              if (handler != null)
     104:                  handler(this, args);
     105:          }
     106:   
     107:          /// <summary>
     108:          /// Raises the <see cref="Filtering"/> event.
     109:          /// </summary>
     110:          protected virtual void OnFiltering(ExceptionFilterEventArgs args)
     111:          {
     112:              ExceptionFilterEventHandler handler = Filtering;
     113:              
     114:              if (handler != null)
     115:                  handler(this, args);
     116:          }
     117:   
     118:          /// <summary>
     119:          /// Determines whether the module will be registered for discovery
     120:          /// in partial trust environments or not.
     121:          /// </summary>
     122:          protected override bool SupportDiscoverability
     123:          {
     124:              get { return true; }
     125:          }
     126:      }
    更多的功能等待您去挖掘,我们在实际开发中按需选择.希望这篇POST对您开发有帮助.

    你可能感兴趣的文章:
    在VS2010中配制Elmah邮件发送到Gmail
    HttpModule应用:
    使用HttpModules实现Asp.net离线应用程序
    Asp.net使用HttpModule压缩并删除空白Html请求

    Asp.net移除Server, X-Powered-By, 和X-AspNet-Version头
    Enterprise Library:

    使用Fluent配置API驱动Enterprise Library 5.0
    EneterpriseLibrary5的Fluent配制API


    作者:Petter Liu
    出处:http://www.cnblogs.com/wintersun/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    该文章也同时发布在我的独立博客中-Petter Liu Blog

  • 相关阅读:
    jni基础
    Rank Scores
    LeetCode:Longest Substring Without Repeating Characters
    LeetCode: Two Sum
    vim配置
    设计模式眨一眨
    分布式时序数据库InfluxDB
    地图坐标转换
    根据两点间的经纬度计算距离
    解密经纬度数据(火星坐标)
  • 原文地址:https://www.cnblogs.com/wintersun/p/2246513.html
Copyright © 2020-2023  润新知